Making flows asynchronous by default

On the other hand,,,how many, many times have we read that we should use the existing msg object and NOT create new ones?

That is partly correct. You should use the same message, otherwise following nodes might misbehave due to missing properties (like the HTTP request-response nodes).

However, if you try to send the same message multiple times, as you do, you have to create a copy using RED.util.cloneMessage(msg). This will become even more important with the 1.0 release.

EDIT: Your new approach by doing node.send({ payload:"foo" }); is also valid, of course. But you have to be sure that following nodes won't require any of the previous message properties.

4 Likes

Here's some information that IMHO should be included in the final documentation.

This blog note https://nodered.org/blog/2019/08/16/going-async talks about "branching" flows. But it should also talk about nodes issuing multiple messages because they have multiple outputs. Those nodes/msgs will also be affected by the new asynchronous behavior !

I know it's probably implied but although I had carefully read the note, it didn't occur to me until I encountered the case....

The triple-output function node contains the following code:

return [
    {payload: "message 1"},
    {payload: "message 2"},
    {payload: "message 3"},
];

the other function nodes simply return the msg they've received.

As you can see with NR 1.00, the messages will arrive "unordered" because they're "delayed" by the intermediary function nodes ... I have not tested this with the switch nodes or other nodes with multiple outputs but I suppose it's the same .... In previous versions, branch 1 would run first, branch 2 second, etc. and any intermediary node wouldn't have an impact.

This might have implications for some of us that have flows that relies on the previous synchronous behavior. If your flow expected branch 1 to complete before treating branch 2 and then branch 3 (even though all 3 msgs were sent at the same time), then your flow will not work anymore. This was a simple way to sequence messages and I'm sure I'm not the only one that used this ...

The main problem I see for now is that until we have more API to handle asynchronous messages (and particularly their "completion"), we have no other choice than to rely on "delay" nodes, "complete" nodes or another mechanism to bring back some kind of synchronous behavior.

Note: this example is very simple one, in fact I have some custom nodes that rely on node.send(array_of_msg) that are impacted as well.

You can use the setting

runtimeSyncDelivery: true

to keep the old behaviour until your flows are converted to the new method

2 Likes

That's a possible workaround but as mentioned by @knolleary this is to be considered as instantly deprecated.

Until we have more effective ways to deal with asynchronous messages, I think it's best to rethink the flows and find ways (even inappropriate ones like using "delays") to be compatible with the new async behavior ...

Yes

I use that technique already. I think its valid, if message rate is slow enough, but probably better to use flow/global.context semaphore flags

Or maybe worth trying out do-red for when one flow has to complete before another flow starts

If you care about the order of the Branches then you don't branch your flows. Create one flow that doesn't branch. That has always been the message we've given when asked.

3 Likes

PS the reply was for @tilleul

I don't think this is a good approach, better then to use a state-mechanism type of approach. Otherwise, slowing down a flow on purpose? How do you then know that the delay "is enough" also for later flow changes? You could end up having to check your flow for such things when you make updates in the future, something I would not enjoy very much

I would follow @knolleary advice as much as possible, re-think the logic, eventually use a state mechanism if there are such dependencies

A good solution may be to run the nodes in series rather than in parallel. Alternatively use a Join node to merge them back together.

1 Like

That's why I'm saying it's inappropriate :wink: but it could help for a while until we have more "tools" available ...

My initial post was not a complaint or anything, just a warning to other users who might have the same problem ...
... and also, the example given is very simple to illustrate the "problem" ... my "real" process uses NR only to give our users the ability to customise slightly an otherwise fixed behavior. A lot of stuff is happening "under the hood", invisible to the user who has access to NR editor ... but "under the hood" it's really using a lot of NR mechanisms, like node.send() with multiple outputs (arrays of msgs) ...
... oh and as a last word, my NR app is now fixed (until I find a new async related-problem) so many thanks to everybody who wants to help me but it's not really needed ... though others might benefit from the advice ....

2 Likes

Sorry I'am late on this. Have been away from the forum with my head in panels =) I think there is certainly an expectation in the industrial automation world for sync. I learned programming in C++ and Java and I was confused at first about how ladder scans from the top down and how conditions can screw your program up (ie latching and one shots). It would be nice if you could force NR do one or the other depending on the application. I do heat process which is SLOW, for what I deal with I think I could do control w/o a PLC entirely and synchronous execution doesn't matter that much - just needs to be in the ballpark-. My buddy who does packaging on assembly lines does crazy shit where the conveyors are moving insanely fast with photo eyes and one little mistake the whole line clogs up and crap flies everywhere. I don't think he could use NR for really anything except maybe logging. So yea the expectation of synchronous execution could get you into trouble. I guess for now test the hell out of it, depends on tolerance of your application.

Hi,

I had a problem with idea of flow branches are totaly indepent. Indeed, i use a switch node for check that data it's different from previous value (in a split / join for read array line by line).

Each branches modify payload and merge like this

This flow it's easily understandable by people who aren't developpers, but since it's async, line in output aren't in same orders than input. In this example we can add sort node before join, but in more complexe example it's not always possible.

They are maybe a semaphore logic node ?

Jérémy

Do you mean that when you feed a sequence of messages in the front, each one of which goes down one (and only one) of the two branches and then on to the Join node, that they can arrive at the Join in the wrong order?
If you look at the animations in the first post I don't think that should happen. However it could happen in more complex flows. The best solution is keep the flow serial for examples like this, avoiding the branch. Otherwise, as you suggest, you could use node-red-contrib-semaphore, which I have used successfully.

You beat me to it Colin.

The key is to make it serial. Many times I see questions on here the user is branching off and is curious as to why messages are out of order or don't arrive at the same time.

My advice (where appropriate) is almost always the same, keep adding to the msg and carry it along to the end.

This has the added benefit of the last debug node has pretty much everything it accumulated on its travels (in my head I think of it like a snowball!) - you get see all the stuff in one one place.

Not to much unlike how a plc predictably updates it's refresh area at the end of a scan.

While such a node exists, it really isn't the flow way of doing things. each branch is independent and there are no guarantees of synchronicity or timing. This is true of a flowchart as well so the concept should not be completely unfamiliar.

Indeed, I would think for such cases, one of the Finite State Machine nodes would likely be a better choice.

BTW, I don't think a sort node would help in your example since, in general, you could never assume that both tracks will be followed in any given time period. Indeed, "joining" the outputs from the two nodes doesn't make logical sense since one would assume from the descriptive names that only one of the paths will be followed from an incoming msg.

While Node-RED is supurb for non-programmers, it does not remove the need for understanding the logic of a flow. Something that will indeed confuse beginners from time-to-time. The point being that it doesn't take a lot of knowledge to get going with Node-RED. However, NR is very powerful and flexible and so it is expected that you will need to gain greater understanding as your flows increase in complexity.

NR allows people to start experimenting very quickly. Like guitar playing, getting started is easy, mastery will take years! :grin: