Stop infinity loop in function node using payload

Hello all.
This is my first post over here.

I had to write a simple simulation routine, which takes data from payload once, then spool the loop to generate a series of result values.
After each iteration of that loop the node sends partial results using node.send() method.
The loop is time-based: let's each iteration starts after a second.

How should I write such code to:

  1. be able to set up time period between iterations?
  2. be able to break the loop by sending 'stop' in input payload
  3. be efficient: not block whole NR (I suppose active waiting could do that)

So far I did use the method shown in code below. Everything works but stopping the loop. Simply sending another payload to the input doesn't affect previously running loop at all.
AFAK it runs the new instance of the whole code ( which is proven by sending two data payloads - it starts two separate simulations)

Is it possible to achieve that?

Thanks in advance

var c = 0;
var t;
var timer_is_on = 0;
var steps = 320; //48*2;
var inc = 4; // mins
var ts = new Date(msg.payload.ts);
ts.setUTCHours(0,0,0,0); 


if (msg.payload == 'stop') {
    stopCount(); 
    node.done(); 
}

function simulate() {
    msg.payload.ts = ts.getTime();
    ts.setUTCMinutes(ts.getUTCMinutes()+inc);
    node.send(msg); 
}  


function timedCount() {
   
  simulate(c); 
   
  c = c + 1;
  t = setTimeout(timedCount, 500);

  if (c>=steps)  {
      stopCount();
  }
}

function startCount() {
  if (!timer_is_on) {
    timer_is_on = 1;
    timedCount();
  }
}

function stopCount() {
    node.error('stop');
  clearTimeout(t);
  timer_is_on = 0; 
}

startCount();

Look at setInterval() and setTimeout(). JavaScript Timing Events

Welcome to the community.

Each time a msg is sent to a function node, the node is started from nothing. So as it stands, what you are doing won't work.

The easiest approach is to use the inject node to send a msg every x seconds. If you need do have a process that is <1sec, you need to use a setInterval function in the function node. However, you have to save that interval function to a context variable and recover it each time the function node is called.

Here is a partial example from one of my own flows:

let i = context.get('rainbow') || undefined

if ( i === undefined && msg.payload === 'start' ) {
    node.warn('starting')
    
   // ... do stuff here ...
    
    context.set('rainbow', i)
}

if ( i && msg.payload === 'stop' ) {
    node.warn('stopping')
    clearInterval(i)
    context.set('rainbow', undefined)
}

The context variable "rainbow" is used to store the interval function so that only 1 is used no matter how many msg's are sent to the function node. I send a msg.payload of "start" to start the timeout and "stop" to stop it.

As you can see in the code those functions are being used already.
The point is, that I found to way to stop the loop being already executed by sending another payload to the same node. I need behaviour similar to delay node, where it is possible to control its behaviour initiated by previous message by sending another message.

Thank you.
I forgot I can use context variables to pass information between calls. So easy idea.
Thank you so much

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.