Queue-gate (q-gate) question

Hi All,

Currently I'm facing an issue with queue-gate (AKA node-red-contrib-queue-gate, q-gate) and I hope the problem is already solved by some of you...

There is an example with picture at the page of the node: Retain Until Processed.

In that example the node start processing is manually initiating the processing of the items in the queue. I would like to have it automatically processed:

  • If there is only one item in the queue and(!) the previous item of the queue is already processed (see in the example: get next), then release the item from the queue (peek) and remove it from the queue (drop).
  • If there is more than one item in the queue, then there is nothing to do, since first item already triggered the processing (see above) and the remaining items will be processed by the get next part one by one.

Any cool ideas?


Can you describe what the purpose is please? I suspect there may be a better way of achieving what you want.

I created subflows for different Alexa (Amazon's Echo Dot) areas for audio (TTS) and text output, e.g. if there is a message to announce in the living room, then the Echo Dot device there will "tell" it by audio and if the TV in the living room is on, then the same message will be shown on the TV as text. There are also other area dependent processings in the subflows (e.g. in the office no audio output during appointments or phone calls, only text on the office's TV), but that is the main purpose of the subflow. Those subflows have one input and one output.

The text to announce will be generated case by case (by a kind of home AI), thus, the length of those announcements are very different.

If 2 announcements follow each other in a very short time (e.g. the main door was opened and closed) then it can happen that the second announcement interrupts the first one before the first one finishes. I thought to use a queue for the announcements and if one was processed to the end, then the next one (if there is any) can be started. For that purpose I wanted to use the q-gate, although the "gate" feature is not really relevant here, only the "queue".

You can use a Delay node in Rate Limit mode, along with the Flush feature for that. I can post an example flow if you can't work it out, but not till I am at my computer, in about 12 hours.

Sorry, but I doubt that the delay node will do that job, but let´s see your example for that...
Please remember, the delay node - even in rate limit - works time based and flush sends all messages currently in the queue. I need here an event based handling of the queue.

Have you read the sidebar help text on delay node (rate limit, flush)

If the received message has this property set to a numeric value then that many messages will be released immediately. If set to any other type (e.g. boolean), then all outstanding messages held by the node are sent immediately.

There are many examples of how to do this already posted on the forum Search results for 'rate limit flush example' - Node-RED Forum

My help text (although in German) talks only about all messages:

Wenn bei der empfangenen Nachricht diese Eigenschaft auf einen beliebigen Wert gesetzt ist, werden alle im Node gepufferten Nachrichten sofort gesendet.

I checked the English version and it is as yours. Thus, I switched now permanently to the English one. Thank you.

1 Like

That should be reported somewhere so it can be fixed. I am not sure where translation issues should be reported though.

This is how I do it.

[{"id":"b6630ded2db7d680","type":"inject","z":"bdd7be38.d3b55","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":480,"wires":[["ed63ee4225312b40"]]},{"id":"ed63ee4225312b40","type":"delay","z":"bdd7be38.d3b55","name":"Queue","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":310,"y":480,"wires":[["d4d479e614e82a49","7eb760e019b512dc"]]},{"id":"a82c03c3d34f683c","type":"delay","z":"bdd7be38.d3b55","name":"Some more stuff to do","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":800,"y":480,"wires":[["7c6253e5d34769ac","b23cea1074943d4d"]]},{"id":"2128a855234c1016","type":"link in","z":"bdd7be38.d3b55","name":"link in 1","links":["7c6253e5d34769ac"],"x":95,"y":560,"wires":[["3a9faf0a95b4a9bb"]]},{"id":"7c6253e5d34769ac","type":"link out","z":"bdd7be38.d3b55","name":"link out 1","mode":"link","links":["2128a855234c1016"],"x":665,"y":560,"wires":[]},{"id":"b23cea1074943d4d","type":"debug","z":"bdd7be38.d3b55","name":"OUT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":670,"y":400,"wires":[]},{"id":"d4d479e614e82a49","type":"debug","z":"bdd7be38.d3b55","name":"IN","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":470,"y":400,"wires":[]},{"id":"3a9faf0a95b4a9bb","type":"function","z":"bdd7be38.d3b55","name":"Flush","func":"return {flush: 1}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":190,"y":560,"wires":[["ed63ee4225312b40"]]},{"id":"7eb760e019b512dc","type":"function","z":"bdd7be38.d3b55","name":"Some functions to be performed","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":480,"wires":[["a82c03c3d34f683c"]]},{"id":"e35f37deeae94860","type":"comment","z":"bdd7be38.d3b55","name":"Set the queue timeout to larger than you ever expect the process to take","info":"OK, here is a simple flow which allows a sequence of nodes to be protected so that only one message is allowed in at a time. It uses a Delay node in Rate Limit mode to queue them, but releases them, using the Flush mechanism, as soon as the previous one is complete. Set the timeout in the delay node to a value greater than the maximum time you expect it ever to take. If for some reason the flow locks up (a message fails to indicate completion) then the next message will be released after that time.\nMake sure that you trap any errors and feed back to the Flush node when you have handled the error. Also make sure only one message is fed back for each one in, even in the case of errors.","x":270,"y":360,"wires":[]}]

Although it is still time based instead of event driven, it seems to be working. I have to think about, whether it is really enough to set the timeout just to some higher number than the processing time (which is usually below 30 sec). This solution is definitely more simple, than using the q-gate, but KISS.

Thank you!

1 Like

If you can help provide the necessary German translation we can get it fixed

The translation by deepl.com is fine, but even translate.google.com is ok (I checked both of them).

