Arbitrary, multiple synchronous message function?

I'd like to trigger a flow x times where x == msg.payload. Due to the inherent asynchronicity, the following function fails:

var count = parseInt(msg.payload);
var i = 0;
while ( i < count) {
    i++;
    node.send(msg);
}

What am I missing?

How is it failing ?

It looks ok.

Are you certain payload contains a number? Add a debug to output of node before this node to check

One way it could be failing is that you are sending the same msg object multiple times. As JavaScript passes references around, if your flow modifies the msg object, you'll find all instances of the msg have modified.

The runtime clones messages to avoid this, but it also tried to avoid doing so if it can to avoid that overhead. Calling node.send multiple times like that stops the runtime from detecting it needs to do the clone thing.

You can do it yourself with:

node.send(RED.util.cloneMessage(msg));

(It might be RED.utils rather than RED.util - I can never remember and I'm not in a place to check)

When the payload is "4" I get four messages at once that don't get individually delayed by the following delay node.

The payload is a string and it get's converted to a number.

Thanks for the hint. I tried it but it doesn't help. The following delay node does not treat the input as individual messages.

[{"id":"acf0af31.be2a58","type":"function","z":"e4c2ecf.f5a731","name":"convert to int","func":"var count = parseInt(msg.payload);\nvar i = 0;\nwhile ( i < count) {\n i++;\n node.send(RED.util.cloneMessage(msg));\n}\n","outputs":1,"noerr":0,"x":280,"y":79,"wires":[["15a88035.337758"]]},{"id":"15a88035.337758","type":"delay","z":"e4c2ecf.f5a731","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":457,"y":80,"wires":[["bd8e4edf.3d7908"]]},{"id":"bd8e4edf.3d7908","type":"debug","z":"e4c2ecf.f5a731","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":629,"y":80,"wires":[]},{"id":"cadffe6.e1fe","type":"inject","z":"e4c2ecf.f5a731","name":"","topic":"","payload":"4","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":139,"y":79,"wires":[["acf0af31.be2a58"]]}]

You never mentioned a delay. And yes you will get 4 messages almost instantaneously.

If you use a delay with rate limit that may achieve what you want?

1 Like

For clarity, the delay (as a delay) will delay the messages for the specified time.

So if you have a delay of 5 sec, and send 4 messages at once, all 4 will be delayed for 5 secs then be sent pretty much 5 secs later (i.e. together 5secs after they arrived).

Rate limited

[{"id":"171282d9.1e907d","type":"function","z":"f57e8780.400c68","name":"convert to int","func":"var count = parseInt(msg.payload);\nvar i = 0;\nwhile ( i < count) {\n i++;\n node.send(RED.util.cloneMessage(msg));\n}\n","outputs":1,"noerr":0,"x":250,"y":80,"wires":[["f8c02a35.5ffc88"]]},{"id":"f8c02a35.5ffc88","type":"delay","z":"f57e8780.400c68","name":"","pauseType":"rate","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":437,"y":81,"wires":[["7875db2f.d59244"]]},{"id":"7875db2f.d59244","type":"debug","z":"f57e8780.400c68","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":599,"y":81,"wires":[]},{"id":"62a807c4.d8c528","type":"inject","z":"f57e8780.400c68","name":"","topic":"","payload":"4","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":109,"y":80,"wires":[["171282d9.1e907d"]]}]

Thanks, Steve. I feel embarrassed. Sorry for the post. Rate limiting, of course, leads to the wanted result.