How to properly handle child process descriptors

I am trying to create a platform for automatically deploying the applications that I create in NodeJS. Each application can be started and stopped from the control panel that processes these operations. The control panel performs the following actions when the application starts:

  • It will request a handle from the binder port, which runs as root. This binder is a forked child of the control panel.
  • Now the control panel listens for requests on this port. After receiving the request, it sends a client socket handle to the application that listens for the message event for new requests.
  • When the application is signaled, the control panel frees all control over the request and the socket.
  • The application does what it needs and releases and closes the request and socket.

This setup works well unless you are trying to bring down a server that is no longer required. Although the server throws a close event, it still accepts the connection, which eventually ends because there is no longer a link to the request.

I assume that there is a handle that is not released properly and thus prevents the server from waking up.

Port Binding:

var options = { http: require('http'), https: require('https') }; process.on('message',function( data, handle ) { var port = data.port, type = data.type, server; server = options[type].createServer(); server.once('error', function( err ) { process.send({success: false, port: port, error: err}); }); server.listen(port,function(){ var handle = server._handle; process.send({success: true, port: port}, handle); server.close(); handle.close(); server._handle = null; handle = null; server.removeAllListeners(); }); }); 

Control Panel:

 var cp = require('child_process'), app, types = { http: require('http'), https: require('https') }, binder = cp.fork('./portbinder'); binder.on('message', function( data, handle ) { var server = types['http'].createServer(handler); server.once('close', function() { server._handle = null; handle = null; }); server.listen( handle ); }); function handler( req, resp ) { app = app || cp.fork('./application'), socket = resp.socket, _handle = socket._handle, _req = {}, _resp = {}, _socket = {}; // Copy transferable fields. for( i in req ) { if( typeof req[i] != 'function' && i != 'socket' && i != 'connection' && i != 'client' ) { _req[i] = req[i]; } } for( i in resp ) { if( typeof resp[i] != 'function' && i != 'socket' && i != 'connection' && i != 'client' ) { _resp[i] = resp[i]; } } for( i in socket ) { if( typeof socket[i] != 'function' && i != '_handle' && i != '_httpMessage' && i != '_idlePrev' && i != '_idleNext' && i != 'server' ) { _socket[i] = socket[i]; } } // Send request to application. app.send({ type: 'request', data: { req: _req, resp: _resp, socket: _socket } }, _handle ); // Release the handle here without sending anything to the browser. socket._write = function() {}; resp.end(); socket.destroy(); socket._handle = null; _handle = null; }; 

Application:

 function reattach( target, properties ) { var i; for( i in properties ) { target[i] = properties[i]; } return target; }; function handler( req, resp ) { resp.end('hello world!'); }; process.on('message', function( param, handle ) { var _req = param.data.req, _resp = param.data.resp, _socket = param.data.socket, socket, resp, req; // Create a socket and reattach its properties. socket = new net.Socket({handle:handle}); reattach( socket, _socket ); // Create a request and reattach its properties. req = new http.IncomingMessage(socket); reattach( req, _req ); // Create a response and reattach its properties. resp = new http.ServerResponse( req ); resp.assignSocket(socket); reattach( resp, _resp ); // Help closing down sockets after request is handled. resp.once('finish', function() { socket._write = function() {}; socket.end(); socket.destroy(); socket._handle = null; handle = null; }); handler( req, resp ); }); 

As you can see, I am trying to remove and delete all the _handle properties that I have, but the server handle does not stop listening on the port. When I create the control panel, there is an uncaught exception, it will work, and the connecting device will also do this. But the node application process does not shut down, and the port remains connected, so I explain that I’m not releasing something there, but I can’t find it.

The whole setup works, it just doesn't shut down the server when I ask for it.

EDIT: I should probably note that I'm using node.js v0.5.10

+6
source share
1 answer

As it turned out, this is a misinterpretation of the node.js documentation that led to this problem. The keep-alive header was sent in the browser that I used, which for some time opened connections to cause new requests on the same connections.

When I did server.close (), I expected these connections to be closed because the docs say:

Stops server connection to new connections.

As it turned out, keep-alive connections weren’t closed, so the browser could still execute requests until the connections were open, which made me understand that the server was still accepting connections.

The solution to this issue is to reconnect requestListener to your server after it is closed. Then, when you get the connection, close the socket stream without sending anything. Now, no new requests will be processed, and as soon as the connection expires, it will close and the server will finally shut down. And thus freeing the port for other applications.

 server.close(); // Drop any new request immediately, while server ditches old connections. server.on('request', function( req, resp ) { req.socket.end(); }); server.once('close', function(){ // Remove the listeners after the server has shutdown for real. server.removeAllListeners(); }); 

By posting this fix, I could also clear my code and remove the code to free the handle. node.js the garbage collector now correctly selects handle objects, and when the connection dies, the handle also.

 // All of this is no longer needed. socket._write = function() {}; socket.end(); socket.destroy(); socket._handle = null; handle = null; 
+8
source

Source: https://habr.com/ru/post/900829/


All Articles