1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Updated Design: Node Messaging API (markdown)

Nick O'Leary 2017-03-09 16:43:07 +00:00
parent d2cb10e3f1
commit b9fe4741e4

@ -25,9 +25,61 @@ This simple system has a few limitations that we want to address:
This design note explores how this mechanism could be updated to satisfy these limitations.
The original draft of this node set out three options. Through the process of writing the options, I've chosen my preferred approach. I have left the other two options at the bottom of the note for reference.
---
### Option 1: Add a `node.complete` function - v1
### Pass in scoped `send` and `done` functions
If the event handler is registered with three arguments, the runtime will pass in functions that should be used to send or mark the msg as handled.
```
this.on('input', function(msg, send, done) {
// do something with 'msg'
if (!err) {
// send can be called as many time as needed (including not at all)
send(msg);
send(msg);
send(msg);
// Once complete, done is called
done();
} else {
// If an error occurs, call done providing the error.
done(err);
}
});
```
The `done` function takes two arguments: `done(error, message)`.
Usage | Meaning
-----------------|------------
`done()` | success. Any `success` node targeting this node will be triggered using the original msg
`done(null,msg)` | success. Any `success` node targeting this node will be triggered using the provided msg
`done(err)` | failure. Any `catch` node targeting this node will be triggered using the original msg
`done(err,msg)` | failure. Any `catch` node targeting this node will be triggered using the provided msg
- a new node will be added to compliment the `Catch` node that can be used to trigger a flow when a node finished processing a message. It's current name is the `Success` node - but it needs to change.
- this feels the most 'node.js-like'. The presence of a `done` callback is familiar to many apis.
- the functions can be scoped to the received message so the node does not need to provide the message back
- the runtime can tell if the handler expects these extra arguments or not, so can adapt its behaviour to match
- `node.send` should not be used in this case as its use will stop the runtime from being able to correlate message received with message sent. We _probably_ won't enforce this - tbd.
- `node.error` can still be used as a handler may need to log multiple errors before completing.
**What if `done` is never called?** - If a handler is registered that takes the `send` and `done` arguments, the runtime requires it to eventually call `done` for each message received. Not calling `done` should be considered a bug with the node implementation. The question is what happens if it doesn't get called.
The easy option is to do nothing. But that will allow buggy implementations to exist, so we should avoid this option.
The right approach will be to timeout the function. A timeout would be considered an error and logged as such. The runtime will set a default timeout of **30 seconds (TBD)**. A node will be able to set its own timeout value by setting a property on itself (`this.TIMEOUT = 60000` (TBD)). This also allows a future extension where a user can set custom timeout values per node in the editor (but this proposal does not extend that far today).
**What if a node that has been timed out then wakes up and calls `done` or `send`?** - should the runtime then block a timed out node from calling `send` or `done` (at least... prevent any messages it then sends from being passed on? I can see use cases for both allowing the message to pass on and for stopping it. Does this need to be a per-node policy? Or a choice made in the editor? Hmmm.
---
### Alternative Option 1: Add a `node.complete` function - v1
The first proposal is to add a new function to the Node object that can be called when a node has finished handling a message.
@ -46,7 +98,7 @@ this.on('input', function(msg) {
- this relies on the user passing msg through - something that could be a source of programming error.
- it would need clear semantics over when it was called and how it relates to `node.error`.
### Option 2: Add a `node.complete` function - v2
### Alternative Option 2: Add a `node.complete` function - v2
The second proposal is similar to the first, but the `complete` function can also be used to indicate a failure:
@ -68,31 +120,3 @@ this.on('input', function(msg) {
- this relies on the user passing msg through - something that could be a source of programming error.
- it would need clear semantics over when it was called and how it relates to `node.error`.
### Option 3: Pass in scoped `send` and `done` functions
If the event handler is registered with three arguments, the runtime will pass in functions that should be used to send or mark the msg as handled.
```
this.on('input', function(msg, send, done) {
// do something with 'msg'
if (!err) {
send(msg);
send(msg);
send(msg);
done(null, msg);
} else {
// Log the error, but don't provide the msg obj here
node.error(error1);
node.error(error2);
node.error(error3);
done(err, msg);
}
});
```
- this feels the most 'node.js-like'. The presence of a `done` callback is familiar to many apis. Calling it
without an argument is considered success, with an argument is considered failure.
- the functions can be scoped to the received message so the node does not need to provide the message back
- the runtime can tell if the handler expects these extra arguments or not, so can adapt its behaviour to match
- need to consider whether the node should still be allowed to use `node.send` and `node.error` directly. It would be possible to disable either of these functions if we see this new style message handler registered. There is certainly a case to support `node.error` regardless - a single message can legitimately trigger multiple errors.