Using 'setTimeout' and restart flow

Is an activ setTimeout still being executed after a flow restart at the specified time, or is the action 'lost'?

This is the part within a function node:

    var timerId = setTimeout(function () {
        var msg2 = {
            info: "Timer elapsed!",
            time: nexttime,
            payload: device,
            status: status
        };
        node.send([null, msg2]);  // at 'time' send command to device via output 1 (mqtt)
    }, elapsTime);

    msg.payload = (` Next ${nexttime}: ${device} ${status}`);

setTimeout also returns a parameter with Nodered (here timerId) with which the timeout can be canceled. But does this also work after the flow has been restarted, for example?

The timerID would be stored in a context variable and could be queried on restart. But does the clearTimeout(timerId) reach the operating system for execution?

What exactly do you mean by flow restart?

n Node-RED, the timer identifier (timerId) returned by setTimeout is only valid for the duration of the flow session. When the flow is restarted, all previously set timers are reset, and the timer identifiers become invalid. Therefore, while you can store the timerId in a context variable, calling clearTimeout(timerId) after a flow restart will not be effective because the timer associated with that identifier no longer exists.

If you need to manage timers across flow restarts, consider saving the timer state (like the remaining time until execution) in a persistent context variable or an external database. After restarting the flow, you can read this state and set up the timer again with a new timerId. This approach requires additional logging and state management, but it can ensure continuity in applications where this is critical.

If node-red is actually restarted (process ends/restarts) no timers will survive.

What you are facing is the perfect argument for use the tools provided - i.e. the delay or trigger node.

I would recommend you try to breakdown your work into logical blocks and as such create more "low-code" flows that utelise the delay/trigger nodes. In doing so you will not need to maintain timer handles or anything like that. PS, you can cancel a delay/timer node by sending a {reset:true} message to it.

To be clear and to add to what others have said, when Node-RED is restarted ALL context is lost except whatever has been persisted to a file and then reloaded (which happens automatically with persisted context variables - though watch out for the default save timeout, I think it only happens every 30s by default, it can be changed).

However, if you are meaning when a (re)deploy is done, then it depends on the TYPE of deploy. Some are more destructive than others.

Thank you for the clarifications and valuable suggestions. It seems that using built-in Node-RED nodes like delay and trigger nodes might be a more robust solution for managing timers, especially since they handle restarts more gracefully. This approach of breaking down work into logical blocks and utilizing these nodes will likely simplify flow management without the need to manually maintain timer handles.

Regarding the persistence of timers through restarts and deploys, your explanation helps a lot. I now understand that all timers and context are lost during a restart unless they have been saved and reloaded from a file (which happens automatically with persisted context variables - though watch out for the default save timeout, which is every 30 seconds by default but can be changed).

As for the behavior of setTimeout after a flow restart, it depends on the type of deploy. Some deploys are more destructive than others.

Thanks a lot guys.
This reminder is probably very important

It is probably cleaner to model the required timeout with

Can anyone point to comparable solutions?

What are you actually trying to achieve?

Are you actually wanting a timeout that actually survives a node-red restart?

Here is a brief project outline:
Throughout the day, (mqtt) jobs must be executed at daily recalculated times. A list holds these time-defined jobs and is processed one after the other. If a job is executed, the time span to the next job time is calculated and executed as a 'timeout'.

If a pending job is canceled (by the user), the next job in the list should be executed at the correct time. The old 'timeout' of the canceled job may no longer be executed.

On the other hand, an interruption/cancellation of the flow should not result in pending jobs being lost on restart.

Seems to me you need to persist the job queue not the time out.

There are a few ways to skin that cat but here are 2 off the top of my head.

  1. Job list entries are an array of { executionTime, jobDetails } & are stored in persistent context
  2. A regular inject set to run every 1m (or so) checks the list for any jobs to execute

Alternatively,

  1. Install node-red-contrib-cron-plus
  2. As jobs arrive, generate a new schedule and add it to a cron node (one which has "persist schedules" enabled)

the cron node has built in examples ctrl-i -> examples

1 Like

Since the list of jobs with their times is stable over the day, I would follow your first suggestion point 1. The list will be available as a file.
But in my opinion, the best way to process it is "from job to job".

In any case, the restart, or manual delete a pending job, the flow has to find the next job on the list using the the current time and compare with the list. So it calculates the time gap from 'now' to the next job time and finally executes the 'timeout' (delay or whatever).
I will try with the 'delay' node.

Another question about node 'delay'

Do I understand correctly that the delay node collects the messages and thus manages several messages? This means that a new incoming message will not overwrite/delete previous ones.

Only when the delay for a message has expired is it forwarded and removed from the delay stack.
Alternatively, the entire stack can be deleted with

Yeah.

As the built in help says "Delays each message passing through the node"

Emphasis on each


Correct


Yeah.

The built in help says better:

reset
If the received message has this property set to any value, all outstanding messages held by the node are cleared without being sent.


1 Like

Thanks @ Steve-Mcl

Working with node delay and using {reset:true} does the job! :+1:

Great help!

Could you use node-red-contrib-cron-plus? That allows loading of schedules dynamically.

1 Like

Interesting advice. But as far as I can see, it doesn't fit into the required user concept.

Probably I misunderstand the requirement. I thought that at some point you determine a schedule of tasks to be performed at given times during the day. Having determined that you could pass the schedule to the cron plus node and leave it to it.

1 Like

That would also be my suggestion.

As previously mentioned, the above settime task description only shows part of the project.

The user should see the daily list in order to be able to make various changes to the jobs during the day. These parts of the project are largely realized. I fear that much of this will have to be changed again with using node-red-contrib-cron-plus
Nevertheless, thanks for the suggestion :+1: