# Option in "Link-Call" to discard response after timeout

**URL:** <https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127>\
**Category:** Feature Requests\
**Created:** [23 November 2022 16:11 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127 "2022-11-23T16:11:25Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [23 November 2022 16:11 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/1 "2022-11-23T16:11:25Z")

</div>

The addition of "Call-link" with "Return to Sender" has been a wonderful improvement in Node-red, and we use it everywhere.

Call-link includes a timeout parameter (which throws an exception). Yet once complete, it always returns a response, even after timeout.

Sometimes we may wish to discard the call-link response after timeout. For example, upon timeout of a DB query we may want to retry, and do not want to get old responses coming out of nowhere. Today we work around this using a design pattern which keeps track of active "Call-link" msg ids in a dynamic map. Upon catching a timeout, we remove the msg id, and thus can ignore the actual response which arrives later.

It would be nice to have this built in the Call-link node, allowing graceful timeout handling:

- Receive the response msg with a timeout indicator (not having to set up an additional catch node)
- Have an option to discard the response if it arrives after timeout

@knolleary , @Steve-Mcl , could this be considered in a future release?

Thanks

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [23 November 2022 16:30 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/2 "2022-11-23T16:30:23Z")

</div>

+1 for the option of discarding the response after a timeout, if it is feasible. It can be a pain if an error is thrown and later the response is received, for exactly the reasons indicated by @omrid.

---

<div class="post-metadata">

**Author:** ![drmibell](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/drmibell/32/8424_2.png) [@drmibell](https://discourse.nodered.org/u/drmibell)\
**Post date:** [23 November 2022 18:51 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/3 "2022-11-23T18:51:35Z")

</div>

> [@omrid](#):
>
> Have an option to discard the response if it arrives after timeout

I'm all in with the idea, if it can be implemented.

> [@omrid](#):
>
> a design pattern which keeps track of active "Call-link" msg ids in a dynamic map

I tried something similar in response to a related [discussion](https://discourse.nodered.org/t/nodes-that-erase-messages/70952). Unfortunately, the `_msgid` may not be stable, so the solution is not really universal.

```auto
[{"id":"729cecbb1ff5eba1","type":"link in","z":"a3965ef0f8fb91de","name":"link in 8","links":[],"x":35,"y":180,"wires":[["b146f8ae3bdafd2e","8db7717a79eeb402"]]},{"id":"b146f8ae3bdafd2e","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":140,"y":160,"wires":[]},{"id":"8db7717a79eeb402","type":"function","z":"a3965ef0f8fb91de","name":"save _linkSource","func":"let sources = flow.get('sources') || {}\nsources[msg._msgid] = msg._linkSource\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":180,"y":200,"wires":[["009387c16092339e"]]},{"id":"8ec8802515434fdb","type":"link out","z":"a3965ef0f8fb91de","name":"link out 6","mode":"return","links":[],"x":805,"y":200,"wires":[]},{"id":"234fe97354c12fa6","type":"function","z":"a3965ef0f8fb91de","name":"restore _linkSource","func":"sources = flow.get('sources')\nmsg._linkSource = sources[msg._msgid]\ndelete sources[msg._msgid]\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":630,"y":200,"wires":[["8ec8802515434fdb","2ef2916145d66652"]]},{"id":"b00e94908e30571b","type":"inject","z":"a3965ef0f8fb91de","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":120,"wires":[["2b05c2cafc2ad77e"]]},{"id":"2b05c2cafc2ad77e","type":"link call","z":"a3965ef0f8fb91de","name":"subroutine","links":["729cecbb1ff5eba1"],"linkType":"static","timeout":"30","x":390,"y":120,"wires":[["ecf2fe114687dfad"]]},{"id":"009387c16092339e","type":"change","z":"a3965ef0f8fb91de","name":"","rules":[{"t":"delete","p":"_linkSource","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":200,"wires":[["234fe97354c12fa6","83d7d07c358f046a"]]},{"id":"96ba466ab14b71b9","type":"link in","z":"a3965ef0f8fb91de","name":"link in 9","links":[],"x":65,"y":380,"wires":[["ebeaea69f592f596","5b53898dfdc45f4b"]]},{"id":"ebeaea69f592f596","type":"function","z":"a3965ef0f8fb91de","name":"save _linkSource","func":"let sources = flow.get('sources') || {}\nsources[msg._msgid] = msg._linkSource\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":210,"y":400,"wires":[["b9ed36c0820eaac4"]]},{"id":"b9ed36c0820eaac4","type":"change","z":"a3965ef0f8fb91de","name":"","rules":[{"t":"delete","p":"_linkSource","pt":"msg"},{"t":"delete","p":"_msgid","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":400,"wires":[["cf741eb2cc65f4a5","d1d8570eb5e27597"]]},{"id":"cf741eb2cc65f4a5","type":"function","z":"a3965ef0f8fb91de","name":"restore _linkSource","func":"sources = flow.get('sources')\nmsg._linkSource = sources[msg._msgid]\ndelete sources[msg._msgid]\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":400,"wires":[["e21c098c19d2c356","0ae61eddb0888810"]]},{"id":"e21c098c19d2c356","type":"link out","z":"a3965ef0f8fb91de","name":"link out 7","mode":"return","links":[],"x":785,"y":400,"wires":[]},{"id":"966a40766453fbeb","type":"inject","z":"a3965ef0f8fb91de","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":320,"wires":[["ace486d9ccbad7ca"]]},{"id":"ace486d9ccbad7ca","type":"link call","z":"a3965ef0f8fb91de","name":"subroutine","links":["96ba466ab14b71b9"],"linkType":"static","timeout":"30","x":390,"y":320,"wires":[["a345d76c98f723df"]]},{"id":"42740aa9100a7075","type":"comment","z":"a3965ef0f8fb91de","name":"this works","info":"","x":380,"y":80,"wires":[]},{"id":"7e9601e9b6ee89fd","type":"comment","z":"a3965ef0f8fb91de","name":"this doesn't","info":"","x":390,"y":280,"wires":[]},{"id":"83d7d07c358f046a","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":160,"wires":[]},{"id":"2ef2916145d66652","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":770,"y":240,"wires":[]},{"id":"ecf2fe114687dfad","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":530,"y":120,"wires":[]},{"id":"5b53898dfdc45f4b","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":170,"y":360,"wires":[]},{"id":"d1d8570eb5e27597","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":570,"y":360,"wires":[]},{"id":"0ae61eddb0888810","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":750,"y":440,"wires":[]},{"id":"a345d76c98f723df","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":530,"y":320,"wires":[]},{"id":"702c440c37cac94d","type":"catch","z":"a3965ef0f8fb91de","name":"","scope":null,"uncaught":false,"x":380,"y":480,"wires":[["3005e764b243a4c5"]]},{"id":"3005e764b243a4c5","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":510,"y":480,"wires":[]}]

```

Have you found a way around this? My example is not completely artificial, since for example, the core `split` node assigns all new id's to messages in the sequence it generates.

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [23 November 2022 19:41 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/4 "2022-11-23T19:41:32Z")

</div>

> [@omrid](#):
>
> It would be nice to have this built in the Call-link node, allowing graceful timeout handling:
> 
> - Receive the response msg with a timeout indicator (not having to set up an additional catch node)
> - Have an option to discard the response if it arrives after timeout

Does the node know how stale a returned message is?  
There could be an option "Send timed out messages to separate output" cf Trigger node.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [23 November 2022 20:03 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/5 "2022-11-23T20:03:40Z")

</div>

Hi all, it would be good if you could get involved in [this discussion](https://github.com/node-red/node-red/issues/3836).

I had proposed an option for error handling (where you could specify if it throws or packs the error into the msg or spits it out of a 2nd output) but it looks like it may not make the cut. The may still be a way to achieve the same result with a bit group thinking?

If there are suitable ideas and clear means of implementing things I will definitely consider them.

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [23 November 2022 21:21 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/6 "2022-11-23T21:21:23Z")

</div>

Thanks for that link Steve.

Off-topic:  
While I'm pretty sure I have no code to offer due to not having fluent Javascript, it would be valuable for my education if discussions like that contained the URL of the specific source code in question.  
It's often pretty intimidating browsing through GitHub.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [24 November 2022 09:21 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/7 "2022-11-24T09:21:57Z")

</div>

> [@Steve-Mcl](#):
>
> Hi all, it would be good if you could get involved in [this discussion](https://github.com/node-red/node-red/issues/3836).

Thanks Steve, let's continue the discussion there

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [24 November 2022 12:10 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/8 "2022-11-24T12:10:46Z")

</div>

> [@drmibell](#):
>
> I tried something similar in response to a related [discussion](https://discourse.nodered.org/t/nodes-that-erase-messages/70952). Unfortunately, the `_msgid` may not be stable, so the solution is not really universal.
> 
> ```auto
> [{"id":"729cecbb1ff5eba1","type":"link in","z":"a3965ef0f8fb91de","name":"link in 8","links":[],"x":35,"y":180,"wires":[["b146f8ae3bdafd2e","8db7717a79eeb402"]]},{"id":"b146f8ae3bdafd2e","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":140,"y":160,"wires":[]},{"id":"8db7717a79eeb402","type":"function","z":"a3965ef0f8fb91de","name":"save _linkSource","func":"let sources = flow.get('sources') || {}\nsources[msg._msgid] = msg._linkSource\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":180,"y":200,"wires":[["009387c16092339e"]]},{"id":"8ec8802515434fdb","type":"link out","z":"a3965ef0f8fb91de","name":"link out 6","mode":"return","links":[],"x":805,"y":200,"wires":[]},{"id":"234fe97354c12fa6","type":"function","z":"a3965ef0f8fb91de","name":"restore _linkSource","func":"sources = flow.get('sources')\nmsg._linkSource = sources[msg._msgid]\ndelete sources[msg._msgid]\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":630,"y":200,"wires":[["8ec8802515434fdb","2ef2916145d66652"]]},{"id":"b00e94908e30571b","type":"inject","z":"a3965ef0f8fb91de","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":120,"wires":[["2b05c2cafc2ad77e"]]},{"id":"2b05c2cafc2ad77e","type":"link call","z":"a3965ef0f8fb91de","name":"subroutine","links":["729cecbb1ff5eba1"],"linkType":"static","timeout":"30","x":390,"y":120,"wires":[["ecf2fe114687dfad"]]},{"id":"009387c16092339e","type":"change","z":"a3965ef0f8fb91de","name":"","rules":[{"t":"delete","p":"_linkSource","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":200,"wires":[["234fe97354c12fa6","83d7d07c358f046a"]]},{"id":"96ba466ab14b71b9","type":"link in","z":"a3965ef0f8fb91de","name":"link in 9","links":[],"x":65,"y":380,"wires":[["ebeaea69f592f596","5b53898dfdc45f4b"]]},{"id":"ebeaea69f592f596","type":"function","z":"a3965ef0f8fb91de","name":"save _linkSource","func":"let sources = flow.get('sources') || {}\nsources[msg._msgid] = msg._linkSource\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":210,"y":400,"wires":[["b9ed36c0820eaac4"]]},{"id":"b9ed36c0820eaac4","type":"change","z":"a3965ef0f8fb91de","name":"","rules":[{"t":"delete","p":"_linkSource","pt":"msg"},{"t":"delete","p":"_msgid","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":400,"wires":[["cf741eb2cc65f4a5","d1d8570eb5e27597"]]},{"id":"cf741eb2cc65f4a5","type":"function","z":"a3965ef0f8fb91de","name":"restore _linkSource","func":"sources = flow.get('sources')\nmsg._linkSource = sources[msg._msgid]\ndelete sources[msg._msgid]\nflow.set('sources',sources)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":400,"wires":[["e21c098c19d2c356","0ae61eddb0888810"]]},{"id":"e21c098c19d2c356","type":"link out","z":"a3965ef0f8fb91de","name":"link out 7","mode":"return","links":[],"x":785,"y":400,"wires":[]},{"id":"966a40766453fbeb","type":"inject","z":"a3965ef0f8fb91de","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":240,"y":320,"wires":[["ace486d9ccbad7ca"]]},{"id":"ace486d9ccbad7ca","type":"link call","z":"a3965ef0f8fb91de","name":"subroutine","links":["96ba466ab14b71b9"],"linkType":"static","timeout":"30","x":390,"y":320,"wires":[["a345d76c98f723df"]]},{"id":"42740aa9100a7075","type":"comment","z":"a3965ef0f8fb91de","name":"this works","info":"","x":380,"y":80,"wires":[]},{"id":"7e9601e9b6ee89fd","type":"comment","z":"a3965ef0f8fb91de","name":"this doesn't","info":"","x":390,"y":280,"wires":[]},{"id":"83d7d07c358f046a","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":160,"wires":[]},{"id":"2ef2916145d66652","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":770,"y":240,"wires":[]},{"id":"ecf2fe114687dfad","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":530,"y":120,"wires":[]},{"id":"5b53898dfdc45f4b","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":170,"y":360,"wires":[]},{"id":"d1d8570eb5e27597","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":570,"y":360,"wires":[]},{"id":"0ae61eddb0888810","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":750,"y":440,"wires":[]},{"id":"a345d76c98f723df","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":530,"y":320,"wires":[]},{"id":"702c440c37cac94d","type":"catch","z":"a3965ef0f8fb91de","name":"","scope":null,"uncaught":false,"x":380,"y":480,"wires":[["3005e764b243a4c5"]]},{"id":"3005e764b243a4c5","type":"debug","z":"a3965ef0f8fb91de","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":510,"y":480,"wires":[]}]
> 
> ```
> 
> Have you found a way around this? My example is not completely artificial, since for example, the core `split` node assigns all new id's to messages in the sequence it generates.

Thanks, I wasn't aware that \_msgid can change.  
You can always take the crude approach: add a timestamp to the msg before sending and compare it to the current time after it returns. if elapsed \> timeout then discard the response...

---

<div class="post-metadata">

**Author:** ![drmibell](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/drmibell/32/8424_2.png) [@drmibell](https://discourse.nodered.org/u/drmibell)\
**Post date:** [24 November 2022 16:47 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/9 "2022-11-24T16:47:34Z")

</div>

> [@omrid](#):
>
> add a timestamp to the msg before sending

Timestamp, yes; before sending, no.

A node in the subroutine that replaces the entire message will remove the timestamp. The only safe place to add a timestamp is at or just before the `link out` (return) node. The `link out` node could be [modified](https://github.com/node-red/node-red/issues/3836#issuecomment-1326667638) to do this. Otherwise, it would have to be done by the user in each subroutine.

---

<div class="post-metadata">

**Author:** ![omrid](https://avatars.discourse-cdn.com/v4/letter/o/77aa72/32.png) [@omrid](https://discourse.nodered.org/u/omrid)\
**Post date:** [24 November 2022 19:09 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/10 "2022-11-24T19:09:34Z")

</div>

> [@drmibell](#):
>
> Timestamp, yes; before sending, no.

I agree that the subroutine can remove the timestamp. But we need the "send" time in order to calculate the elapsed time, and Link-out is called _after_ the subroutine execution.  
Any idea how to calculate the elapsed time of the returning msg?

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [24 November 2022 20:32 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/11 "2022-11-24T20:32:29Z")

</div>

If you do something like this on the way in  
`msg.callTime = new Date().getTime()`  
That will add a millisecond timestamp to the message. Then when it comes back you can do  
`const msDiff = new Date().getTime() - msg.callTime`  
to give you the number of msec since it went in.

As @drmibell says, this will only work if you know that the nodes in the function do not lose the timestamp.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [23 January 2023 20:32 UTC](https://discourse.nodered.org/t/option-in-link-call-to-discard-response-after-timeout/71127/12 "2023-01-23T20:32:46Z")

</div>

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