Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Messaging API support of core nodes #2402

Closed
wants to merge 25 commits into from

Conversation

k-toumura
Copy link
Contributor

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Proposed changes

Update core nodes to support new Node Messaging API.

Invocation of done() is deferred until the message has been removed from node's own message buffer/queue, or promise for the message processing has been fulfilled. For example, in delay node, done() is not called when a message has pushed to its queue. It is called after the message has been removed from the queue and sent to next nodes.

This PR is a preparation for Graceful Shutdown function, which needs to detect a completion of message processing.

Checklist

  • I have read the contribution guidelines
  • For non-bugfix PRs, I have discussed this change on the mailing list/slack team.
  • I have run grunt to verify the unit tests pass
  • I have added suitable unit tests to cover the new/changed functionality

@coveralls
Copy link

coveralls commented Dec 9, 2019

Coverage Status

Coverage increased (+0.04%) to 76.898% when pulling dfa8b75 on node-red-hitachi:dev-messaging-api into 103e212 on node-red:dev.

@knolleary
Copy link
Member

knolleary commented Dec 15, 2019

This is going to take quite some time to review given it changes so many core nodes.

In future, please consider breaking up items like this into multiple PRs that are easier to review in small steps.

@dceejay
Copy link
Member

dceejay commented Dec 15, 2019

My basic comment is that they all seem to just replace
this.send(msg); with send(msg); - where send is just the passed in function....
What happens for all the cases where the node isn't called with the correct signature...
eg the inject not actually creates it's own events (on a timeout) - and calls node.emit("input", {});
so will it now fail ???
I think they all need to be protected with something like
send = send || function() { node.send.apply(node,arguments) };

@k-toumura
Copy link
Contributor Author

This is going to take quite some time to review given it changes so many core nodes.
In future, please consider breaking up items like this into multiple PRs that are easier to review in small steps.

I agree. I'm sorry for causing you trouble.

What happens for all the cases where the node isn't called with the correct signature...
eg the inject not actually creates it's own events (on a timeout) - and calls node.emit("input", {});
so will it now fail ???
I think they all need to be protected with something like
send = send || function() { node.send.apply(node,arguments) };

From my understanding, we can safely assume that "input" callback is called with the correct signature, if we use a recent (1.0.0-beta3 or newer) runtime.
Node-RED runtime overrides native EventEmitter function in Node object. and node.emit("input", {}) calls Node.prototype.emit(), which overrides original EventEmitter.prototype.emit(). If the event is "input", this is just a wrapper for Node.prototoype._emitInput, and in that function it call a callback with proper signature.

@knolleary
Copy link
Member

knolleary commented Jan 17, 2020

To help me track progress through reviewing this PR, here's a checklist of all nodes it touches. I'll tick them off as I complete the review for each one.

  • Inject
  • Complete
  • Catch
  • Status
  • Link
  • Switch
  • Range
  • Template
  • Delay
  • Trigger
  • HTTP In
  • CSV
  • HTML
  • JSON
  • XML
  • YAML
  • Split
  • Join
  • Sort
  • Batch

@knolleary knolleary added this to the 1.1 milestone May 21, 2020
}, delayvar);
send(msg);
done();
}, delayvar, () => done("queue cleared"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think clearing the delay queue should be considered an error - which calling done(...) with an argument suggests. The queue is being cleared because the user has asked for that to happen.

(This applies to all the places you call done(...) with a string argument).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I'll remove an argument on done(...) when clearing the queue:

@@ -354,9 +360,12 @@ module.exports = function(RED) {
node.pending_count = pending_count;
var max_msgs = maxKeptMsgsCount(node);
if ((max_msgs > 0) && (pending_count > max_msgs)) {
Object.values(node.pending).forEach(group => {
group.msgs.forEach(mInfo => mInfo.done(RED._("join.too-many")));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you describe the logic here?

It looks like you now report the too-many error against every single message, rather than just the most recent one. Not sure if that's the right behaviour - the error log will be flooded. But I think we need to discuss it.

Copy link
Contributor Author

@k-toumura k-toumura Jun 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention is to notify which message is dropped due to buffer overflow.
But, yes, it will cause a flood of error messages.

Possible alternative is:
- call msgInfo.done() for queued messages,
- call done(RED._("join.too-many")) for emit an error message, and
- call node.trace("overflowed message ["+msgInfo.msg.id+"]") to log the flashed messages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same reply for the Batch node - I agree with point 1 and 2 - but not 3 (node.trace)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll also update for this as same as Batch node.

Object.values(node.pending).forEach(p_topic => {
p_topic.groups.forEach(group => {
group.msgs.forEach(msg => {
msg.done("premature close");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really an error? In other nodes the close function calls done() with no error even though the message will be discarded.

We really need to be consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to comment to this. I removed all occurrences of "premature close" argument in batch node on commit c23e71b.

Object.values(node.pending).forEach(p_topic => {
Object.values(p_topic.groups).forEach(group => {
group.msgs.forEach(msg => {
msg.done(RED._("batch.too-many"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with other comments - is it really the right thing to throw an error against every message in the group? That is going to cause a lot of noise in the log.

Copy link
Contributor Author

@k-toumura k-toumura Jun 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as commented in split.js(#2402 (comment)), I propose following behaviour:

  • call msgInfo.done() for queued messages,
  • call done(RED._("batch.too-many")) for emit an error message, and
  • call node.trace("overflowed message ["+msgInfo.msg.id+"]") to log the flashed messages

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with calling done() on the queued messages and done(RED._("batch.too-many")) on the message that caused the overflow.

I do not think we should node.trace all of the flushed messages as again, that could be a huge list and there's little the user would be able to do with that information from the trace log.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this. I'll replace done(RED._("batch.too-many")) with done(), and emit a single error on the message that caused the overflow.

@knolleary knolleary modified the milestones: 1.1, 1.2 Jun 29, 2020
@knolleary
Copy link
Member

We are almost there with this PR!

I think there is just the issue with the Batch/Join nodes on what they do when the max message count is reached. If we can get that sorted, then we can get this merged.

I do need to point out that the unit tests have not been updated for any of these changes. That is not ideal - especially as these are changes to such a core piece of functionality. I should have flagged that up when this PR was first raised.

Can you confirm you have manually tested all of the nodes covered by this PR for all the different paths that have been changed?

@k-toumura
Copy link
Contributor Author

Can you confirm you have manually tested all of the nodes covered by this PR for all the different paths that have been changed?

I'll make unit tests to check the logic. Could you give me some more time?

@k-toumura
Copy link
Contributor Author

At now, I'm looking delay nodes logic, and I found several oversights on calling done(), especially when a message is dropped.
I think that more comprehensive investigation is needed to avoid inconsistent behaviour.

Would you mind closing this PR?
And then, I'll create new PRs for each nodes (Delay, Trigger, CSV, Split, Join, Sort and Batch) with test cases (after 1.2 release)?

@knolleary
Copy link
Member

This is your PR - if you think closing it and opening smaller individual PRs is a better choice, then that's absolutely fine by me 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants