Server.close() not stoping - javascript

Below is a simple code which I wrote :-
var http = require('http');
var server = http.createServer(function (req,res) {
res.end("Hello World")
})
server.listen(5000);
setTimeout(() => {server.close() } ,4000); // put anytime duration here
The behaviour which I expected was that server should stay on for 4 seconds and then closes. But rather what is happening is that server stays on indefinitely and we can do anything, however when we leave server idle for 4 seconds, after that if we reload or do anything then the timer of 5 seconds starts and after that server closes.
Means from 0 to n seconds I kept on working, then left idle for 4 seconds, on 24th second I reloaded again and then on 29th second the server is closing.
Why is it happening like that. Basically settimeout will move to call queue after 5 seconds and then it should be moved to call stack by event loop and close the server as soon as it goes idle.We can put anytime duration in timeout we have to wait leave server idle for that duration for the settimeout to begin and after that 5 seconds it take to close it.
Why is it behaving so ?
I expected that the server shall close after 4 seconds but it is not happening so.

The issue is that setTimeout is non-blocking and does not wait for the server to finish processing any requests before closing. This means that even though server.close() is called after 5 seconds, the server continues to process any requests that were already in progress at that time. To ensure that the server closes after 5 seconds, regardless of any active requests, you can use the server.unref() method before calling setTimeout. This method tells node.js to not keep the event loop running solely for the server, so that it can close as soon as there are no other events to process.
server.unref();
setTimeout(() => {server.close() } ,5000);

Related

Websockets onMessage function: What happens if the code block within onMessage takes longer to run than interval between two messages?

As a websocket client, we have access to an onMessage function that fires everytime the client receives a message from the server. I am trying to understand what happens if the code block called on the onMessage event takes longer to run the interval between the next message being received.
For example, I tested out the code below:
client.onMessage = (event) => {
console.log('Message Received')
setTimeout(() => console.log('Delay of 10 seconds'), 10000)
}
The output I got was quite strange:
Message Received
Message Received
Message Received
Message Received
Message Received
Message Received
Message Received
Message Received
Message Received
Message Received
Message Received
Message Received
Delay of 10 seconds
Message Received
Delay of 10 seconds
Delay of 10 seconds
Delay of 10 seconds
Message Received
Delay of 10 seconds
Delay of 10 seconds
Message Received
Delay of 10 seconds
Delay of 10 seconds
Delay of 10 seconds
Message Received
Delay of 10 seconds
Message Received
Message Received
Message Received
Message Received
Message Received
Delay of 10 seconds
Message Received
Anyone has any idea what is going on here?
On a related note, what happens if the function called within the block is an async function like below?
client.onMessage = async(event) => {
console.log('Message Received')
await setTimeout(() => console.log('Delay of 10 seconds'), 10000)
}
Would this just keep executing and adding console.log's to the end of the async queue until memory was full and it gave a buffer error?
Thanks for the insights! :)
setTimeout doesn't block. It looks like you're just receiving many messages in the first 10 seconds. Lots of onMessage callbacks run immediately, and lots of future setTimeout callbacks get queued, but the first setTimeout callback only starts running after 10 seconds.
On a related note, what happens if the function called within the block is an async function like below?
Nothing - async functions don't block either. awaiting a setTimeout doesn't do anything, because setTimeout returns a number, not a Promise.
Even if setTimeout returned a Promise, Promises still don't block, so the situation would be the same.
Would this just keep executing and adding console.log's to the end of the async queue until memory was full and it gave a buffer error?
This would only be a risk if you had actual blocking code, eg:
client.onMessage = (event) => {
const now = Date.now();
console.log('Message Received')
while (Date.now() - now < 10000);
console.log('Delay of 10 seconds');
}
Here, eventually (might take a long time), there would be too many events for the machine's memory to handle, and the script would fail. But such expensive blocking code is rare and often an indication of a problem in the logic, so it's not something to worry about in nearly any sane situation.

Server saturation with Ajax calls

I'm using PHP over IIS 7.5 on Windows Server 2008.
My web application is requesting repeatedly with Ajax in the background 3 different JSON pages:
page 1 Every 6 seconds
page 2 Every 30 seconds
page 3 Every 60 seconds
They retrieve data related with the current state of some tables. This way I keep the view updated.
Usually I have no much trouble with it, but lately I saw my server saturated with hundreds of unanswered requests and I believe the problem can be due to a delay in one of the request.
If page1, which is being requested every 6 seconds, needs 45 seconds to respond (due to slow database queries or whatever), then it seem to me that the requests start getting piled one after the other.
If I have multiple users connected to the web application at the same time (or with multiple tabs) things can turn bad.
Any suggestion about how to avoid this kind of problem?
I was thinking about using some thing such as ZMQ together with Sockets.io in the client side, but as the data I'm requesting doesn't get fired from any user action, I don't see how this could be triggered from the server side.
I was thinking about using some thing such as ZMQ together with Sockets.io in the client side...
This is almost definitely the best option for long-running requests.
...but as the data I'm requesting doesn't get fired from any user action, I don't see how this could be triggered from the server side.
In this case, the 'user action' in question is connecting to the socket.io server. This cut-down example is taken from one of the socket.io getting started docs:
var io = require('socket.io')(http);
io.on('connection', function(socket) {
console.log('a user connected');
});
When the 'connection' event is fired, you could start listening for messages on your ZMQ message queue. If necessary, you could also start the long-running queries.
I ended up solving the problem following the recommendation of #epascarello and improving it a bit if I get no response in X time.
If the request has not come back, do not send another. But fix the serverside code and speed it up.
Basically I did something like the following:
var ELAPSED_TIME_LIMIT = 5; //5 minutes
var responseAnswered = true;
var prevTime = new Date().getTime();
setInterval(function(){
//if it was answered or more than X m inutes passed since the last call
if(responseAnsswered && elapsedTime() > ELAPSED_TIME_LIMIT){
getData()
updateElapsedTime();
}
}, 6000);
function getData(){
responseAnswered = false;
$.post("http://whatever.com/action.json", function(result){
responseAnswered = true
});
}
//Returns the elapsed time since the last time prevTime was update for the given element.
function elapsedTime(){
var curTime = new Date().getTime();
//time difference between the last scroll and the current one
var timeDiff = curTime - prevTime;
//time in minutes
return (timeDiff / 1000) / 60;
}
//updates the prevTime with the current time
function updateElapsedTime(){
prevTime = new Date().getTime();
}
This is a very bad setup. You should always avoid polling if possible. Instead of sending request every 6 seconds from client to server, send data from server to the clients. You should check at the server side if there is any change in the data, then transfer the data to the clients using websockets. You can use nodejs at the server side to monitor any changes in the data.

PHP Script to re-run itself until process completed.and then restart every week

I've made a script that retrieves XML content from a web service. The process needs to be run once a week, but the script itself needs to be re-run about 180 times to complete the process. Each run of the script takes about 3-8 minutes. I would like it to re-run about 5 seconds after each completion.
My current solution for this is:
Task scheduler for windows opens the php page once a week.
When script is run and completed, javascript makes the page restart 5 seconds after completion.
When the last time of the script runs it removes the reload of the page so that it stops.
The problem with this solution is that it opens a new browser window every week. Is there any good alternative ways of doing this without having to manually close down the browser?
The reason of re-run of the script is due to script timeout settings of the php server max limit, and the possibility to after each run to see status whether any error occurred.
I'm not using cron since it would require to do extremely many polls in order to get the process to start within 5 seconds of last time run. For the weekly start up of the script I assume it wouldn't work as long as the script uses javascript to rerun itself?
With PHP:
<?php
// increase the maximum execution time to 43200 seconds (12 hours)
set_time_limit(43200);
function runTask() {
static $cycles = 0;
// do whatever you need to do
// Increments cycle count then compares against limit
if ($cycles++ < 180) {
sleep(5); // wait five seconds
runTask(); // run it again
}
}
runTask(); // fire up the loop
Or, if you're a fan of Javascript...
With node.js:
var cycles = 0;
function runTask() {
// do whatever you need to do
// Increments cycle count then compares against limit
if (cycles++ < 180) {
setTimeout(runTask, 5000); // run again in 5000 milliseconds
}
}
runTask(); // fire up the loop
Both solutions will not run the function again until 5 seconds after each iteration has completed.
Just have your task runner execute either script directly; no need for browsers.

Does Node.js really do the background I/O tasks asynchronously?

