Trigger Node - Original versus Latest then Send option

Node-RED version 2.2, Node version 16.14.0:

I was working on a semi-complex flow containing a Trigger Node. The flow was not producing the desired result. I narrowed it down to the Trigger node by creating a simple test flow (see attached JSON export below). My trigger node is setup to send the existing msg object, wait for a specified time, extend the delay if a new message arrives, and then send the latest msg object when the timer expires. The problem is, I get the same result no matter which option I select for "then send" (original or latest). That is, it returns the original message when "then send" is set to "latest".

Playing around with my simple test flow I determined it works as expected but ONLY when the "Handling" option is set to "all messages". My actual flow is using the "each" message.option. I was expecting the node to give me the latest message on a per topic basis because everything else (e.g. the actual timer itself) appears to work on a per topic basis when "Handling" is set to "each". My question: is this by design? If so, i can work around it...no big deal. However, I decided to ask the question just in case this is a bug. If this is intended behavior it would be nice if the help text in the sidebar mentions that. Thanks in advance!

Simple Test Flow:

[
    {
        "id": "4a3c07bce144963c",
        "type": "debug",
        "z": "d33fb4473770860c",
        "name": "Debug Latest",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 790,
        "y": 1120,
        "wires": []
    },
    {
        "id": "ddcabcc54e0ee621",
        "type": "trigger",
        "z": "d33fb4473770860c",
        "name": "Latest",
        "op1": "",
        "op2": "",
        "op1type": "pay",
        "op2type": "payl",
        "duration": "15",
        "extend": true,
        "overrideDelay": false,
        "units": "s",
        "reset": "",
        "bytopic": "all",
        "topic": "topic",
        "outputs": 1,
        "x": 590,
        "y": 1120,
        "wires": [
            [
                "4a3c07bce144963c"
            ]
        ]
    },
    {
        "id": "bc006f989eb24044",
        "type": "function",
        "z": "d33fb4473770860c",
        "name": "",
        "func": "if (msg.resetCount === true) {\n    context.set('count', 0);\n    return null;\n}\n\nlet count = context.get('count') || 0;\ncount = count + 1;\ncontext.set('count', count)\nmsg1 = {topic: msg.topic};\nmsg1.payload = count;\n\nreturn msg1;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 380,
        "y": 1180,
        "wires": [
            [
                "ddcabcc54e0ee621",
                "5df271dd70f0740e"
            ]
        ]
    },
    {
        "id": "40d6d2cd7bb142fd",
        "type": "inject",
        "z": "d33fb4473770860c",
        "name": "",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "TEST",
        "x": 150,
        "y": 1180,
        "wires": [
            [
                "bc006f989eb24044"
            ]
        ]
    },
    {
        "id": "5df271dd70f0740e",
        "type": "trigger",
        "z": "d33fb4473770860c",
        "name": "Original",
        "op1": "",
        "op2": "",
        "op1type": "pay",
        "op2type": "pay",
        "duration": "30",
        "extend": true,
        "overrideDelay": false,
        "units": "s",
        "reset": "",
        "bytopic": "topic",
        "topic": "topic",
        "outputs": 1,
        "x": 600,
        "y": 1240,
        "wires": [
            [
                "b71c2c3b0d2844bf"
            ]
        ]
    },
    {
        "id": "3f112364a5eeed2b",
        "type": "inject",
        "z": "d33fb4473770860c",
        "name": "Reset Counter",
        "props": [
            {
                "p": "resetCount",
                "v": "true",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 180,
        "y": 1100,
        "wires": [
            [
                "bc006f989eb24044"
            ]
        ]
    },
    {
        "id": "b71c2c3b0d2844bf",
        "type": "debug",
        "z": "d33fb4473770860c",
        "name": "Debug Original",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 1240,
        "wires": []
    }
]

Unfortunately the flow you posted is not importable...
There seems to be a glitch in some of the values:

image

@ralphwetzel I edited the post for @gil27255

It should work now.

@gil27255 ...

In order to make code readable and usable it is necessary to surround your code with three backticks (also known as a left quote or backquote ```)

``` 
   code goes here 
```

See this post for more details - How to share code or flow json

1 Like

Sorry about that....never tried to post a flow before, Try this:

[
    {
        "id": "4a3c07bce144963c",
        "type": "debug",
        "z": "d33fb4473770860c",
        "name": "Debug Latest",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 790,
        "y": 1120,
        "wires": []
    },
    {
        "id": "ddcabcc54e0ee621",
        "type": "trigger",
        "z": "d33fb4473770860c",
        "name": "Latest",
        "op1": "",
        "op2": "",
        "op1type": "pay",
        "op2type": "payl",
        "duration": "15",
        "extend": true,
        "overrideDelay": false,
        "units": "s",
        "reset": "",
        "bytopic": "topic",
        "topic": "topic",
        "outputs": 1,
        "x": 590,
        "y": 1120,
        "wires": [
            [
                "4a3c07bce144963c"
            ]
        ]
    },
    {
        "id": "bc006f989eb24044",
        "type": "function",
        "z": "d33fb4473770860c",
        "name": "",
        "func": "if (msg.resetCount === true) {\n    context.set('count', 0);\n    return null;\n}\n\nlet count = context.get('count') || 0;\ncount = count + 1;\ncontext.set('count', count)\nmsg1 = {topic: msg.topic};\nmsg1.payload = count;\n\nreturn msg1;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 380,
        "y": 1180,
        "wires": [
            [
                "ddcabcc54e0ee621",
                "5df271dd70f0740e"
            ]
        ]
    },
    {
        "id": "40d6d2cd7bb142fd",
        "type": "inject",
        "z": "d33fb4473770860c",
        "name": "",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "TEST",
        "x": 150,
        "y": 1180,
        "wires": [
            [
                "bc006f989eb24044"
            ]
        ]
    },
    {
        "id": "5df271dd70f0740e",
        "type": "trigger",
        "z": "d33fb4473770860c",
        "name": "Original",
        "op1": "",
        "op2": "",
        "op1type": "pay",
        "op2type": "pay",
        "duration": "30",
        "extend": true,
        "overrideDelay": false,
        "units": "s",
        "reset": "",
        "bytopic": "topic",
        "topic": "topic",
        "outputs": 1,
        "x": 600,
        "y": 1240,
        "wires": [
            [
                "b71c2c3b0d2844bf"
            ]
        ]
    },
    {
        "id": "3f112364a5eeed2b",
        "type": "inject",
        "z": "d33fb4473770860c",
        "name": "Reset Counter",
        "props": [
            {
                "p": "resetCount",
                "v": "true",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 180,
        "y": 1100,
        "wires": [
            [
                "bc006f989eb24044"
            ]
        ]
    },
    {
        "id": "b71c2c3b0d2844bf",
        "type": "debug",
        "z": "d33fb4473770860c",
        "name": "Debug Original",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 1240,
        "wires": []
    }
]

@Steve-Mcl ......you beat me to the punch....I did not realize you fixed it for me. Tx!!!

It is working ok for me, whether I set the top trigger to each or all it still shows the latest message after the timeout, or have I misinterpreted what you mean?

@Colin ....you are correct sir. I tested what I posted and it worked for me too. My original test flow was slightly more complicated so I made a last minute change to filter out the noise and better draw attention the issue. I guess my filter was strong enough to eliminate the issue altogether. I should have retested....apologies.

My actual flow has messages with multiple different topics and more complex objects. However, I was able to reproduce something similar to what I described by making a minor change to the previously posted test code. Specifically, I added a count property to the msg that stores the value of the count variable (i.e. msg1.count = count) and set the payload to a constant string value = 'payload'. This small change was enough to reproduce the issue. However this time, both paths return the latest message rather than the original message....which is odd. I also found it interesting that there is a delay between when the 1st and 2nd "then send" messages show up even though both paths return the latest object.

image

t[
    {
        "id": "4a3c07bce144963c",
        "type": "debug",
        "z": "d33fb4473770860c",
        "name": "Debug Latest",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 790,
        "y": 1120,
        "wires": []
    },
    {
        "id": "ddcabcc54e0ee621",
        "type": "trigger",
        "z": "d33fb4473770860c",
        "name": "Latest",
        "op1": "",
        "op2": "",
        "op1type": "pay",
        "op2type": "payl",
        "duration": "15",
        "extend": true,
        "overrideDelay": false,
        "units": "s",
        "reset": "",
        "bytopic": "topic",
        "topic": "topic",
        "outputs": 1,
        "x": 590,
        "y": 1120,
        "wires": [
            [
                "4a3c07bce144963c"
            ]
        ]
    },
    {
        "id": "bc006f989eb24044",
        "type": "function",
        "z": "d33fb4473770860c",
        "name": "",
        "func": "if (msg.resetCount === true) {\n    context.set('count', 0);\n    return null;\n}\n\nlet count = context.get('count') || 0;\ncount = count + 1;\ncontext.set('count', count)\nmsg1 = {topic: msg.topic};\nmsg1.payload = 'payload';\nmsg1.count = count;\n\nreturn msg1;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 380,
        "y": 1180,
        "wires": [
            [
                "ddcabcc54e0ee621",
                "5df271dd70f0740e"
            ]
        ]
    },
    {
        "id": "40d6d2cd7bb142fd",
        "type": "inject",
        "z": "d33fb4473770860c",
        "name": "",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "TEST",
        "x": 150,
        "y": 1180,
        "wires": [
            [
                "bc006f989eb24044"
            ]
        ]
    },
    {
        "id": "5df271dd70f0740e",
        "type": "trigger",
        "z": "d33fb4473770860c",
        "name": "Original",
        "op1": "",
        "op2": "",
        "op1type": "pay",
        "op2type": "pay",
        "duration": "30",
        "extend": true,
        "overrideDelay": false,
        "units": "s",
        "reset": "",
        "bytopic": "topic",
        "topic": "topic",
        "outputs": 1,
        "x": 600,
        "y": 1240,
        "wires": [
            [
                "b71c2c3b0d2844bf"
            ]
        ]
    },
    {
        "id": "3f112364a5eeed2b",
        "type": "inject",
        "z": "d33fb4473770860c",
        "name": "Reset Counter",
        "props": [
            {
                "p": "resetCount",
                "v": "true",
                "vt": "bool"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 180,
        "y": 1100,
        "wires": [
            [
                "bc006f989eb24044"
            ]
        ]
    },
    {
        "id": "b71c2c3b0d2844bf",
        "type": "debug",
        "z": "d33fb4473770860c",
        "name": "Debug Original",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 800,
        "y": 1240,
        "wires": []
    }
]ype or paste code here

The delay between the two messages is because you have different times in the triggers.
What is happening is that the payload is obeying the Initial/Last message setting, but the rest of the message is always the latest. The node does not remember the complete message, only the payload. You can see this if you set the payload to be the count also.
I seem to remember there was some discussion about this recently but I don't remember the outcome.

@knolleary can you tell us what is the current situation with this? The issue is that with the trigger node, with Then Send Original Message it appears to be only the payload that is from the original message, the rest of the message is from the latest.

I did some additional testing based on your last reply and everything aligns exactly with your explanation. I now have a much better understanding of how this node works with the parameters I am using. Your help is greatly appreciated as this behavior was not obvious to me from the available help text. Cheers!

1 Like

One workaround for a situation like this is to "promote" all msg objects up into msg.payload just before the trigger node and then demote them all back afterwards

Agreed. Moving all the properties under msg.payload is indeed a solution and one I considered. However, at least for the flow that I am currently working on, an even easier solution was simply to store a different, existing property inside payload as the previous assignment was somewhat arbitrary. With that said and now that I am aware of how this node works, I probably need to review the numerous watchdog timers I have on existing flows and some of those may require the approach you suggest. Appreciate the response!