Skip Menu |

This queue is for tickets about the Net-WebSocket-Server CPAN distribution.

Report information
The Basics
Id: 127311
Status: resolved
Priority: 0/
Queue: Net-WebSocket-Server

People
Owner: Nobody in particular
Requestors: pliablepixels [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Handling new connections in child process
Date: Sun, 7 Oct 2018 07:06:13 -0400
To: bug-net-websocket-server [...] rt.cpan.org
From: Pliable Pixels <pliablepixels [...] gmail.com>
Good day, thank you for your excellent library. I have a usage question which may be a feature request as well, if an option doesn't exist today. I have am using your library to handle WSS connections from clients. I however need to be able to fork inside the server process so that the main loop continues while the fork handles communication with the child. This requires that the connection negotiation happens inside the child due to SSL state issues. I am initiating work on the on_connect handler of your library. Is there a pre-handler which I can intercept on an incoming TCP connection and then fork() and let the child handle the SSL upgrade? Thanks
On Sun Oct 07 07:06:42 2018, pliablepixels@gmail.com wrote: Show quoted text
> Good day, thank you for your excellent library. I have a usage question > which may be a feature request as well, if an option doesn't exist today. > > I have am using your library to handle WSS connections from clients. I > however need to be able to fork inside the server process so that the main > loop continues while the fork handles communication with the child. This > requires that the connection negotiation happens inside the child due to > SSL state issues. > > I am initiating work on the on_connect handler of your library. Is there a > pre-handler which I can intercept on an incoming TCP connection and then > fork() and let the child handle the SSL upgrade? > > Thanks
You probably shouldn't be forking on a per-connection basis to avoid blocking the main process. The problem you are encountering is probably because Net::WebSocket::Server implements its own select-based event loop that you either aren't using or that isn't suitable for your needs. You shouldn't try to circumvent its event loop at the per-client level, as it defeats the resource benefits of using an event loop for client multiplexing. You should assume that once you call start(), Net::WebSocket::Server has control of the process. However, you have a few options: Net::WebSocket::Server provides a few basic methods to support some simple main loop logic. If you specify tick_period, your on_tick handler will be called roughly that frequently; if you put your main loop logic there, possibly with some checks for each subtask to see whether enough time has passed, you might get what you need. If your main loop logic requires the detection of read/write availability on filehandles, you can also register event handlers via watch_readable and watch_writable. If you can meet those criteria, this is probably the option with the least effort for you. If you really want control of your main process, but also want to use Net::WebSocket::Server, another option would be to run the entire Net::WebSocket::Server (and all of its child connections) in a single subprocess. This will require additional complexity to pass data between your main process and the server process, but could get you up and running quickly if you already have a lot of code that depends on Net::WebSocket::Server otherwise. (Admittedly, you'd also have to solve the communication problem if you manage to put each child in a subprocess as you describe.) In general, it's best to avoid this approach, but it might work for you. I don't know the full scope of your project, but if what you need is a more complete (but more complex) event loop, I recommend using AnyEvent with AnyEvent::WebSocket::Server. This will require a rewrite of your project, but is flexible enough to support a very wide variety of projects. This option gives you many more ways to handle many more kinds of events, but still recommends that you to put your main loop in a timer-based callback like the Net::WebSocket::Server on_tick approach I outlined above. Ultimately, you should probably avoid forking entirely - the goal of any event loop is to let one process handle many things as work is required for them. If you can reframe the work from your main loop into work that can be done in response to an event (like a periodic timer or changes in a file or data on a socket), your program will be simpler and use fewer resources.
Subject: Re: [rt.cpan.org #127311] Handling new connections in child process
Date: Mon, 8 Oct 2018 09:00:36 -0400
To: bug-Net-WebSocket-Server [...] rt.cpan.org
From: Pliable Pixels <pliablepixels [...] gmail.com>
Thanks for your detailed reply. Admittedly, I did not provide sufficient project context. I am already using your "on_tick" handler today. The context is as follows: 1. The project involves using this module to broadcast "alarms" to listeners over websockets (Home security camera alarms). The server in turns connects to the home security solution to listen for alarms (not related to this module) 2. When a listener (such as a mobile app) connects to the server, I store the incoming connection to a master list (because in addition to the connection your module manages, I need to associate meta-data with it related to my project) 3. I use your "on_tick" handler every 5 seconds, to invoke a "checkAlarms()" procedure that interacts with the security server to see if a new alarm occurred and if so, runs some algorithms in a routine called processAlarms() and if necessary sends out a notification to the listener 4. Multiple alarms may occur for different cameras at the same time 5. processAlarms() basically is a time consuming process because it tuns some neural nets on the image for classification My goal therefore was this: on_tick => if (checkAlarms()) { // fork and run processAlarms($conn) } where processAlarms($conn) sends out the notification over websockets, which I can't do due to SSL states (parent instantiates the connection) Thank you. Show quoted text
> >
On Mon Oct 08 09:01:09 2018, pliablepixels@gmail.com wrote: Show quoted text
> Thanks for your detailed reply. Admittedly, I did not provide sufficient > project context. I am already using your "on_tick" handler today. > The context is as follows: > > 1. The project involves using this module to broadcast "alarms" to > listeners over websockets (Home security camera alarms). The server in > turns connects to the home security solution to listen for alarms (not > related to this module) > 2. When a listener (such as a mobile app) connects to the server, I store > the incoming connection to a master list (because in addition to the > connection your module manages, I need to associate meta-data with it > related to my project) > 3. I use your "on_tick" handler every 5 seconds, to invoke a > "checkAlarms()" procedure that interacts with the security server to see if > a new alarm occurred and if so, runs some algorithms in a routine called > processAlarms() and if necessary sends out a notification to the listener > 4. Multiple alarms may occur for different cameras at the same time > 5. processAlarms() basically is a time consuming process because it tuns > some neural nets on the image for classification > > My goal therefore was this: > > on_tick => if (checkAlarms()) { // fork and run processAlarms($conn) } > where processAlarms($conn) sends out the notification over websockets, > which I can't do due to SSL states (parent instantiates the connection) > > Thank you. >
I'm not understanding the SSL state issues; it's not my area of expertise, but it was my understanding that each SSL connection is isolated from the others. Because of your expensive neural network operations (and to isolate your SSL issue I don't fully understand), maybe it would be better to run *that* in a separate process. Event-driven systems (like the ones used by Net::WebSocket::Server or AnyEvent) are typically based on cooperative multitasking; if you have a long-running operation like a neural net, it will prevent all other events (like WebSocket activity) from being handled until it finishes. The event-driven solution for this is to break the work into small operations that can be handled individually, returning control to the event system between steps so other events can be handled. If you fork a subprocess (for the alert monitoring / neural network work) before you start the webserver and use pipes to communicate with it, you can give the subprocess' STDOUT pipe to Net::WebSocket::Server's watch_readable function and, with no tick handler at all, automatically be notified every time the subprocess sends you data (probably, an alert description ready to be delivered). I assume the subprocess would also isolate your SSL issues. For completeness, the AnyEvent analogue to this approach would be to use AnyEvent::Process, which would automate most of the pipe connection rigging for you, but with the costs I described before. To track per-connection state, rather than keep a separate table of all the connections, it might be simpler to keep a local variable in the on_connect routine. Variables declared in on_connect via `my' will persist (via closure) and be accessible by any of the subs defined within. (If something outside that scope needs access to that state, this approach won't work; I can add a mechanism to store outside state within connection objects if you like.)
Subject: Re: [rt.cpan.org #127311] Handling new connections in child process
Date: Mon, 8 Oct 2018 16:50:02 -0400
To: bug-Net-WebSocket-Server [...] rt.cpan.org
From: Pliable Pixels <pliablepixels [...] gmail.com>
Thanks. Yes, I'll likely have to fork and pipe() as I don't see another option. The task cannot be broken down to any smaller steps, unfortunately as the neural net detection is an atomic operation. Do I need to do anything specific to close this issue? I haven't used the cpan bug reporting mechanism before and all of this is via email. I don't see a close interface in https://rt.cpan.org/Public/Bug/Display.html?id=127311 On Mon, Oct 8, 2018 at 4:29 PM Eric Wastl via RT < bug-Net-WebSocket-Server@rt.cpan.org> wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=127311 > > > On Mon Oct 08 09:01:09 2018, pliablepixels@gmail.com wrote:
> > Thanks for your detailed reply. Admittedly, I did not provide sufficient > > project context. I am already using your "on_tick" handler today. > > The context is as follows: > > > > 1. The project involves using this module to broadcast "alarms" to > > listeners over websockets (Home security camera alarms). The server in > > turns connects to the home security solution to listen for alarms (not > > related to this module) > > 2. When a listener (such as a mobile app) connects to the server, I store > > the incoming connection to a master list (because in addition to the > > connection your module manages, I need to associate meta-data with it > > related to my project) > > 3. I use your "on_tick" handler every 5 seconds, to invoke a > > "checkAlarms()" procedure that interacts with the security server to see
> if
> > a new alarm occurred and if so, runs some algorithms in a routine called > > processAlarms() and if necessary sends out a notification to the listener > > 4. Multiple alarms may occur for different cameras at the same time > > 5. processAlarms() basically is a time consuming process because it tuns > > some neural nets on the image for classification > > > > My goal therefore was this: > > > > on_tick => if (checkAlarms()) { // fork and run processAlarms($conn) } > > where processAlarms($conn) sends out the notification over websockets, > > which I can't do due to SSL states (parent instantiates the connection) > > > > Thank you. > >
> > I'm not understanding the SSL state issues; it's not my area of expertise, > but it was my understanding that each SSL connection is isolated from the > others. > > Because of your expensive neural network operations (and to isolate your > SSL issue I don't fully understand), maybe it would be better to run *that* > in a separate process. > > Event-driven systems (like the ones used by Net::WebSocket::Server or > AnyEvent) are typically based on cooperative multitasking; if you have a > long-running operation like a neural net, it will prevent all other events > (like WebSocket activity) from being handled until it finishes. The > event-driven solution for this is to break the work into small operations > that can be handled individually, returning control to the event system > between steps so other events can be handled. > > If you fork a subprocess (for the alert monitoring / neural network work) > before you start the webserver and use pipes to communicate with it, you > can give the subprocess' STDOUT pipe to Net::WebSocket::Server's > watch_readable function and, with no tick handler at all, automatically be > notified every time the subprocess sends you data (probably, an alert > description ready to be delivered). I assume the subprocess would also > isolate your SSL issues. > > For completeness, the AnyEvent analogue to this approach would be to use > AnyEvent::Process, which would automate most of the pipe connection rigging > for you, but with the costs I described before. > > To track per-connection state, rather than keep a separate table of all > the connections, it might be simpler to keep a local variable in the > on_connect routine. Variables declared in on_connect via `my' will persist > (via closure) and be accessible by any of the subs defined within. (If > something outside that scope needs access to that state, this approach > won't work; I can add a mechanism to store outside state within connection > objects if you like.) >
On Mon Oct 08 16:50:55 2018, pliablepixels@gmail.com wrote: Show quoted text
> Thanks. Yes, I'll likely have to fork and pipe() as I don't see > another > option. The task cannot be broken down to any smaller steps, > unfortunately > as the neural net detection is an atomic operation. > > Do I need to do anything specific to close this issue? I haven't used > the > cpan bug reporting mechanism before and all of this is via email. I > don't > see a close interface in > https://rt.cpan.org/Public/Bug/Display.html?id=127311 > > > On Mon, Oct 8, 2018 at 4:29 PM Eric Wastl via RT < > bug-Net-WebSocket-Server@rt.cpan.org> wrote: >
> > <URL: https://rt.cpan.org/Ticket/Display.html?id=127311 > > > > > On Mon Oct 08 09:01:09 2018, pliablepixels@gmail.com wrote:
> > > Thanks for your detailed reply. Admittedly, I did not provide > > > sufficient > > > project context. I am already using your "on_tick" handler today. > > > The context is as follows: > > > > > > 1. The project involves using this module to broadcast "alarms" to > > > listeners over websockets (Home security camera alarms). The server > > > in > > > turns connects to the home security solution to listen for alarms > > > (not > > > related to this module) > > > 2. When a listener (such as a mobile app) connects to the server, I > > > store > > > the incoming connection to a master list (because in addition to > > > the > > > connection your module manages, I need to associate meta-data with > > > it > > > related to my project) > > > 3. I use your "on_tick" handler every 5 seconds, to invoke a > > > "checkAlarms()" procedure that interacts with the security server > > > to see
> > if
> > > a new alarm occurred and if so, runs some algorithms in a routine > > > called > > > processAlarms() and if necessary sends out a notification to the > > > listener > > > 4. Multiple alarms may occur for different cameras at the same time > > > 5. processAlarms() basically is a time consuming process because it > > > tuns > > > some neural nets on the image for classification > > > > > > My goal therefore was this: > > > > > > on_tick => if (checkAlarms()) { // fork and run > > > processAlarms($conn) } > > > where processAlarms($conn) sends out the notification over > > > websockets, > > > which I can't do due to SSL states (parent instantiates the > > > connection) > > > > > > Thank you. > > >
> > > > I'm not understanding the SSL state issues; it's not my area of > > expertise, > > but it was my understanding that each SSL connection is isolated from > > the > > others. > > > > Because of your expensive neural network operations (and to isolate > > your > > SSL issue I don't fully understand), maybe it would be better to run > > *that* > > in a separate process. > > > > Event-driven systems (like the ones used by Net::WebSocket::Server or > > AnyEvent) are typically based on cooperative multitasking; if you > > have a > > long-running operation like a neural net, it will prevent all other > > events > > (like WebSocket activity) from being handled until it finishes. The > > event-driven solution for this is to break the work into small > > operations > > that can be handled individually, returning control to the event > > system > > between steps so other events can be handled. > > > > If you fork a subprocess (for the alert monitoring / neural network > > work) > > before you start the webserver and use pipes to communicate with it, > > you > > can give the subprocess' STDOUT pipe to Net::WebSocket::Server's > > watch_readable function and, with no tick handler at all, > > automatically be > > notified every time the subprocess sends you data (probably, an alert > > description ready to be delivered). I assume the subprocess would > > also > > isolate your SSL issues. > > > > For completeness, the AnyEvent analogue to this approach would be to > > use > > AnyEvent::Process, which would automate most of the pipe connection > > rigging > > for you, but with the costs I described before. > > > > To track per-connection state, rather than keep a separate table of > > all > > the connections, it might be simpler to keep a local variable in the > > on_connect routine. Variables declared in on_connect via `my' will > > persist > > (via closure) and be accessible by any of the subs defined within. > > (If > > something outside that scope needs access to that state, this > > approach > > won't work; I can add a mechanism to store outside state within > > connection > > objects if you like.) > >
I can close the ticket. Please let me know if you need anything else!