Node.js / express: immediately respond to the client’s request and continue with the nextTick tasks

I would like to highlight a server task with high CPU consumption from the user:

./main.js:

var express = require('express'); var Test = require('./resources/test'); var http = require('http'); var main = express(); main.set('port', process.env.PORT || 3000); main.set('views', __dirname + '/views'); main.use(express.logger('dev')); main.use(express.bodyParser()); main.use(main.router); main.get('/resources/test/async', Test.testAsync); main.configure('development', function() { main.use(express.errorHandler()); }); http.createServer(main).listen(main.get('port'), function(){ console.log('Express server app listening on port ' + main.get('port')); }); 

./resources/test.js:

 function Test() {} module.exports = Test; Test.testAsync = function(req, res) { res.send(200, "Hello world, this should be sent inmediately"); process.nextTick(function() { console.log("Simulating large task"); for (var j = 0; j < 1000000000; j++) { // Simulate large loop } console.log("phhhew!! Finished!"); }); }; 

When you ask for "localhost: 3000 / resources / test / async", I expect that the rendering of the browser "Hello world, it needs to be sent right away" is very fast and node.js to continue processing and after a while the message "completed" appears in the console "

Instead, the browser continues to wait until node.js completes a large task and then displays the contents. I tried with res.set({ 'Connection': 'close' }); , as well as res.end(); but nothing works as expected. I also did not look googled.

How should I immediately send a response to the client, and the server should continue the tasks?

EDIT

published fork method in solution

+6
source share
3 answers

Thakns to help Peter Lyon, finally, the main problem was firefox buffer: the answer was not as long as clearing it (so Firefox kept waiting).

In any case, to run high-performance CPUs, the node will be held until it runs out, so it will not visit new requests. If someone needs this, this can be achieved by forking (with child_process, see Sample at http://nodejs.org/api/child_process.html )

I must say that changing the context by forking can take longer than splitting the task in different ticks.

./resources/test.js:

 var child = require('child_process'); function Test() {} module.exports = Test; Test.testAsync = function(req, res) { res.send(200, "Hello world, this should be sent inmediately"); var childTask = child.fork('child.js'); childTask.send({ hello: 'world' }); }; 

./resources/child.js:

 process.on('message', function(m) { console.log('CHILD got message:', m); }); 
+4
source

Try to wait, instead of expelling the processor:

 res.send("Hello world, this should be sent inmediately"); console.log("Response sent."); setTimeout(function() { console.log("After-response code running!"); }, 3000); 

node.js is single threaded. If you lock the CPU with a busy cycle, all this will stop until it is done.

+6
source

A good solution is to use child_process.fork() : it allows you to execute another JavaScript file of your application in a different instance of Node and, therefore, in a different event loop . Of course, you can still communicate between the two processes by sending messages: therefore, from the user interface process, you can send a message to the forked process to ask it to do something.

For example, in ui.js :

 var ChildProcess = require('child_process'); var heavyTaskWorker = ChildProcess.fork('./heavyTaskWorker.js'); ... var message = { operation: "longOperation1", parameters: { param1: "value1", ... } }; heavyTaskWorker.send(message); 

And in heavyTaskWorker.js :

 process.on('message', function (message) { switch (message.operation) { case 'longOperation1': longOperation1.apply(null, message.parameters); break; ... } }); 

Tested here and it works great!

Hope this helps!

+1
source

All Articles