From b9fe4741e427346d9eb8774a38d59975357c1c7b Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 9 Mar 2017 16:43:07 +0000 Subject: [PATCH] Updated Design: Node Messaging API (markdown) --- Design:-Node-Messaging-API.md | 84 ++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/Design:-Node-Messaging-API.md b/Design:-Node-Messaging-API.md index 0f64eed..f22e813 100644 --- a/Design:-Node-Messaging-API.md +++ b/Design:-Node-Messaging-API.md @@ -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. \ No newline at end of file