Function node `timeout` option doesn't work?

Could anyone try out a flow on Node-RED a v3.1.x and / or V4.x version?
Please let me know your setup (OS (Win/Mac/Linux/Docker), Node-RED version, NodeJS version - they may be relevant)

TL;DR;
I am working on some code in core and want to be sure I respect the way a function times out but I cannot get it to do anything in the versions I have available to me at the moment. For me, in NR4.0.9/Node20, NR4.15/Node22 and even NR5.beta-2/Node22, I never get an error and the function continues regardless of the timeout.

Demo setup

  • first flow
    • function code awaits a 2 sec promise
    • warns "after awaiting 2 second sleep"
    • returns the msg
  • second flow
    • function code sets up a 2s setTimeout
    • after setTimeout resolves:
      • warns "after awaiting 2 second sleep"
      • sends msg

NOTE: both function nodes have a timeout setting of 1

At no time, did an error get thrown/caught

From the docs:

Handling a Timeout

Since Node-RED 3.1.0

It is possible to set a timeout for the function node on the Setup tab. This value, in seconds, is how long the runtime will allow the Function node to run for before raising an error. If set to 0, the default, no timeout is applied.

Flow to try out:

[{"id":"496cebb58846c847","type":"function","z":"d1c96cf8529a5579","name":"code awaits 2s sleep, function timeout setting is 1s","func":"await new Promise(r => setTimeout(r, 2000));\nnode.warn('after awaiting 2 second sleep')\nreturn msg\n","outputs":1,"timeout":"1","noerr":0,"initialize":"","finalize":"","libs":[],"x":810,"y":320,"wires":[["a80c0cdd911b28c6"]]},{"id":"52fa1c38a816ca85","type":"inject","z":"d1c96cf8529a5579","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":530,"y":320,"wires":[["496cebb58846c847"]]},{"id":"a80c0cdd911b28c6","type":"debug","z":"d1c96cf8529a5579","name":"await sleep version","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1210,"y":320,"wires":[]},{"id":"8e6f2e764efd5607","type":"complete","z":"d1c96cf8529a5579","name":"","scope":["496cebb58846c847","b94941589bf06811"],"uncaught":false,"x":990,"y":420,"wires":[["8629dcf10b4fc6c5"]]},{"id":"8629dcf10b4fc6c5","type":"debug","z":"d1c96cf8529a5579","name":"complete","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":1180,"y":420,"wires":[]},{"id":"b94941589bf06811","type":"function","z":"d1c96cf8529a5579","name":"code sends after setTimeout 2s, function timeout setting is 1s","func":"setTimeout(function() {\n    node.warn('setTimeout elapsed its 2 seconds setting')\n    node.send(msg)\n}, 2000);\n\n","outputs":1,"timeout":"1","noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":360,"wires":[["088e25f9ab8944ec"]]},{"id":"f3c7e4089915cb27","type":"inject","z":"d1c96cf8529a5579","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":530,"y":360,"wires":[["b94941589bf06811"]]},{"id":"088e25f9ab8944ec","type":"debug","z":"d1c96cf8529a5579","name":"setTimeout version","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1210,"y":360,"wires":[]},{"id":"747764c2367e43a4","type":"catch","z":"d1c96cf8529a5579","name":"","scope":["496cebb58846c847","b94941589bf06811"],"uncaught":false,"x":1010,"y":480,"wires":[["01d08d2a641105c4"]]},{"id":"01d08d2a641105c4","type":"debug","z":"d1c96cf8529a5579","name":"caught","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":1170.895751953125,"y":478.90277099609375,"wires":[]}]

Did something change and the docs are out of date?
Am i missing something obvious?

To be sure I wasnt hitting an edge case (where a single await longer than the functions timeout setting might be preventing a sigint in the vm to occur), i did another demo flow.

This demo awaits 6 x 1/2 second sleeps then returns the msg with the function nodes timeout option set for 2 seconds.

It still doesn't raise/throw an error & it continues to operate even returning the msg at the end.

[{"id":"080c8e68f4b86d38","type":"function","z":"cc414bda5adfb096","name":"code awaits 6x0.5s sleeps (total 3s), timeout setting is 2s","func":"const s = Date.now()\nawait new Promise(r => setTimeout(r, 500));\nnode.warn('sleep 1: after awaiting 1/2 second')\nawait new Promise(r => setTimeout(r, 500));\nnode.warn('sleep 2: after awaiting 1/2 second')\nawait new Promise(r => setTimeout(r, 500));\nnode.warn('sleep 3: after awaiting 1/2 second')\nawait new Promise(r => setTimeout(r, 500));\nnode.warn('sleep 4: after awaiting 1/2 second')\nawait new Promise(r => setTimeout(r, 500));\nnode.warn('sleep 5: after awaiting 1/2 second')\nawait new Promise(r => setTimeout(r, 500));\nnode.warn('sleep 6: after awaiting 1/2 second')\nconst tt = (Date.now() - s) / 1000\nnode.warn(`Returning the msg after ${tt} seconds`)\nreturn msg\n","outputs":1,"timeout":"2","noerr":0,"initialize":"","finalize":"","libs":[],"x":1190,"y":1640,"wires":[["1af89da0fd93838b"]]},{"id":"310ec135b930d62e","type":"inject","z":"cc414bda5adfb096","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":890,"y":1640,"wires":[["080c8e68f4b86d38"]]},{"id":"1af89da0fd93838b","type":"debug","z":"cc414bda5adfb096","name":"await sleep version","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1570,"y":1640,"wires":[]},{"id":"a293727d2df173f3","type":"complete","z":"cc414bda5adfb096","name":"","scope":["080c8e68f4b86d38"],"uncaught":false,"x":1410,"y":1700,"wires":[["ec1ce4f74ba079d3"]]},{"id":"ec1ce4f74ba079d3","type":"debug","z":"cc414bda5adfb096","name":"complete","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":1600,"y":1700,"wires":[]},{"id":"02d4a9baeec54cf6","type":"catch","z":"cc414bda5adfb096","name":"","scope":["080c8e68f4b86d38"],"uncaught":false,"x":1430,"y":1760,"wires":[["289cc0fb99c83b64"]]},{"id":"289cc0fb99c83b64","type":"debug","z":"cc414bda5adfb096","name":"caught","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":1590.895751953125,"y":1758.9027709960938,"wires":[]}]

Pretty certain this is gonna turn out to be egg on my face :smiley:

Seeing same timings as your images, on all test flows. No errors thrown.
nodejs 24
node-red 4.0.3
Android 11 running termux

1 Like

At least i am not going mad :wink:

Wondering if this is a regression after introduction in NR3.1 or if something has changed in v8 engine :thinking:

Anyone rocking Node-RED 3.1.x that could give this a go?

Same result on a NR 3.1 docker image
run --rm -it -p 1880:1880 nodered/node-red:3.1.0-18

Raised an issue: Function node `timeout` option doesn’t work? · Issue #5493 · node-red/node-red · GitHub

That happens when you write a node without the nrg framework!

update: works as designed

not a regression... so no need for nrg in this instance... (see issue for details)

1 Like

I was just selling myself hahaha

Nice try …

1 Like