How to properly handle node.done()

I'm a little confused about node.done() function and how to use it after a for loop.

Let's suppose that I have 10 messages to send async. I must tell nodered the that it has finished due to timeout issues.

In my example, I should only call node.done() only after I every message went out, or after every node.send()?

2 Likes

Great question - one that myself, is interested to know.

on the basis of :

If a Function node does asynchronous work with a message, the runtime will not automatically know when it has finished handling the message.

To help it do so, the Function node should call node.done() at the appropriate time. This will allow the runtime to properly track messages through the system

I would say, your node is doing work with a message - it may send further messages multiple times using async methods - but doing so, its still "doing work".

so i would say after the last send - but I don't know the correct answer - someone here will know however

You should call done when you have finished everything that is required by the message that went in. The purpose of it is so that a user of that node can tell when it has completed acting on the message that was sent in.

2 Likes

:+1:

:+1:


Additionally, calling done() signifies that is it complete and ensures the complete node operates.

If an error (like a timeout or something occurs) you should call done with the error e.g. done(err) and then the catch node will permit users to "catch" your error.


~Ignore me - I assumed wrong~

NOTE: Because you are talking about the done function I assume you are talking about a custom node you are developing right?

Because it is not node.done but is infact just done (i.e. the callback passed into the 'on' 'input' handler) e.g...

See: JavaScript file : Node-RED

3 Likes

Hey Steve,
what is the difference with node.error(...)? Saw yesterday something in the documentation, but it was not really clear to me.

Can I summarize it like this?

  • Call done() when the input message processing has finished succesfully.
  • Call done(err) when the input message processing has finished unsuccesfully.
  • Call node.error(err) when there is an error during the processing but you don't return after the error, so you keep on processing the input message.

node.error requires a 2nd parameter (the msg) in order for the runtime and editor to know where the error originated. node.done does not (it already knows because done is passed into the VM).

Operationally, your summary is as good as any guide but to add my recollection of this...
node.done() is the "new" way of signalling an error and also a means of triggering the complete action but should really be used to indicate the overall operation is done (either cleanly or with an error).

2 Likes

As it happens, I have just noticed a bug with the JSDoc hint for node.done

image
image

The type docs are not correct!
node.error should permit an optional 'error' parameter

3 Likes

Just to make sure I understand this correctly...
Is this summary better?

  1. Call done() when the input message processing has finished succesfully, in case the input message is being processed asynchronously. When the message is being processed synchronously, Node-RED automatically detects when the processing is done.
  2. Call done(err) when the input message processing has finished unsuccesfully due to a blocking error, i.e. when the message processing is interrupted and stopped. This should be used instead of the old node.error(err, msg).
  3. Call node.error(err) when there is a non-blocking error during the processing, i.e. when the message processing is not interrupted after the error. After that processing we arrive back at 1 or 2.
3 Likes

Perhaps just to add to #1 that done is only needed when doing async message processing/sending. It isn't needed if you are only sending a msg at the end of the function node code.

2 Likes

I have edited my post to add your remark.
Or like you english speaking people always say: "Consider it done" :wink:

1 Like

Shouldn't that be "Consider it done()" :rofl:

2 Likes

Damn you Julian. Now you have even confused me even more :woozy_face:

  • When I process a message synchronously, then the Complete node is automatically triggered by Node-RED as soon as the synchronous code is completed.
  • When I process a message asynchronously, then I need to call done() myself in my code because otherwise Node-RED doesn't know when the asynchronous code is completed.

However to be able to start the asynchronous code, I first need to run some synchronous code:

  1. I need to validate the message
  2. Then I need to enrich the message with some extra data
  3. Then I call the asynchronous function --> in which I need to call done()
  4. I do some postprocessing (e.g. change the node status, ...)

So how does Node-RED see the difference between synchronous processing of a message, and asynchronous processing (which is also started in the middle of a bunch of synchronous code) :exploding_head:

Got a couple of days ago my first question ever about one of my nodes to make it compatible with the Complete node. So it would be very welcome to get some understanding in how this works, so I can refactor my node to accomplish this...

"Your mission, should you choose to accept it ..." :grin:

It doesn't need to and doesn't care. All done() does is terminate the processing - or rather tells Node-RED that the processing has ended. You don't need to do that when running a straight synchronous function because the function has already ended - there is nothing for Node-RED to do.

When talking about custom nodes, it doesn't hurt to call done, I do that in uibuilder. Mostly because the processing is somewhat hybrid and calling done is safer than not calling it. Just as not calling it in a synchronous mode, calling when similarly in such a mode does no harm, it just isn't necessary. I don't do it in simpler nodes because the processing of the msg is more linear. But I could, without any harm done.

  • For synchronous processing it doesn't matter whether you call done() at the end or not.:

    doPreProcessing();
    doProcessing();
    doPostProcessing();
    

    Is equal to:

    doPreProcessing();
    doProcessing();
    doPostProcessing();
    done();
    

    Because at the end of the synchronous processing, Node-RED knows automatically that the message processing has ended. That sounds logical

  • But for asynchronous processing:

    doPreProcessing();
    async doProcessing();
          --> Some time afterwards I need to call done() in the async function
    doPostProcessing();
    

    How does Node-RED know in this case that the message processing is NOT completed after the sychronous code is finished. Because doPreProcessing and doPostProcessing is simple synchronous code that is completed, but the real message processing is not completed. In this case the message processing is only completed when I call done() in the asynchronous function...

I think I am missing something very simple here...

Even for synchronous nodes I think that if the node can fail then it should call done, either showing success or failure. That allows the user to use Catch and Complete nodes, and know that one, and only one, of them will always be called.

I think that Julian meant not that NR automatically calls done() for you, just that there is no benefit to calling done() as messages pass straight through without delay.

1 Like

A fair point.

Let me add another question.
From the above discussion, I was also expecting that complete node should be called only when node.done() is emitted. However, it gets called from every single node.send(). Is that the correct behavior?

Sorry, but your question is quite ambiguous & I don't want to pass on bad info.

How many times in the function node is node.send called is this particular scenario? By that I mean if you trigger the function ONCE, how many times is node.send executed.

Are you actually calling node.done anywhere in this function node?

Can you share a minimal flow that demonstrates what you are seeing?

Sorry, after your message I've revisited my code and I confirm my mistake. Node complete is activated after node.done() call. thx and sorry