Edit: We can close. Isn't truly asynchronous, non-blocking javascript impossible?
var PATH = require ("path");
var URL = require ("url");
var sleep = function (ms){
var start = new Date ().getTime ();
while ((new Date ().getTime () - start) < ms);
}
require ("http").createServer (function (req, res){
if (URL.parse (req.url).pathname === "/1"){
console.log ("tab 1: I'm in");
PATH.exists ("test", function (exists){
sleep (5000);
res.writeHead (200, {"Content-Type": "text/plain"});
res.end ("1");
console.log ("tab 1: I'm done");
});
}else{
console.log ("tab 2: I'm in");
res.writeHead (200, {"Content-Type": "text/plain"});
res.end ("2");
console.log ("tab 2: I'm done");
}
}).listen (80);
Copy the content into a file.
Execute the file.
Open a new tab in browser. Set the url to localhost/1. Don't go yet.
Open a new tab in browser. Set the url to localhost/2. Don't go yet.
Go back to the first tab. Press enter and immediately after change to the second tab and press enter.
Result:
console log:
tab 1: I'm in
tab 1: I'm done
tab 2: I'm in
tab 2: I'm done
Tab 1 waits 5 seconds to receive the result "1".
Tab 2 also has to wait 5 seconds because tab 1 is sleeping for 5 seconds.
The docs says that all is asynchronous except the code. Only one thread. Only one request at a time. Requests are enqueued.
I/O calls are supposed to be asynchronous, right? Then why tab 2 has to wait to tab 1 if the callback comes from an asynchronous I/O process?
Thanks.
Because your sleep is blocking the event loop.
Replace it with setTimemout(function() { /* Code to run */ }, 5000); and watch /2 respond immediately.
The actual I/O is asynchronous, but all actions you're performing on the I/O happen in the event loop. If something is blocking the event loop, everything else has to wait, just like you said.
EDIT. For more clarity, look at the following ASCII graphic:
Event Loop Thread: ------+req1HandlerExistsCall+-------+req1Wait5Sec++++++++++++++++++++++++++req2ExistsCall+-------+req2Immediate+-------------
HTTP I/O: -+req1+--------------------------------------+req2+--------------------------------------+req1Response+--------+req2Response+
File I/O: ----------------------------+exists1+----------------------------------------------------+exists2+---------------------------
Basically, only one at a time for each thread. Because the first request handler blocks for 5 seconds (and it's essentially impossible to beat your filesystem with your fingers in a speed test), the second response doesn't even start to be handled until the first request is almost done.
You don't have any I/O calls in your code
You are calling a busy sleep method in your code ie your code is taking 5 seconds to process. And while it is processing nothing else can run on that instance
Honestly, is this a real question or are you just trying to bash node?
Sleep is implemented in blocking manner and runs on the very engine that is being single threaded.
SetTimeout method is the equivalent version of waiting some time in JavaScript.
Also consider, that in JavaScript most thing should involve a resultHandler as continuation is handled with function typed parameters to other functions to be invoked when the job is done.

Cancel Javascript timeout

I have a long process hosted on a Web Server. The thing is triggered from a Web Page, at the click of a button by a user. Some Javascript polls regularly via Ajax to check if the operation has completed server side. To do this, I use setInterval, and later on clearInterval to stop polling.
If this takes too long (e.g. server has crashed), I'd like the client to be informed by some sort of timeout. I've done some research and found about setTimeout. Problem is, if the operation finishes successfully before the timeout, I'd like to cancel this one.
How to do this ?
Would you suggest a different approach ?
PS : I'm targetting IE7/IE8 in particular, but always open to some JQuery
As long as you store your interval's id in a variable, you can use it to clear the interval at any time.
var interval = window.setInterval(yourFunction, 10000);
...elsewhere...
window.clearTimeout(interval);
For more information see the Mozilla Documentation's setInterval example.
Put together a quick JS Fiddle containing a modified version of Mozilla's Example.
To clear a setTimeout, use clearTimeout.
You want two timers (as you said)
repeating interval to do the next poll and
one-time expiration to give up if the server never responds
If the polling is successful you want to clear both the polling interval and cancel the failure timer. If the expiration timer fires you want to clear the polling interval
var checkCount = 0;
function checkComplete() {
console.log("test " + checkCount);
if (checkCount++ > 10) {
console.log("clearing timeout");
window.clearInterval(pollInterval);
window.clearTimeout(expireTimer);
}
}
function cancelPolling(timer) {
console.log("clearing poll interval");
window.clearInterval(pollInterval);
}
var pollInterval = window.setInterval(checkComplete, 500);
var expireTimer = window.setTimeout(cancelPolling, 10000);
You can fiddle with the checkCount constant "10" - keep it low to simulate polling success, raise it higher for the timeout to occur before the checkCount is reached, simulating polling failure.

Categories

Resources