How to create an interruptible loop in node.js - node.js

Disclaimer: I'm a Node.js newbie and the following description may be lengthy...
I'm currently trying to teach myself Node.js for a little project I'm after. The project idea is the following: a RaspberryPI runs a Node.js application which allows me to control the colors of an RGB LED strip. The application should be able to set both a static color and also run color wheels that smoothly change colors.
My idea is now to create several Node.js scripts:
A "controller" that does the client communication, sets static colors or is able to start a color wheel
"client scripts" that each run a color wheel. At most one of them would be "alive", started/stopped by the "controller"
I've been able to create a little script that forks another script and is able to stop that script using child.send as follows:
controller.js
var fork = require('child_process').fork,
test2 = fork(__dirname + '/test2.js');
setTimeout(function() { test2.send({func: 'quit'}); }, 5000);
This forks the test2.js script and after 5 seconds sends a quit message that quits test2.js.
test2.js
function runLoop()
{
console.log("Hello");
setTimeout(runLoop, 1000);
}
process.on('message', function(m) {
if (m.func === 'quit')
{
process.exit(0);
}
});
setTimeout(runLoop, 1000);
This "client script" prints "Hello" every second until the controller sends the quit message.
This works pretty well - after 5 seconds the scripts finish gracefully.
My question is now: If I implement a color wheel, I'll need a possibly endless loop that changes the colors of the LED strip. Would the above (with shorter timer values of course - I need something like 10ms here) be a feasible way of implementing an interruptible loop or is there some neater mechanism I don't know of yet?

If you're using setTimeout, you shouldn't even need to fork a new process. Here's how I would write your example:
var ntrvl = setInterval(function() { console.log('Hello'); }, 1000);
setTimeout(function() { clearInterval(ntrvl); }, 5000);
... very simple. With setTimeout and setInterval, you're using asynchronous functions, so you will not block the event loop. When the timer is up, it runs your code, then waits for the next event. You should be able to control all of your "clients", you'll have bandwidth for far more than you'll actually need, all in the same process in this way, concurrently.
All you need to be wary of is that you're not blocking the script. If you attempt to perform any action synchronously (which means that the script will wait for the action to complete before performing the next command), then you need to make sure it runs quickly. If you have to run processor/time intensive tasks synchronously, that's when you'll need to fork a new process.

You're making the life complicated. Your global architecture is as follows:
external trigger --> listener ----------> code that changes color
(ie. web client) (ie. web server)
With that in mind you don't need to fork any process, you can control the LED strip within a single process. Somewhere in your code you'll have an object similar to this:
//"led" is the module that allows you to change the color of a led (suppose 4 leds)
var led = require ("led-controller");
var ColorChanger = module.exports = function (){
this._intervalId = null;
};
ColorChanger.prototype.setColor = function (hex){
//Color in hexadecimal
//Cancel any current interval
cancelInterval (this._intervalId);
led.color (0, hex);
led.color (1, hex);
led.color (2, hex);
led.color (3, hex);
};
ColorChanger.prototype.wheel = function (hex, ms){
//Color in hexadecimal
//"ms" is the time interval between leds going on and off
//Cancel any current interval
cancelInterval (this._intervalId);
//Shutdown all the leds
led.off (0);
led.off (1);
led.off (2);
led.off (3);
//Activate the first led
led.color (0, hex);
//Current active led
var curr = 0;
this._intervalId = setInterval (function (){
//Each "ms" the current led will go off and the next will go on
led.off (curr);
//Next led to activate
curr = ++curr%4;
led.color (curr, hex);
}, ms);
};
Then the listener module uses the ColorChanger.
var ColorChanger = require ("./color-changer");
var changer = new ColorChanger ();
//Set all the leds to red
changer.setColor ("#FF0000");
//Each 10ms one led goes green and the previous is turned off, in an endless loop
changer.wheel ("#00FF00", 10);

Related

nodejs express . For loop is blocking my simple server [duplicate]

