express js setInterval route 1 and clearInterval route 2 - node.js

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, ...).

Related

Node.js and socket.io - Access socket from a different file

i'm having a problem accessing the socket from a secondary file:
Having two files:
1) main.js
2) secondary.js
In main.js:
var sec = require('./secondary.js');
function DoFuncOnSecondaryFile(){
setInterval(function(){
//here i can't pass the socket, because it is not inside "io.on connection"
sec.myExternalFunc( socket );
}, 5000);
}
io.on('connection', function(socket){
//all the socket events in here
});
In secondary.js:
module.exports = {
myExternalFunc: function(){
socket.emit("message", "I cannot reach the socket so i will throw an error");
socket.to(anId).emit("message", "Supposing 'anId' is correctly defined and it is the id of a connected socket, this function won't work anyway!");
}
}
I need the function "myExternalFunc()" to be executed every 5 seconds, if i want to pass the socket as argument, i need to put it inside io.on('connection') so that the socket variable is defined, but then my Interval will start everytime someone connects.
How can I use an emit in an external file where i am not able to pass the socket variable?

How to make setInterval running on background?

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...

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.

mocha should expect a timeout, call done() when timed out

I'm trying to write a test for socket. I'm using passport.socketio and so socket shouldn't be connected (and thus the socket callback never fired) when there's no logged in user. I want to test that.
Is there a way to actually expect a timeout?
describe('Socket without logged in user', function() {
it('passport.socketio should never let it connect', function(done) {
socket.on('connect', function() {
// this should never happen, is the expected behavior.
});
});
});
Or any other way I should approach this?
You can basically program it yourself:
var EXPECTED_TIMEOUT = 2000; // This value should be lesser than the actual mocha test timeout.
it('passport.socketio should never let it connect', function(done) {
this.timeout(EXPECTED_TIMEOUT + 100); // You add this to make sure mocha test timeout will only happen as a fail-over, when either of the functions haven't called done callback.
var timeout = setTimeout(done, EXPECTED_TIMEOUT); // This will call done when timeout is reached.
socket.on('connect', function() {
clearTimeout(timeout);
// this should never happen, is the expected behavior.
done(new Error('Unexpected call'));
});
});
You can also use addTimeout module to shorten the code:
var EXPECTED_TIMEOUT = 2000; // This value should be lesser than the actual mocha test timeout.
it('passport.socketio should never let it connect', function(done) {
this.timeout(EXPECTED_TIMEOUT + 100); // You add this to make sure mocha test timeout will only happen as a fail-over, when either of the functions haven't called done callback.
function connectCallback() {
done(new Error('Unexpected Call'));
}
socket.on('connect', addTimeout(EXPECTED_TIMEOUT, connectCallback, function () {
done()
});
});

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