How to make setInterval running on background? - node.js

I have this function and it's called during my node server starts up in index.js file. In the init function, it sets setInterval to call refreshKeyValues periodically which takes about 10 sec.
I ran some tests and sent a health check (simple get call to health end point returning 200 ok) and it seemed that the health check blocked when refreshKeyValues was running.
Is setInterval blocking? How do I make this refreshing logic running on background so that it won't block the incoming requests?
export default function initMyClient(server) {
server.clients.myclient = MyClient.createNewClient();
server.clients.myclient.init();
server.keyValues = getKeyValues();
function refreshKeyValues() {
server.keyValues = getKeyValues();
}
const refreshInterval = setInterval(
refreshKeyValues,
1000
);
server.on('close', function onClose() {
clearInterval(refreshInterval);
});
}

The JavaScript's setInterval function is asynchronous, so it not blocks the main flow when it in "waiting" state. But your function refreshKeyValues seems to be not async, so it may block the main JavaScript flow. When it called, the refreshKeyValues can block the flow, because of JavaScript is single threaded.
You can take better understanding while reading through this: JavaScript event loop

Ivan Matveev is completely correct. Node.js is single threaded, even though it might look like it is not due to its async nature. However you can achieve what you need with the cluster module. Here is how to do it:
var cluster = require('cluster');
if (cluster.isMaster) {
var httpWorker = cluster.fork(); // worker thread for server
var intervalWorker = cluster.fork(); // worker thread for setInterval
// send messages to your wokers specifying the worker type
httpWorker.send({ server: true });
intervalWorker.send({ server: false });
} else {
process.on('message', function (data) {
if (data.server) {
// start server
var server = require('http').createServer(function (req, res) {
res.end('OK');
});
server.listen(8080, function () {
console.log('server running');
});
} else {
// start your interval
setInterval(function () {
console.log('1s passed');
}, 1000);
}
});
}
EDIT:
Also why are you running your refreshKeyValues function once every second if it takes 10s to run? I would recommend you call it every 10s...

Related

Forked process in expressjs causes server to restart

