Using done()/complete for debugging

Apologies if this has been mentioned before -- I am further behind than usual in reading the forum.

When possible, I avoid using global variables by attaching state information to each message. I recently built a flow with some complex logic that was not producing the messages I expected in certain cases. Using a complete node attached to a debug node, I could catch the messages as they passed through each function and change node in the flow and so was able to see each message as it was modified at various points and find the problem.

This flow gives the general idea:

[{"id":"618b1cf1.6df17c","type":"inject","z":"42e9cb90.fa9734","name":"inject","topic":"testing complete node","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":280,"wires":[["d6ea6b13.304ce8","ed2f9d3d.1bcef8"]]},{"id":"17d0a463.499f2c","type":"debug","z":"42e9cb90.fa9734","name":"function output","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":460,"y":260,"wires":[]},{"id":"fa3c7acb.30e618","type":"complete","z":"42e9cb90.fa9734","name":"","scope":["d6ea6b13.304ce8","ed2f9d3d.1bcef8"],"uncaught":false,"x":110,"y":360,"wires":[["1d04b428.2c777c"]]},{"id":"1d04b428.2c777c","type":"debug","z":"42e9cb90.fa9734","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":250,"y":360,"wires":[]},{"id":"d6ea6b13.304ce8","type":"change","z":"42e9cb90.fa9734","name":"","rules":[{"t":"set","p":"time","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"topic","tot":"msg"},{"t":"set","p":"foo","pt":"msg","to":"bar","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"change node output","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":300,"wires":[["c90a3799.49fe6"]]},{"id":"ed2f9d3d.1bcef8","type":"function","z":"42e9cb90.fa9734","name":"dummy function","func":"\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":260,"wires":[["17d0a463.499f2c"]]},{"id":"c90a3799.49fe6","type":"debug","z":"42e9cb90.fa9734","name":"change output","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":460,"y":300,"wires":[]}]

Before making a habit of this, I have a few questions:

  • Are there obvious down sides to using complete as a debugging tool in this way?
  • Is this behavior likely to change in the future?
  • Are there core nodes in addition to function, change, and debug that have implemented the done() function?
  • Would it be possible to add done() to other core nodes that transmit messages, like link, delay, and trigger, or that generate messages like inject, range and random?

Also, a couple of observations, illustrated by this flow:

[{"id":"c39db174.4b3d2","type":"complete","z":"f953caa6.ca00c","name":"","scope":["119e8e79.9e8012","171cafbb.ddde5","b1af9e2c.05fcc8"],"uncaught":false,"x":150,"y":240,"wires":[["8b9484f6.1ad448"]]},{"id":"5a2dbdb6.575ee4","type":"inject","z":"f953caa6.ca00c","name":"","topic":"empty function and debug","payload":"hello world","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":140,"wires":[["171cafbb.ddde5","119e8e79.9e8012","b1af9e2c.05fcc8"]]},{"id":"119e8e79.9e8012","type":"debug","z":"f953caa6.ca00c","name":"empty debug","active":false,"tosidebar":false,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":310,"y":140,"wires":[]},{"id":"171cafbb.ddde5","type":"function","z":"f953caa6.ca00c","name":"empty function","func":"","outputs":0,"noerr":0,"x":320,"y":100,"wires":[]},{"id":"8b9484f6.1ad448","type":"debug","z":"f953caa6.ca00c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":290,"y":240,"wires":[]},{"id":"b1af9e2c.05fcc8","type":"function","z":"f953caa6.ca00c","name":"function (no output)","func":"msg.payload = \"goodbye world\"\nmsg.topic = \"not empty function\"\nmsg.foo = \"bar\"","outputs":0,"noerr":0,"x":330,"y":180,"wires":[]}]
  • Both the function and debug nodes will send a message to the complete node even when they do nothing to the input message and have no output.
  • The function node can modify the message sent to the complete node even when it has no output.
  • If the complete node is allowed to catch output from its attached debug node, you get a loop. :wink:
1 Like

That's a nice use-case for the complete node! :slightly_smiling_face:

There's a pending pull request for the remaining core nodes. Messaging API support of core nodes by k-toumura · Pull Request #2402 · node-red/node-red · GitHub

The done() callback is only available in nodes that handle incoming messages to signal completion. So it wouldn't make much sense for nodes without an input port, like inject.

My question for this to work would be: Is the complete node notified before the message is passed to the next nodes? So the message that arrived in the debug bar is still the same and not yet modified by following nodes. Once it was sent to the editor it doesn't matter if it's been modified.
The runtime is another subject, the message could have been modified if it hasn't been cloned by the complete node (not sure if it does).

Thanks for your comments. I wish I could answer that question with certainty by examining the code, but the message-passing internals of NR are beyond my grasp. (I once tried to sort out something similar for the link node and failed miserably.) Experimentally, I have tried a number of flows, both linear and branching, that change the message at each step, and have not run into any problems. YMMV.

I couldn't get how the link nodes work either. Maybe there is some more special internal handling involved. I saw that it uses RED.events, so I guess it uses the runtime events to work.

Well, that behaviour would make sense in terms of life-cycle.

I tried digging through the code multiple times, but I ended up stopping that due to time constraints. At work I am just a one-man team who does the platform development. So most of the time goes there, our custom nodes and keeping up-to-date. And at home there are other commitments besides the personal projects (including Node-RED). :slightly_smiling_face:

Though I'd like to know more about the runtime, and to make contributions at some time, time is the limiting factor. :anguished:

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.