How to stop setInterval when javascript process ends - javascript

I have an interval set to run a function every 5 minutes: const timer = setInterval(func, TIMEOUT)
This starts when a specific object is created and I use clearInterval to stop it once a condition is met. This works as expected in practice. However, there are certain tests (using chai and sinon) that result in the creation of the object, though they are not specifically testing the creation of the object. This leads to the creation of the interval, which prevents the tests from every finishing.
I saw in node there is timer.unref(), which sounds like it would work for me, but in practice since setInverval in js returns an id, I get a type error Timer.unref is not a function
Is there a way to stop an interval in javascript when the test process ends?
Edit: The creation of the object exists in one package, as part of an API call, and the tests are calling the API from another package, so do not have access to the creation of the object nor the timer. The condition which clears the interval is not (and cannot) be met in the tests.

Related

How to store setInterval globally and efficiently in Node.js so I can clear it from any route from my API?

When new order is insert I need to distribute it to subscribers based on a time gap of 12 seconds.
For example: A will receive the order immediately, 12 seconds later it will be reached to B.
If someone picks the order, for example B, I need to stop the propagation to C and D.
If B rejects the order, I don't want to wait until the 12 seconds resolve, I want to immediately propagate the order to the next in turn (C).
What I have tried to do is to set a recursive function firing by the time the setTimeout is functioned. But I don't have any way to clear it or skip or restart the mechanism for the cases I described above.
If I could save the setTimeout/setInterval instance in a global variable that could allow me to manage it from other API routes.
But I am not sure at all if it's a good approach, since storing global variables in node can lead to problems.
Maybe I can store it via Redis or cache or something so it won't catch too much memory and wont get collided with another methods that stored globally?

Non-blocking setTimeout

Is it possible in NodeJS to implement a version of setTimeout that wouldn't block the process from exiting once the last line of code has finished?
i.e. the kind of conditional setTimeout that would only trigger the callback function provided the process is still running.
Practical example:
When implementing a library that initializes itself by setting up some timeouts, you would want that once the app has finished, you don't need to make an explicit call into that library to clear all the timeouts, and let the app shut down regardless.
You can use clearTimeout if you wanted to maintain references to all your outstanding timers and then clear them as part of your application exit process, but it is much easier in node to use unref() Node doc on unref. The effect is that any unrefed timer will not prevent Node from exiting.
For example:
var to = setTimeout(myFunction,delay);
to.unref();
Works with setInterval as well
setInterval(myFunction,delay).unref();
If you look at the docs for setTimeout, you will notice that it returns a timeoutObject that can be used to cancel the timeout via clearTimeout(obj).
So what you could do is keep track of all the timeouts you create by storing their id objects. Then you are able end all the timeouts whenever you want.
If you simply want to exit the process, ignoring everything else, you can just use process.exit() (passing an argument if you want to return a non zero error code).

Javascript internals - clearTimeout just before it fires