There is still an issue:
The Alexa functionality is done by the node call service which doesn't wait for the end of the processing (asynchrone), thus, there is still a collision of the messages.

The simplified subflow:

[{"id":"8246f0e467c3a7ec","type":"subflow","name":"Wohnzimmer-TV: Text+Audio oder Wohnzimmer-Alexa","info":"Falls der **Wohnzimmer-Fernseher** an ist, dann kommt dort die Benachrichtigung, ansonsten per **Wohnzimmer-Alexa**.","category":"","in":[{"x":60,"y":160,"wires":[{"id":"b288533fad71379b"}]}],"out":[{"x":1520,"y":220,"wires":[{"id":"d6836ef9d82a79d7","port":0}]}],"env":[],"meta":{"desc":"Falls der **Wohnzimmer-Fernseher** an ist, dann kommt dort die Benachrichtigung, ansonsten per **Wohnzimmer-Alexa**."},"color":"#E2D96E","icon":"font-awesome/fa-home","status":{"x":1580,"y":360,"wires":[{"id":"11415c5730ff33a7","port":0}]}},{"id":"797397d6c8c621a6","type":"junction","z":"8246f0e467c3a7ec","x":680,"y":160,"wires":[["69164558931fcfa7","d6836ef9d82a79d7"]]},{"id":"9dadf6cca7486b75","type":"junction","z":"8246f0e467c3a7ec","x":1060,"y":220,"wires":[["c641b2aa70bf3b47"]]},{"id":"b288533fad71379b","type":"junction","z":"8246f0e467c3a7ec","x":260,"y":160,"wires":[["434742e7c3f85bb4"]]},{"id":"69164558931fcfa7","type":"api-call-service","z":"8246f0e467c3a7ec","name":"Alexa im Wohnzimmer-TV - Texteinblendung","server":"5c3a8010.dcc6d","version":5,"debugenabled":false,"domain":"notify","service":"lg_webos_tv_up75009lf","areaId":[],"deviceId":[],"entityId":[],"data":"{\"message\":\"{{payload}}\",\"data\":{\"type\":\"tts\"}}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"payload","valueType":"jsonata"}],"queue":"none","x":930,"y":160,"wires":[[]]},{"id":"11415c5730ff33a7","type":"status","z":"8246f0e467c3a7ec","name":"","scope":null,"x":1360,"y":360,"wires":[[]]},{"id":"d6836ef9d82a79d7","type":"api-call-service","z":"8246f0e467c3a7ec","name":"Alexa im Wohnzimmer Audio","server":"5c3a8010.dcc6d","version":5,"debugenabled":false,"domain":"notify","service":"alexa_media_wohnzimmer","areaId":[],"deviceId":[],"entityId":[],"data":"{\"message\":\"{{payload}}\",\"data\":{\"type\":\"tts\"}}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":880,"y":220,"wires":[["9dadf6cca7486b75"]]},{"id":"93ce2551e639d4c2","type":"link in","z":"8246f0e467c3a7ec","name":"link in 2","links":["c641b2aa70bf3b47"],"x":205,"y":280,"wires":[["af7f45a64f20991b"]]},{"id":"c641b2aa70bf3b47","type":"link out","z":"8246f0e467c3a7ec","name":"link out 2","mode":"link","links":["93ce2551e639d4c2"],"x":1135,"y":280,"wires":[]},{"id":"af7f45a64f20991b","type":"function","z":"8246f0e467c3a7ec","name":"Flush","func":"return {flush: 1}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":220,"wires":[["434742e7c3f85bb4"]]},{"id":"434742e7c3f85bb4","type":"delay","z":"8246f0e467c3a7ec","name":"Queue","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":490,"y":160,"wires":[["797397d6c8c621a6"]]},{"id":"e0db0439ab851a0f","type":"catch","z":"8246f0e467c3a7ec","name":"","scope":null,"uncaught":false,"x":1100,"y":40,"wires":[[]]},{"id":"5c3a8010.dcc6d","type":"server","name":"Home Assistant","addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"","statusSeparator":"","enableGlobalContextStore":false}]

It isn't time based, the next message is released when you tell it to release it, via the Flush message. The rate setting is purely so that you can specify a timeout such that if a message never completes for some reason that the whole flow will not lock up. If you don't want to use that then set it to a large time.

Well if there is no way of knowing when the previous message has finished processing then this approach will obviously not work.

Is it possible to tell that the call service has completed by using some effect of whatever the call service node does.

It would only go, if there would be a kind of media_player.in_use functionality, which is not the case -AFAIK. Even the Queue functionality of the node call service doesn't really help because of the asnch execution. Also the tracking of the router's traffic to the given device won't help without the analysis of the traffic's content.
Thus, the solution is not in the node call service or in other external resources, but in the (Alexa) device (i.e. Alexa Media Player).

The current workaround is to give every message a time slot, which is how it was done also previously and it isn't nice.

You can use node-red-contrib-alexa-remote2-applestrudel (node) - Node-RED to integrate with Alexa, these node would give a response when the speech is finished, allowing for the flush command.

Thank you, I'll try it and will give you feedback here.

Sorry, but I have no idea how to initialize those applestrudel stuff: If I'm starting some of those Alexa-nodes, the response is:

open http://localhost:3456/ in your browser

which would be fine, but I have no browser on my HA installation (in Virtual Box) and I don't know how to get there any. I tried it in the HA Terminal with curl and wget, but it did not work. In Node RED I called that URL with the node http request (followed by a debug node), but it delivered a script for that page...

The same browser you are using the editor on, open a new window and enter the url. You then get a amazon login page.

There are many topics on this forum on how to initialise the nodes Search results for 'alexa remote2 initialise' - Node-RED Forum