Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is setTimeout blocking my Node.js app?

Take this code, typical node js example of a Http server, to which I've added a delay of 5 seconds to simulate some async work taking place somewhere else:

const http = require('http');

const hostname = '127.0.0.1';
const port = 8080;

http.createServer((req, res) => {
  setTimeout(()=>{
      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.end('Hello World\n');
  },5000);
}).listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

What I would expect is that when I open 5 tabs, let's say with a delay of half a second between opening each, the server should "respond" to each tab more or less with this timings:

t=0s - I open first tab
t=0.5s - I open second tab
t=1s - I open third tab
...
t=5s - First tab stops loading, server has replied
t=5.5s - Second tab stops loading, server has replied
t=6s - Third tab stops loading, server has replied
t=6.5s - Fourth tab stops loading, server has replied
t=7s - Fifth tab stops loading, server has replied

However, the behaviour I'm seeing is the following:

t=0s - I open first tab
t=0.5s - I open second tab
t=1s - I open third tab
...
t=5s - First tab stops loading, server has replied
t=10s - Second tab stops loading, server has replied
t=15s - Third tab stops loading, server has replied
t=20s - Fourth tab stops loading, server has replied
t=25s - Fifth tab stops loading, server has replied

As if the subsequent requests weren't starting to run until the first one has finished. Am I missing something here? I thought the whole point of Node JS was to be able to run async taks from a single thread?

like image 594
Ruben Serrate Avatar asked Mar 06 '16 10:03

Ruben Serrate


People also ask

Does setTimeout block node?

setTimeout doesn't block anything, just like it doesn't block on the client side. You shouldn't confuse for example PHP's sleep function with setTimeout (or setInterval for that matter).

Is setTimeout blocking JS?

Explanation: setTimeout() is non-blocking which means it will run when the statements outside of it have executed and then after one second it will execute.

Does setTimeout work in node JS?

The setTimeout function is used to call a function after the specified number of milliseconds. The delay of the called function begins after the remaining statements in the script have finished executing. The setTimeout function is found in the Timers module of Node. js.

How do I avoid setTimeout?

You can also prevent the setTimeout() method from executing the function by using the clearTimeout() method. If you have multiple setTimeout() methods, then you need to save the IDs returned by each method call and then call clearTimeout() method as many times as needed to clear them all.


1 Answers

The problem isn't your code or Node.js -- it's how you set up your test.

You wrongly assumed that your browser would make 5 concurrent requests, which is not happening. Different browsers have different behaviors, but typically browsers limit to a very low number the maximum amount of simultaneous connections to a single origin. The HTTP spec gives a suggest maximum. I was actually quite surprised to see Chrome only opening 1 single connection to localhost, as I know Chrome opens 6 to other origins -- just learned something new!

Use a different tool to run your test, one that you can control and know for sure that it's making concurrent requests. Then you'll see the expected behavior.

As an example, I ran your code and tested with Apache Benchmark as shown below. The parameters indicate: -n 10 is to make 10 requests, -c 10 is to use concurrency 10 (ie, make all the ten requests concurrently). As you can see in the results below, the total time taken for all the requests was ~5s (and "time per request" 0.5s):

~ $ ab -n 10 -c 10 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1663405 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      10
Time taken for tests:   5.019 seconds
Complete requests:      10
Failed requests:        0
Total transferred:      1130 bytes
HTML transferred:       120 bytes
Requests per second:    1.99 [#/sec] (mean)
Time per request:       5019.151 [ms] (mean)
Time per request:       501.915 [ms] (mean, across all concurrent requests)
Transfer rate:          0.22 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       0
Processing:  5017 5018   0.3   5018    5018
Waiting:     5008 5008   0.2   5008    5009
Total:       5018 5018   0.2   5019    5019
ERROR: The median and mean for the total time are more than twice the standard
       deviation apart. These results are NOT reliable.

Percentage of the requests served within a certain time (ms)
  50%   5019
  66%   5019
  75%   5019
  80%   5019
  90%   5019
  95%   5019
  98%   5019
  99%   5019
 100%   5019 (longest request)
like image 71
Bruno Reis Avatar answered Oct 18 '22 08:10

Bruno Reis