Let's say I do this:
var timer = setTimeout(function() {
console.log("will this happen?");
}, 5000);
And then after just less than 5 seconds, another callback (from a network event in NodeJS for example) fires and clears it:
clearTimeout(timer);
Is there any possibility that the callback from the setTimeout call is already in the queue to be executed at this point, and if so will the clearTimeout be in time to stop it?
To clarify, I am talking about a situation where the setTimeout time actually expires and the interpreter starts the process of executing it, but the other callback is currently running so the message is added to the queue. It seems like one of those race condition type things that would be easy to not account for.
Even though Node is single thread, the race condition the question describes is possible.
It can happen because timers are triggered by native code (in lib_uv).
On top of that, Node groups timers with the same timeout value. As a result, if you schedule two timers with the same timeout within the same ms, they will be added to the event queue at once.
But rest assured node internally solves that for you. Quoting code from node 0.12.0:
timer.js > clearTimeout
exports.clearTimeout = function(timer) {
if (timer && (timer[kOnTimeout] || timer._onTimeout)) {
timer[kOnTimeout] = timer._onTimeout = null;
// ...
}
}
On clearing a timeout, Node internally removes the reference to the callback function. So even if the race condition happens, it can do no harm, because those timers will be skipped:
listOnTimeout
if (!first._onTimeout) continue;
Node.js executes in a single thread.
So there cannot be any race conditions and you can reliably cancel the timeout before it triggers.
See also a related discussion (in browsers).
I am talking about a situation where the setTimeout time actually expires and the interpreter starts the process of executing it
Without having looked at Node.js internals, I don't think this is possible. Everything is single-threaded, so the interpreter cannot be "in the process" of doing anything while your code is running.
Your code has to return control before the timeout can be triggered. If you put an infinite loop in your code, the whole system hangs. This is all "cooperative multitasking".
This behavior is defined in the HTML Standard, the fired task starts with:
If the entry for handle in the list of active timers has been cleared, then abort these steps.
Therefore even if the task has been queued already, it'll be aborted.
Whether this applies to Node.js, however, is debatable, as the documentation just states:
The timer functions within Node.js implement a similar API as the timers API provided by Web Browsers but use a different internal implementation that is built around the Node.js Event Loop.

A Reliable timer for Javascript

I have a web site and i am using a javscript timer to swap images about.
I am using the timer like this:
var myTimer = window.setTimeout(MyFunction, MyInterval);
function MyFunction
{
//do something
//recalll timer
}
Now, the problem I have is not that the interval does not fire off at regular intervals as I can accept that in my application and I understand why it can vary.
The issue I have is that every now and then the timer stops for a few seconds and then resumes.
What I am trying ascertain is what is the main cause of this random suspension of the timer?
Is it due to the resources being diverted to another process on the hosting browser PC OR is it just the nature of using a JavaScript timer?
If the latter should I look to do an eternal loop? Everywhere I read and have practised elsewhere indicates that an infinite loop will grab all the resources and it would be a greater evil than the timer random suspension.
Are there any alternatives to using a javascript timer when a regular quick execution of code is paramount?
Thanks
The code you run inside MyFunction takes some time to execute (depending on what you are doing). When you recall the timer at the end of that function, the interval is not exactly MyInterval, because of the code execution time being added.
If you use setInterval() instead of setTimeout(), the given function will be executed exactly every MyInterval milliseconds rather than (MyInterval + execution time) milliseconds.
To answer your question, the random suspension happens because of the execution time of your code.
I had a similar issue on a website I was working on and ultimately found the culprit in another timer-triggered job in a jQuery plugin that was occasionally delaying execution of my own function. If you're using external code in your site, you could do some debugging to see if this is your case too.
As a possible remedy, you could give a look at web workers. Since worker tasks are executed in a separated thread, they are not subject to delay when something in your main thread is taking too long to complete.
Your code would then look like this:
var worker = new Worker('worker.js');
And in another file called "worker.js" you would write:
var myTimer = setTimeout(MyFunction, MyInterval);
function MyFunction
{
//do something
//recalll timer
}
Just note that there is no window. anymore before setTimeout. This is because web workers don't have direct access to the DOM.
It's not guaranteed to solve your problem, but it's worth a test.

How to test for user-specified time in setTimeout

Right now I have a jQuery plugin that adds some extra customization (around how to handle the return data in certain contexts) and polling a server for information and changes. One of the required features is to allow the user set the polling interval. setTimeout (paired with recursion) is the function that is used for creating the constant poll; this is also a requirement.
This is where I am stumped: along with the required functionality noted above, I also have to test if the user-specified value was actually used in the setTimeout. How would I go about doing this from a QUnit perspective?
I have already pondered straight timing the function with Date.getTime(), but the way things are currently set up this isn't an option.
Consider refactoring the code in a way that let's you override the method starting the timeout within your test, allowing you to verify that the correct value is passed, without actually starting the timeout.
If you need to actually call setTimeout, consider using sinon.js to mock setTimeout itself and control what it does instead.

Categories