@rosepetal/node-red-contrib-utils 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/nodes/io/queue.md +12 -5
- package/nodes/io/queue.html +21 -3
- package/nodes/io/queue.js +24 -8
- package/package.json +1 -1
package/docs/nodes/io/queue.md
CHANGED
|
@@ -16,9 +16,14 @@ The `queue` node buffers incoming messages, enforces a minimum interval between
|
|
|
16
16
|
- **Incoming Message**: Any Node-RED message to be enqueued.
|
|
17
17
|
|
|
18
18
|
### Outputs
|
|
19
|
-
- **
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
- **Output 1**: Messages forwarded in FIFO order while respecting the configured interval.
|
|
20
|
+
- **Output 2**: Messages dropped due to timeout or overflow, with metadata:
|
|
21
|
+
- `msg.meta.queueDropped` - Always `true`
|
|
22
|
+
- `msg.meta.queueDropReason` - Either `"timeout"` or `"overflow"`
|
|
23
|
+
- `msg.meta.queuedDuration` - Time spent in queue before timeout (timeout drops only)
|
|
24
|
+
- `msg.meta.queueTimeout` - Configured timeout value in ms (timeout drops only)
|
|
25
|
+
- `msg.meta.queueSize` - Queue size when overflow occurred (overflow drops only)
|
|
26
|
+
- `msg.meta.queueMaxSize` - Configured max queue size (overflow drops only)
|
|
22
27
|
|
|
23
28
|
## Configuration Options
|
|
24
29
|
|
|
@@ -47,11 +52,13 @@ When timeout mode is selected, messages that exceed the configured timeout are s
|
|
|
47
52
|
- Messages are processed in first-in-first-out order.
|
|
48
53
|
- The node emits messages immediately when the interval requirement has already been satisfied.
|
|
49
54
|
- If necessary, the node waits the remaining interval before releasing the next message.
|
|
50
|
-
- When messages expire due to timeout (and timeout mode is active) they are
|
|
55
|
+
- When messages expire due to timeout (and timeout mode is active) they are sent to output 2 with metadata and a warning is logged.
|
|
56
|
+
- When the queue overflows (queue-size mode) excess messages are sent to output 2 with metadata.
|
|
51
57
|
- Node status indicates whether the queue is idle, holding messages, or actively sending.
|
|
52
58
|
|
|
53
59
|
## Best Practices
|
|
54
60
|
|
|
55
61
|
- Pair with Array nodes to control the rate of batch processing pipelines.
|
|
56
62
|
- Use timeouts to keep sensor readings or camera frames current.
|
|
57
|
-
-
|
|
63
|
+
- Connect output 2 to logging, alerting, or fallback processing to handle dropped messages.
|
|
64
|
+
- Use `msg.meta.queueDropReason` to differentiate between timeout and overflow scenarios in downstream logic.
|
package/nodes/io/queue.html
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
timeout: { value: 0 }
|
|
11
11
|
},
|
|
12
12
|
inputs: 1,
|
|
13
|
-
outputs:
|
|
13
|
+
outputs: 2,
|
|
14
|
+
outputLabels: ["output", "dropped"],
|
|
14
15
|
icon: "font-awesome/fa-clock-o",
|
|
15
16
|
label: function() {
|
|
16
17
|
if (this.name) return this.name;
|
|
@@ -106,11 +107,28 @@
|
|
|
106
107
|
<dd>Minimum time to wait between forwarded messages. Zero means send immediately when data is available.</dd>
|
|
107
108
|
</dl>
|
|
108
109
|
|
|
110
|
+
<h3>Outputs</h3>
|
|
111
|
+
<dl class="message-properties">
|
|
112
|
+
<dt>Output 1 <span class="property-type">message</span></dt>
|
|
113
|
+
<dd>Successfully queued messages released according to the interval setting.</dd>
|
|
114
|
+
<dt>Output 2 <span class="property-type">message</span></dt>
|
|
115
|
+
<dd>Messages dropped due to timeout expiration or queue overflow. Includes metadata:
|
|
116
|
+
<ul>
|
|
117
|
+
<li><code>msg.meta.queueDropped</code> - Always <code>true</code></li>
|
|
118
|
+
<li><code>msg.meta.queueDropReason</code> - Either <code>"timeout"</code> or <code>"overflow"</code></li>
|
|
119
|
+
<li><code>msg.meta.queuedDuration</code> - Time in queue before timeout (timeout only)</li>
|
|
120
|
+
<li><code>msg.meta.queueTimeout</code> - Configured timeout value (timeout only)</li>
|
|
121
|
+
<li><code>msg.meta.queueSize</code> - Current queue size (overflow only)</li>
|
|
122
|
+
<li><code>msg.meta.queueMaxSize</code> - Configured max size (overflow only)</li>
|
|
123
|
+
</ul>
|
|
124
|
+
</dd>
|
|
125
|
+
</dl>
|
|
126
|
+
|
|
109
127
|
<h3>Behavior</h3>
|
|
110
128
|
<ul>
|
|
111
129
|
<li>Messages are processed in FIFO order while respecting the selected mode.</li>
|
|
112
|
-
<li>Queue-size mode enforces a hard cap
|
|
113
|
-
<li>Timeout mode keeps buffering but evicts stale entries
|
|
130
|
+
<li>Queue-size mode enforces a hard cap; excess messages go to output 2 with <code>overflow</code> reason.</li>
|
|
131
|
+
<li>Timeout mode keeps buffering but evicts stale entries to output 2 with <code>timeout</code> reason.</li>
|
|
114
132
|
<li>The interval ensures a steady pace by adding delays between sends when configured.</li>
|
|
115
133
|
</ul>
|
|
116
134
|
|
package/nodes/io/queue.js
CHANGED
|
@@ -68,23 +68,32 @@ module.exports = function (RED) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const now = Date.now();
|
|
71
|
-
|
|
71
|
+
const expiredEntries = [];
|
|
72
72
|
|
|
73
73
|
while (state.queue.length > 0) {
|
|
74
74
|
const oldest = state.queue[0];
|
|
75
75
|
if (now - oldest.enqueuedAt >= node.timeoutMs) {
|
|
76
|
-
state.queue.shift();
|
|
77
|
-
dropped += 1;
|
|
76
|
+
expiredEntries.push(state.queue.shift());
|
|
78
77
|
} else {
|
|
79
78
|
break;
|
|
80
79
|
}
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
if (
|
|
84
|
-
node.warn(`Queue node dropped ${
|
|
82
|
+
if (expiredEntries.length > 0) {
|
|
83
|
+
node.warn(`Queue node dropped ${expiredEntries.length} message(s) due to timeout.`);
|
|
84
|
+
// Send expired messages to output 2 with metadata
|
|
85
|
+
for (const entry of expiredEntries) {
|
|
86
|
+
const droppedMsg = entry.msg;
|
|
87
|
+
droppedMsg.meta = droppedMsg.meta || {};
|
|
88
|
+
droppedMsg.meta.queueDropped = true;
|
|
89
|
+
droppedMsg.meta.queueDropReason = 'timeout';
|
|
90
|
+
droppedMsg.meta.queuedDuration = now - entry.enqueuedAt;
|
|
91
|
+
droppedMsg.meta.queueTimeout = node.timeoutMs;
|
|
92
|
+
node.send([null, droppedMsg]);
|
|
93
|
+
}
|
|
85
94
|
}
|
|
86
95
|
|
|
87
|
-
return
|
|
96
|
+
return expiredEntries.length;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
function scheduleNextSend() {
|
|
@@ -144,7 +153,7 @@ module.exports = function (RED) {
|
|
|
144
153
|
text: `Sending (remaining ${state.queue.length})`
|
|
145
154
|
});
|
|
146
155
|
|
|
147
|
-
node.send(entry.msg);
|
|
156
|
+
node.send([entry.msg, null]);
|
|
148
157
|
scheduleNextSend();
|
|
149
158
|
}
|
|
150
159
|
|
|
@@ -161,8 +170,15 @@ module.exports = function (RED) {
|
|
|
161
170
|
state.queue.length >= node.maxQueueSize
|
|
162
171
|
) {
|
|
163
172
|
node.warn(
|
|
164
|
-
`Queue node at capacity (${node.maxQueueSize}). Incoming message
|
|
173
|
+
`Queue node at capacity (${node.maxQueueSize}). Incoming message dropped.`
|
|
165
174
|
);
|
|
175
|
+
// Send overflow message to output 2 with metadata
|
|
176
|
+
msg.meta = msg.meta || {};
|
|
177
|
+
msg.meta.queueDropped = true;
|
|
178
|
+
msg.meta.queueDropReason = 'overflow';
|
|
179
|
+
msg.meta.queueSize = state.queue.length;
|
|
180
|
+
msg.meta.queueMaxSize = node.maxQueueSize;
|
|
181
|
+
node.send([null, msg]);
|
|
166
182
|
setStatusQueued();
|
|
167
183
|
return done?.();
|
|
168
184
|
}
|
package/package.json
CHANGED