The following example is given in a Node.js book:
var open = false;
setTimeout(function() {
open = true
}, 1000)
while (!open) {
console.log('wait');
}
console.log('open sesame');
Explaining why the while loop blocks execution, the author says:
Node will never execute the timeout callback because the event loop is
stuck on this while loop started on line 7, never giving it a chance
to process the timeout event!
However, the author doesn't explain why this happens in the context of the event loop or what is really going on under the hood.
Can someone elaborate on this? Why does node get stuck? And how would one change the above code, whilst retaining the while control structure so that the event loop is not blocked and the code will behave as one might reasonably expect; wait
will be logged for only 1 second before the setTimeout fires and the process then exits after logging 'open sesame'.
Generic explanations such as the answers to this question about IO and event loops and callbacks do not really help me rationalise this. I'm hoping an answer which directly references the above code will help.
It's fairly simple really. Internally, node.js consists of this type of loop:
Get something from the event queue
Run whatever task is indicated and run it until it returns
When the above task is done, get the next item from the event queue
Run whatever task is indicated and run it until it returns
Rinse, lather, repeat - over and over
If at some point, there is nothing in the event queue, then go to sleep until something is placed in the event queue or until it's time for a timer to fire.
So, if a piece of Javascript is sitting in a while() loop, then that task is not finishing and per the above sequence, nothing new will be picked out of the event queue until that prior task is completely done. So, a very long or forever running while() loop just gums up the works. Because Javascript only runs one task at a time (single threaded for JS execution), if that one task is spinning in a while loop, then nothing else can ever execute.
Here's a simple example that might help explain it:
var done = false;
// set a timer for 1 second from now to set done to true
setTimeout(function() {
done = true;
}, 1000);
// spin wait for the done value to change
while (!done) { /* do nothing */}
console.log("finally, the done value changed!");
Some might logically think that the while loop will spin until the timer fires and then the timer will change the value of done to true and then the while loop will finish and the console.log() at the end will execute. That is NOT what will happen. This will actually be an infinite loop and the console.log() statement will never be executed.
The issue is that once you go into the spin wait in the while() loop, NO other Javascript can execute. So, the timer that wants to change the value of the done variable cannot execute. Thus, the while loop condition can never change and thus it is an infinite loop.
Here's what happens internally inside the JS engine:
done variable initialized to false
setTimeout() schedules a timer event for 1 second from now
The while loop starts spinning
1 second into the while loop spinning, the timer is ready to fire, but it won't be able to actually do anything until the interpreter gets back to the event loop
The while loop keeps spinning because the done variable never changes. Because it continues to spin, the JS engine never finishes this thread of execution and never gets to pull the next item from the event queue or run the pending timer.
node.js is an event driven environment. To solve this problem in a real world application, the done flag would get changed on some future event. So, rather than a spinning while loop, you would register an event handler for some relevant event in the future and do your work there. In the absolute worst case, you could set a recurring timer and "poll" to check the flag ever so often, but in nearly every single case, you can register an event handler for the actual event that will cause the done flag to change and do your work in that. Properly designed code that knows other code wants to know when something has changed may even offer its own event listener and its own notification events that one can register an interest in or even just a simple callback.
This is a great question but I found a fix!
var sleep = require('system-sleep')
var done = false
setTimeout(function() {
done = true
}, 1000)
while (!done) {
sleep(100)
console.log('sleeping')
}
console.log('finally, the done value changed!')
I think it works because system-sleep is not a spin wait.
There is another solution. You can get access to event loop almost every cycle.
let done = false;
setTimeout(() => {
done = true
}, 5);
const eventLoopQueue = () => {
return new Promise(resolve =>
setImmediate(() => {
console.log('event loop');
resolve();
})
);
}
const run = async () => {
while (!done) {
console.log('loop');
await eventLoopQueue();
}
}
run().then(() => console.log('Done'));
Node is a single serial task. There is no parallelism, and its concurrency is IO bound. Think of it like this: Everything is running on a single thread, when you make an IO call that is blocking/synchronous your process halts until the data is returned; however say we have a single thread that instead of waiting on IO(reading disk, grabbing a url, etc) your task continues on to the next task, and after that task is complete it checks that IO. This is basically what node does, its an "event-loop" its polling IO for completion(or progress) on a loop. So when a task does not complete(your loop) the event loop does not progress. To put it simply.
because timer needs to comeback and is waiting loop to finish to add to the queue, so although the timeout is in a separate thread, and may indeed finsihed the timer, but the "task" to set done = true is waiting on that infinite loop to finish
var open = false;
const EventEmitter = require("events");
const eventEmitter = new EventEmitter();
setTimeout(function () {
open = true;
eventEmitter.emit("open_var_changed");
}, 1000);
let wait_interval = setInterval(() => {
console.log("waiting");
}, 100);
eventEmitter.on("open_var_changed", () => {
clearInterval(wait_interval);
console.log("open var changed to ", open);
});
this exemple works and you can do setInterval and check if the open value changed inside it and it will work