I have an expressjs server and it uses a fork inside a route to make sure that the main loop isn't blocked (it's somewhat computing intensive). Every time this route is called, the server restarts. I've debugged this problem and found that the forking is what causes this behaviour but I don't understand why. The route is defined as follows:
module.exports = async function someComputingIntensiveFunction(req, res) {
try {
// some stuff
const childProcess = fork('../path/to/file.js');
childProcess.on('message', (data) => {
res.status(201).json(data).end();
});
catch (error) {
res.status(500).end()
}
}
Inside this file is
process.on('message', (data) => {
// do some stuff with data
// based on whatever the result is
process.send(result);
process.exit(result.status);
});
Am I forgetting a crucial part of forking which causes the expressjs server to restart? Thanks in advance for any help.

Why we need async Callback in Node JS Since Event Loop offers Worker Pool to handle expensive task?

I was studying how Node JS improves performance for multiple concurrent request! After reading couple of blogs I found out that:
When any request come an event is triggered and corresponding
callback function is placed in Event Queue.
An event Loop(Main Thread) is responsible for handling all requests
in Event Queue. Event Loop processes the request and send back the
response if request uses Non-Blocking I/O.
If request contains Blocking I/O Event Loop internally assigns this request to
an idle worker from Work Pool and when worker send back the result
Event Loop sends the response.
My Question is since Event Loop is passing heavy blocking work internally to Work Pool using libuv library, why we need Asynchronous callback?
For Better Understanding please see the below code:
const express = require('express')
const app = express()
const port = 3000
function readUserSync(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
}
return "User"
}
async function readUserAsync(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
}
return "User"
}
app.get('/sync', (req, res) => {
const user = readUserSync(80)
res.send(user)
})
app.get('/async', async (req, res) => {
const user = await readUserAsync(80)
res.send(user)
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
I checked performance for both endpoints using apache benchmark tool, assuming each I/O operation takes 80ms.
ab -c 10 -t 5 "http://127.0.0.1:3000/async/"
ab -c 10 -t 5 "http://127.0.0.1:3000/sync/"
And surprisingly for endpoint with async callback had higher number of request per second.
So how Event Loop, Thread Pool and async await works internally to handle more concurrent requests?

express js setInterval route 1 and clearInterval route 2

i have a node js server with express js.
On one route i start an interval by using setInterval.
Now i want to stop the interval if a user navigates to a second route.
E.g.
router.get('/startInterval', function() {
var timer = setInterval(function() {
console.log('Interval is running');
}, 1000);
});
router.get('/stopInterval', function() {
// Stop the interval startet before
// clearInterval(); <--- How i get the timer object?
});
How do i do that?
What is if i declare the timer as a global variable?
Is a second user able to stop the timer started by the first user in a defferent browser?
You need to define the timer on the outside scope
var timer;
router.get('/startInterval', function() {
timer = setInterval(function() {
console.log('Interval is running');
}, 1000);
});
router.get('/stopInterval', function() {
clearInterval(timer);
});
By the way, any user going to the /stopInterval route will stop the global timer (ONE timer for ALL users).
If you want to have a different timer for every different user, you'll need way more complicated code (using session, cookie, ...).

node.js: How to sync socket receive in 2 different routes

I am still learning node.js basics. My flow is like this,
browser<-->node<-->backend server doing calculation.
node and backend uses socket to communicate.
From the browser there are start/stop buttons to ask backend to start/stop the
calculation.
When node asks backend to start/stop, it must query to see if backend is
alive first.
My code is like this -
app.get('/stopCmd', function(req, res)
{
socketToBackendServer.write("status", function() {
console.log("Sending:", 'Node asking for STATUS');
});
socketToBackendServer.on("data", function() {
if(status is ok) // pseudo code
{
socketToBackendServer.write("stop", function() {
console.log("Sending:", 'Node sending STOP');
});
} else {
console.log("backend server is NOT ready");
}
});
});
app.get('/startCmd', function(req, res)
{
// do similar things as stopCmd
});
/////////////////////////////////////////////////
var socketToBackendServer = net.connect(2899);
function openSocket() {
socketToBackendServer.setKeepAlive(true);
socketToBackendServer.on('connect', onConnect.bind({}, socketToBackendServer));
socketToBackendServer.on('error', onError.bind({}, socketToBackendServer));
}
function onConnect(socket) {
var myData;
console.log('Socket is open!');
socket.on('data', function(data) {
console.log('Received:', data);
io.emit('time', { time: data.toJSON() });
});
}
function onError(socket) {
console.log('Socket error!');
// Kill socket
clearInterval(interval);
socket.destroy();
socket.unref();
// Re-open socket
setTimeout(openSocket, 1e3);
}
openSocket();
server.listen(7778);
if using the same browser, if i go crazy clicking start/stop... for the "
stopCmd", how to make sure when it queries "status", the response is caught
by its function, not "startCmd"'s ?
it's this line
socketToBackendServer.on("data", function()
Thank you again !
You can use multiple connections to the backend server, so one function can freely use one channel, the responses won't mix.
Or you can use a multiplexer function, that you call from both of your functions:
It could work if you can identify your requests, like you send and id with the status, for example socketToBackendServer.write("status 1", ... , and you send the id with the status response back from the backend server (if it yours). In this way you can send multiple requests at the same time, and when the response come, you can identify it, and call the callback function that you stored in an array with the ids.
You only send one request, and you wait for the response before you send another one. You must use a waiting queue, where you store the request, and the callback functions.

Client can only emit once and "force new connection" duplicates the response.

my client side can only emit once and "force new connection" duplicates the response back to my client. here's my code so you can look it up.
server.js
var app = require('http').createServer()
, io = require('socket.io').listen(app);
app.listen(5000);
io.sockets.on('connection', function(socket) {
socket.on('sendSheet', function(data) {
io.sockets.emit('displayData', data);
});
socket.on('disconnect', function() {
io.sockets.emit('user disconnected');
});
});
client.js
var socket = io.connect('http://localhost:5000', {'force new connection': true});
socket.on('dispatchConnect', function (data) {
socket.emit('sendSheet', mergedForm);
});
socket.on('displayData', function (data) {
console.log(data);
});
Read about asynchronous functions in nodejs and try to understand "the node event loop".
Your code is blocking couse your functions are synchronous .
Since an event loop runs in a single thread, it only processes the next event when the callback finishes.
You should never use a blocking function inside a callback, since you’re blocking the event loop
and preventing other callbacks - probably belonging to other client connections - from being served.
Here is a async example:
var myAsyncFunction = function(someArg, callback) { // simulate some I/O was done
setTimeout(function() { // 1 second later, we are done with the I/O, call the callback
callback();
}, 1000)
}

Resources