CAPL code, putting delay in the code

I have a CAPL test code that controls the start of CAN signal sending. My goal is to delay the start of the sending process.
My idea to do this is via a setTimer() function in combination with isTimerActive().
In general my code looks the following:
main() {
CANstart();
function_2();
function_3();
}
CANstart() {
SetTimer(Delay, 5000); //Timer initialization, set to be 5000ms
while (isTimerActive()==1) {
// this while loop avoids that the code is proceding while the settimer exception is being called and executed
}
StartCANTransmitting(); // After this function, jump back to main and proceed with function_2
}
on timer Delay {
// Do nothing, just wait
}
The program code above lead to being stuck at that point, CANoe does not response and the only way I can end the simulation is via taskmanager.
Further examination from my side lead to the conclusion that the timer need more time to process and is not executed at all.
Without the isTimerActive() function, the program code does not wait for the timer to finish and there is no delay at all. Seems like the code runs through without waiting for the exception.
Seems like CAPL handles loops very bad.
I check out stackoverflow and the following forum posts talk about very similar issues that I have without offering any working solutions:
CAPL Programming usage of Timer as a delay
Are timers running, while loops are active?
Delay function in CAPL apart from testwaitfortimeout()
I see a great deal of issues with your code. It actually does not feel like code at all, but more like pseudo-code. Does it compile on your CAPL browser?
main() {
CANstart();
function_2();
function_3();
}
If this is a function declaration, then it is missing both a type and a return value. In addition, when are you expecting main() to be executed?
The same applies to:
CANstart()
Let us make a step back. You need to delay the beginning of can transmitting. If you need to do so because you have code outside CANalyzer/CANoe running, then I suggest you call the application via command line (refer to the guide for more help).
If you need, however, to have blocks running in your setup configuration, like a Replay block, a Loggin block or whatever, I suggest you to do the following:
variables {
/* define your variables here. You need to define all messages you want to send and respective signal values if not defaulted */
message 0x12345678 msg1; // refer to CAPL guide on how to define message type variables
msTimer delay;
msTimer msgClock1;
}
on start {
/* when you hit the start measurements button (default F9) */
setTimer(delay, 5000); // also note your syntax is wrong in the example
}
on timer delay {
/* when timer expires, start sending messages */
output(msg1); // send your message
setTimer(msgClock1,250); // set timer for cyclic message sending
}
on timer msgClock1 {
/* this mimicks the behaviour of a IG block */
setTimer(msgClock1,250); // keep sending message
output(msg1)
}
Does this achieve your goal? Please feel free to ask for more details.
It appears that you have a problem with the while (isTimerActive()==1) { statement.
CAPL function int isTimerActive requires the parameters timer or mstimer variable and return values
1, if the timer is active otherwise 0.
You can check if the timer is active and the time to elapse in the following way.
timer t;
write("Active? %d", isTimerActive(t)); // writes 0
setTimer(t, 5);
write("Active? %d", isTimerActive(t)); // writes 1
write("Time to elapse: %d",timeToElapse(t)); // Writes 5
try adding the parameter timer at while (isTimerActive(Delay)==1) {
I would not suggest using the while statement instead you can use the timer directly to call the function StartCANTransmitting() and your Main() should be MainTest()
void MainTest()
{
TestModuleTitle("Sample Tests");
TestModuleDescription("This test module calls some test cases to demonstrate ");
CANstart();
if (TestGetVerdictLastTestCase() == 1)
Write("CANstart failed.");
else
Write("CANstart passed.");
}
testcase CANstart() {
// add info block to test case in report
TestReportAddMiscInfoBlock("Used Test Parameters");
TestReportAddMiscInfo("Max. voltage", "19.5 V");
TestReportAddMiscInfo("Max. current", "560 mA");
TestReportAddMiscInfo("StartCANTransmitting");
SetTimer(Delay, 5000); //Timer initialization, set to be 5000ms
}
on timer Delay {
StartCANTransmitting();
}

Sleeping in action script 2 using getTimer() method

How can I correctly perform something like sleep function using getTimer()? I need to do an action every 15 seconds. The code below doesn't work. I compile it with mtasc compiler on Linux.
class Tuto
{
static var lastMsg = 0;
static var msgInt = 15000;
static function main(mc)
{
if(getTimer() > lastMsg + msgInt)
{
trace("something");
lastMsg = getTimer();
}
}
}
The main instruction will be executed just once. You have to build some kind of loop or rely on the tick events sent by the player to execute your code continuously.
The basic options are:
while (true) { doSomething() }
this will execute forever, but remember that the flashplayer is single threaded so while that runs everything else will be frozen, UI and user inputs included. this is only "good" if you are building some heavy-processing tool that has no need of interacting with the user.
setInterval(doSomething, 15000)
this creates an interval that will call your function every X milliseconds. This is the simplest option and probably what you're looking for.
addEventListener(Event.ENTER_FRAME, doSomething)
this registers a listener for the ENTER_FRAME event of the Flash Player, which will be dispatched 30 times per second (by default). Inside that function you can check the current time with getTimer() and decide if it's time to execute your logic.

Meteor.setTimeout is not causing delay

I am creating my first Meteor app with the Spheron smart package. I can control he sphero ok and change it's colors but I'm trying to create a delay in between the color change.
Here is my code:
function makePrettyLights(sphero,color){
var colors = [];
colors['red'] = '0xB36305';
colors['green'] = '0xE32017';
colors['blue'] = '0xFFD300';
console.log(color);
var spheroPort = '/dev/tty.Sphero-OBB-RN-SPP';
var timer = 2000;
Meteor.setTimeout(function(){
sphero.on('open', function() {
sphero.setRGB(colors[lineName], false);
});
sphero.open(spheroPort);
},2000);
}
This function is being called from in a loop. I havent included the loop at it involves me parsing some xml and other bits but it works.
if (Meteor.isServer) {
/**** Loop Code Here ****/
makePrettyLights(sphero,color)
/****End Loop Code ****/
}
I have also tried setting the timeout wrapper around the function where it is called instead of inside it.
But basically they all run at the end of my code at the same time.
I20140806-09:49:35.946(1)? set color
I20140806-09:49:35.946(1)? set color
I20140806-09:49:35.946(1)? set color
The problem is most probably in your loop. I assume it's a pretty standard for loop, in which case such behavior is expected. When you call:
for(var i=0; i<5; ++i) {
setTimeout(someFunction, 2000);
}
the setTimeout method will be called 5 times in a row in a single moment. This means that someFunction will be called 5 times in a row after 2000 miliseconds.
Your sphero variable is scoped outside the timeout. So every time a connection is opened the previously added callbacks will fire at the same time since you're just adding on to globally scoped sphero variable.
Try defining sphero (not currently shown with your code above) inside the Meteor.setTimeout callback instead of outside of it.

How to forcibly keep a Node.js process from terminating?

TL;DR
What is the best way to forcibly keep a Node.js process running, i.e., keep its event loop from running empty and hence keeping the process from terminating? The best solution I could come up with was this:
const SOME_HUGE_INTERVAL = 1 << 30;
setInterval(() => {}, SOME_HUGE_INTERVAL);
Which will keep an interval running without causing too much disturbance if you keep the interval period long enough.
Is there a better way to do it?
Long version of the question
I have a Node.js script using Edge.js to register a callback function so that it can be called from inside a DLL in .NET. This function will be called 1 time per second, sending a simple sequence number that should be printed to the console.
The Edge.js part is fine, everything is working. My only problem is that my Node.js process executes its script and after that it runs out of events to process. With its event loop empty, it just terminates, ignoring the fact that it should've kept running to be able to receive callbacks from the DLL.
My Node.js script:
var
edge = require('edge');
var foo = edge.func({
assemblyFile: 'cs.dll',
typeName: 'cs.MyClass',
methodName: 'Foo'
});
// The callback function that will be called from C# code:
function callback(sequence) {
console.info('Sequence:', sequence);
}
// Register for a callback:
foo({ callback: callback }, true);
// My hack to keep the process alive:
setInterval(function() {}, 60000);
My C# code (the DLL):
public class MyClass
{
Func<object, Task<object>> Callback;
void Bar()
{
int sequence = 1;
while (true)
{
Callback(sequence++);
Thread.Sleep(1000);
}
}
public async Task<object> Foo(dynamic input)
{
// Receives the callback function that will be used:
Callback = (Func<object, Task<object>>)input.callback;
// Starts a new thread that will call back periodically:
(new Thread(Bar)).Start();
return new object { };
}
}
The only solution I could come up with was to register a timer with a long interval to call an empty function just to keep the scheduler busy and avoid getting the event loop empty so that the process keeps running forever.
Is there any way to do this better than I did? I.e., keep the process running without having to use this kind of "hack"?
The simplest, least intrusive solution
I honestly think my approach is the least intrusive one:
setInterval(() => {}, 1 << 30);
This will set a harmless interval that will fire approximately once every 12 days, effectively doing nothing, but keeping the process running.
Originally, my solution used Number.POSITIVE_INFINITY as the period, so the timer would actually never fire, but this behavior was recently changed by the API and now it doesn't accept anything greater than 2147483647 (i.e., 2 ** 31 - 1). See docs here and here.
Comments on other solutions
For reference, here are the other two answers given so far:
Joe's (deleted since then, but perfectly valid):
require('net').createServer().listen();
Will create a "bogus listener", as he called it. A minor downside is that we'd allocate a port just for that.
Jacob's:
process.stdin.resume();
Or the equivalent:
process.stdin.on("data", () => {});
Puts stdin into "old" mode, a deprecated feature that is still present in Node.js for compatibility with scripts written prior to Node.js v0.10 (reference).
I'd advise against it. Not only it's deprecated, it also unnecessarily messes with stdin.
Use "old" Streams mode to listen for a standard input that will never come:
// Start reading from stdin so we don't exit.
process.stdin.resume();
Here is IFFE based on the accepted answer:
(function keepProcessRunning() {
setTimeout(keepProcessRunning, 1 << 30);
})();
and here is conditional exit:
let flag = true;
(function keepProcessRunning() {
setTimeout(() => flag && keepProcessRunning(), 1000);
})();
You could use a setTimeout(function() {""},1000000000000000000); command to keep your script alive without overload.
spin up a nice repl, node would do the same if it didn't receive an exit code anyway:
import("repl").then(repl=>
repl.start({prompt:"\x1b[31m"+process.versions.node+": \x1b[0m"}));
I'll throw another hack into the mix. Here's how to do it with Promise:
new Promise(_ => null);
Throw that at the bottom of your .js file and it should run forever.

Resources