@pauldeng/node-red-contrib-bullmq 1.0.3 → 2.0.0
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/README.md +61 -38
- package/bull-queue.html +241 -73
- package/bull-queue.js +623 -120
- package/docs/ARCHITECTURE.md +62 -18
- package/docs/CHANGE_WORKFLOW.md +10 -11
- package/docs/COMMANDS.md +72 -11
- package/docs/CONNECTIONS.md +62 -5
- package/docs/MIGRATION.md +56 -22
- package/docs/NODE_GUIDE.md +51 -16
- package/docs/REFERENCE_MAP.md +27 -10
- package/docs/RELEASE.md +17 -4
- package/docs/RULES.md +33 -0
- package/docs/TELEMETRY.md +55 -0
- package/docs/TESTING.md +30 -16
- package/docs/TROUBLESHOOTING.md +44 -5
- package/examples/README.md +40 -12
- package/examples/bullmq_features.json +218 -16
- package/examples/example_flow.json +11 -11
- package/examples/postgres_backend.json +149 -0
- package/examples/repeatable_jobs.json +51 -19
- package/examples/scheduled_notifications.json +216 -0
- package/lib/acknowledgements.js +19 -1
- package/lib/commands.js +74 -35
- package/lib/connections.js +212 -26
- package/lib/scheduler.js +5 -74
- package/lib/serialization.js +1 -4
- package/package.json +24 -8
package/bull-queue.html
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
<script type="text/html" data-template-name="
|
|
1
|
+
<script type="text/html" data-template-name="bullmq-queue-server">
|
|
2
2
|
<div class="form-row">
|
|
3
3
|
<label for="node-config-input-name"><i class="fa fa-tasks"></i> Queue</label>
|
|
4
4
|
<input type="text" id="node-config-input-name" placeholder="email-jobs">
|
|
5
5
|
</div>
|
|
6
6
|
<div class="form-row">
|
|
7
|
+
<label for="node-config-input-backend"><i class="fa fa-database"></i> Backend</label>
|
|
8
|
+
<select id="node-config-input-backend" style="width: 70%;">
|
|
9
|
+
<option value="redis">Redis</option>
|
|
10
|
+
<option value="postgres">PostgreSQL</option>
|
|
11
|
+
</select>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="form-row bull-redis-row">
|
|
7
14
|
<label for="node-config-input-deployment"><i class="fa fa-server"></i> Deployment</label>
|
|
8
15
|
<select id="node-config-input-deployment" style="width: 70%;">
|
|
9
16
|
<option value="single">Standalone Redis</option>
|
|
@@ -35,9 +42,26 @@
|
|
|
35
42
|
<label for="node-config-input-db"><i class="fa fa-database"></i> Database</label>
|
|
36
43
|
<input type="number" id="node-config-input-db" placeholder="0">
|
|
37
44
|
</div>
|
|
45
|
+
<div class="form-row bull-postgres-row">
|
|
46
|
+
<label for="node-config-input-database"><i class="fa fa-database"></i> Database Name</label>
|
|
47
|
+
<input type="text" id="node-config-input-database" placeholder="bullmq">
|
|
48
|
+
</div>
|
|
49
|
+
<div class="form-row bull-postgres-row">
|
|
50
|
+
<label for="node-config-input-schema"><i class="fa fa-folder-o"></i> Schema</label>
|
|
51
|
+
<input type="text" id="node-config-input-schema" placeholder="bullmq">
|
|
52
|
+
</div>
|
|
53
|
+
<div class="form-row bull-postgres-row">
|
|
54
|
+
<label for="node-config-input-max"><i class="fa fa-database"></i> Pool Max</label>
|
|
55
|
+
<input type="number" id="node-config-input-max" min="1" step="1" placeholder="2">
|
|
56
|
+
</div>
|
|
57
|
+
<div class="form-row bull-postgres-row">
|
|
58
|
+
<label for="node-config-input-migrate"><i class="fa fa-wrench"></i> Migrations</label>
|
|
59
|
+
<input type="checkbox" id="node-config-input-migrate" style="display:inline-block; width:auto; vertical-align:top;">
|
|
60
|
+
<span>Create and update the BullMQ schema on connect</span>
|
|
61
|
+
</div>
|
|
38
62
|
<div class="form-row">
|
|
39
63
|
<label for="node-config-input-username"><i class="fa fa-user"></i> Username</label>
|
|
40
|
-
<input type="text" id="node-config-input-username" placeholder="
|
|
64
|
+
<input type="text" id="node-config-input-username" placeholder="user">
|
|
41
65
|
</div>
|
|
42
66
|
<div class="form-row">
|
|
43
67
|
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
|
|
@@ -54,7 +78,7 @@
|
|
|
54
78
|
<div class="form-row">
|
|
55
79
|
<label for="node-config-input-tls"><i class="fa fa-shield"></i> TLS</label>
|
|
56
80
|
<input type="checkbox" id="node-config-input-tls" style="display:inline-block; width:auto; vertical-align:top;">
|
|
57
|
-
<span>Use TLS for
|
|
81
|
+
<span>Use TLS for data connections</span>
|
|
58
82
|
</div>
|
|
59
83
|
<div class="form-row bull-sentinel-row">
|
|
60
84
|
<label for="node-config-input-sentinelTls"><i class="fa fa-shield"></i> Sentinel TLS</label>
|
|
@@ -68,7 +92,7 @@
|
|
|
68
92
|
</div>
|
|
69
93
|
<div class="form-row bull-tls-row">
|
|
70
94
|
<label for="node-config-input-tlsServerName"><i class="fa fa-globe"></i> TLS Server Name</label>
|
|
71
|
-
<input type="text" id="node-config-input-tlsServerName" placeholder="
|
|
95
|
+
<input type="text" id="node-config-input-tlsServerName" placeholder="server.example.com">
|
|
72
96
|
</div>
|
|
73
97
|
<div class="form-row bull-tls-row">
|
|
74
98
|
<label for="node-config-input-tlsCa"><i class="fa fa-certificate"></i> CA</label>
|
|
@@ -82,31 +106,95 @@
|
|
|
82
106
|
<label for="node-config-input-tlsKey"><i class="fa fa-key"></i> Client Key</label>
|
|
83
107
|
<textarea id="node-config-input-tlsKey" rows="3" style="width: 70%;"></textarea>
|
|
84
108
|
</div>
|
|
85
|
-
<div class="form-row">
|
|
109
|
+
<div class="form-row bull-redis-row">
|
|
86
110
|
<label for="node-config-input-prefix"><i class="fa fa-code"></i> Prefix</label>
|
|
87
111
|
<input type="text" id="node-config-input-prefix" placeholder="{bull}">
|
|
88
112
|
</div>
|
|
113
|
+
<div class="form-row">
|
|
114
|
+
<label for="node-config-input-removeOnComplete"><i class="fa fa-trash"></i> Completed</label>
|
|
115
|
+
<input type="number" id="node-config-input-removeOnComplete" min="0" step="1" placeholder="1000">
|
|
116
|
+
</div>
|
|
117
|
+
<div class="form-row">
|
|
118
|
+
<label for="node-config-input-removeOnFail"><i class="fa fa-trash-o"></i> Failed</label>
|
|
119
|
+
<input type="number" id="node-config-input-removeOnFail" min="0" step="1" placeholder="5000">
|
|
120
|
+
</div>
|
|
121
|
+
<div class="form-row">
|
|
122
|
+
<label for="node-config-input-telemetry"><i class="fa fa-line-chart"></i> Telemetry</label>
|
|
123
|
+
<input type="checkbox" id="node-config-input-telemetry" style="display:inline-block; width:auto; vertical-align:top;">
|
|
124
|
+
<span>Enable OpenTelemetry tracing via bullmq-otel</span>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="form-row bull-telemetry-row">
|
|
127
|
+
<label for="node-config-input-telemetryServiceName"><i class="fa fa-tag"></i> Service Name</label>
|
|
128
|
+
<input type="text" id="node-config-input-telemetryServiceName" placeholder="queue name">
|
|
129
|
+
</div>
|
|
130
|
+
<div class="form-row bull-telemetry-row">
|
|
131
|
+
<label for="node-config-input-telemetryMetrics"><i class="fa fa-bar-chart"></i> Metrics</label>
|
|
132
|
+
<input type="checkbox" id="node-config-input-telemetryMetrics" style="display:inline-block; width:auto; vertical-align:top;">
|
|
133
|
+
<span>Enable OpenTelemetry metrics</span>
|
|
134
|
+
</div>
|
|
89
135
|
</script>
|
|
90
136
|
|
|
91
137
|
<script type="text/javascript">
|
|
92
138
|
(function() {
|
|
139
|
+
function validateKeepCount(value) {
|
|
140
|
+
return value === "" || /^\d+$/.test(value);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Blank is not zero: blank means "use the default pool size", while 0 is a
|
|
144
|
+
// pool that can never hand out a connection, which the runtime rejects.
|
|
145
|
+
// Undefined counts as blank so a saved flow with no max never shows an
|
|
146
|
+
// error before the dialog has been opened once.
|
|
147
|
+
function validatePoolMax(value) {
|
|
148
|
+
if (value === "" || value === undefined || value === null) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
return /^\d+$/.test(String(value)) && Number(value) >= 1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function isPostgresBackend() {
|
|
155
|
+
return $("#node-config-input-backend").val() === "postgres";
|
|
156
|
+
}
|
|
157
|
+
|
|
93
158
|
function updateBullQueueServerRows() {
|
|
159
|
+
var postgres = isPostgresBackend();
|
|
94
160
|
var deployment = $("#node-config-input-deployment").val() || "single";
|
|
95
|
-
$(".bull-
|
|
96
|
-
$(".bull-
|
|
97
|
-
|
|
98
|
-
|
|
161
|
+
$(".bull-redis-row").toggle(!postgres);
|
|
162
|
+
$(".bull-postgres-row").toggle(postgres);
|
|
163
|
+
// Host and port are shared, so PostgreSQL always shows them. The cluster,
|
|
164
|
+
// Sentinel, and Redis-database rows describe Redis topologies only.
|
|
165
|
+
$(".bull-single-row").toggle(postgres || deployment === "single");
|
|
166
|
+
$(".bull-cluster-row").toggle(!postgres && deployment === "cluster");
|
|
167
|
+
$(".bull-sentinel-row").toggle(!postgres && deployment === "sentinel");
|
|
168
|
+
$(".bull-db-row").toggle(!postgres && deployment !== "cluster");
|
|
99
169
|
$(".bull-tls-row").toggle($("#node-config-input-tls").is(":checked"));
|
|
170
|
+
$(".bull-telemetry-row").toggle($("#node-config-input-telemetry").is(":checked"));
|
|
100
171
|
}
|
|
101
172
|
|
|
102
|
-
RED.nodes.registerType("
|
|
173
|
+
RED.nodes.registerType("bullmq-queue-server", {
|
|
103
174
|
category: "config",
|
|
104
175
|
defaults: {
|
|
105
176
|
name: { value: "", required: true },
|
|
177
|
+
backend: { value: "redis", required: true },
|
|
106
178
|
deployment: { value: "single", required: true },
|
|
107
179
|
address: { value: "localhost" },
|
|
108
180
|
port: { value: 6379, validate: RED.validators.number() },
|
|
109
181
|
db: { value: "" },
|
|
182
|
+
database: { value: "" },
|
|
183
|
+
schema: { value: "" },
|
|
184
|
+
max: {
|
|
185
|
+
value: "",
|
|
186
|
+
// Node-RED validates every default, visible or not, and calls this
|
|
187
|
+
// with the node as `this`. A Redis config must not be flagged
|
|
188
|
+
// invalid by the PostgreSQL pool size: that row is hidden on Redis,
|
|
189
|
+
// so the dialog offers no way to correct it. lib/connections.js
|
|
190
|
+
// draws the same line, validating only the selected backend's
|
|
191
|
+
// fields. A flow saved before the selector existed has no backend
|
|
192
|
+
// property and is Redis, so it is exempt too.
|
|
193
|
+
validate: function(value) {
|
|
194
|
+
return this.backend !== "postgres" || validatePoolMax(value);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
migrate: { value: true },
|
|
110
198
|
clusterNodes: { value: "" },
|
|
111
199
|
sentinels: { value: "" },
|
|
112
200
|
sentinelMasterName: { value: "" },
|
|
@@ -116,7 +204,12 @@
|
|
|
116
204
|
sentinelTls: { value: false },
|
|
117
205
|
tlsRejectUnauthorized: { value: true },
|
|
118
206
|
tlsServerName: { value: "" },
|
|
119
|
-
prefix: { value: "" }
|
|
207
|
+
prefix: { value: "" },
|
|
208
|
+
removeOnComplete: { value: "1000", validate: validateKeepCount },
|
|
209
|
+
removeOnFail: { value: "5000", validate: validateKeepCount },
|
|
210
|
+
telemetry: { value: false },
|
|
211
|
+
telemetryServiceName: { value: "" },
|
|
212
|
+
telemetryMetrics: { value: false }
|
|
120
213
|
},
|
|
121
214
|
credentials: {
|
|
122
215
|
password: { type: "password" },
|
|
@@ -129,49 +222,92 @@
|
|
|
129
222
|
return this.name || this.address + ":" + this.port;
|
|
130
223
|
},
|
|
131
224
|
oneditprepare: function() {
|
|
225
|
+
// A flow saved before the backend selector existed has no backend or
|
|
226
|
+
// migrate property, and editor defaults never migrate saved JSON: the
|
|
227
|
+
// inputs are populated from the saved node, so both would read as
|
|
228
|
+
// "unset" here -- an empty select, and a migrations box unchecked when
|
|
229
|
+
// the runtime default is on. Seed them to the runtime's own defaults
|
|
230
|
+
// before anything reads them.
|
|
231
|
+
if (!this.backend) {
|
|
232
|
+
$("#node-config-input-backend").val("redis");
|
|
233
|
+
}
|
|
234
|
+
if (this.migrate === undefined) {
|
|
235
|
+
$("#node-config-input-migrate").prop("checked", true);
|
|
236
|
+
}
|
|
237
|
+
// One saved port field serves both backends. Keep one value per mode
|
|
238
|
+
// while the dialog is open so even a deliberate Redis port of 5432
|
|
239
|
+
// survives a round-trip through PostgreSQL.
|
|
240
|
+
var backendField = $("#node-config-input-backend");
|
|
241
|
+
var portField = $("#node-config-input-port");
|
|
242
|
+
var activeBackend = isPostgresBackend() ? "postgres" : "redis";
|
|
243
|
+
var portValues = {
|
|
244
|
+
redis: activeBackend === "redis" ? String(portField.val()) : "6379",
|
|
245
|
+
postgres: activeBackend === "postgres" ? String(portField.val()) : "5432"
|
|
246
|
+
};
|
|
247
|
+
backendField.on("change", function() {
|
|
248
|
+
var nextBackend = isPostgresBackend() ? "postgres" : "redis";
|
|
249
|
+
if (nextBackend !== activeBackend) {
|
|
250
|
+
portValues[activeBackend] = String(portField.val());
|
|
251
|
+
portField.val(portValues[nextBackend]);
|
|
252
|
+
activeBackend = nextBackend;
|
|
253
|
+
}
|
|
254
|
+
updateBullQueueServerRows();
|
|
255
|
+
});
|
|
132
256
|
$("#node-config-input-deployment").on("change", updateBullQueueServerRows);
|
|
133
257
|
$("#node-config-input-tls").on("change", updateBullQueueServerRows);
|
|
258
|
+
$("#node-config-input-telemetry").on("change", updateBullQueueServerRows);
|
|
134
259
|
updateBullQueueServerRows();
|
|
135
260
|
}
|
|
136
261
|
});
|
|
137
262
|
})();
|
|
138
263
|
</script>
|
|
139
264
|
|
|
140
|
-
<script type="text/html" data-help-name="
|
|
141
|
-
<p>Configures the BullMQ queue name and
|
|
142
|
-
<p>
|
|
265
|
+
<script type="text/html" data-help-name="bullmq-queue-server">
|
|
266
|
+
<p>Configures the BullMQ queue name and the backend connection shared by the BullMQ nodes. BullMQ v6 can store queues in either Redis or PostgreSQL; pick one per config node with <b>Backend</b>.</p>
|
|
267
|
+
<p>PostgreSQL requires the <code>pg</code> package, which is an optional peer dependency and must be installed separately (<code>npm install pg</code>). It is reported once per config node on first use, not at load.</p>
|
|
268
|
+
<p>API reference: <a href="https://docs.bullmq.io/api/classes/v6.Queue.html" target="_blank" rel="noopener noreferrer">Queue</a> and <a href="https://docs.bullmq.io/api/interfaces/v6.QueueOptions.html" target="_blank" rel="noopener noreferrer">QueueOptions</a>.</p>
|
|
143
269
|
|
|
144
270
|
<h3>Options</h3>
|
|
145
271
|
<ul>
|
|
146
272
|
<li><b>Queue</b>: BullMQ queue name. All producer, worker, event, and flow nodes that select this config use this queue name unless a BullMQ flow child specifies another <code>queueName</code>.</li>
|
|
273
|
+
<li><b>Backend</b>: Where BullMQ stores this queue. <code>Redis</code> keeps the Redis topology, key prefix, and Redis database options below. <code>PostgreSQL</code> replaces them with the database options and needs <code>pg</code> installed.</li>
|
|
147
274
|
<li><b>Deployment</b>: Redis topology. Use <code>Standalone Redis</code> for one Redis endpoint, <code>Redis Cluster / AWS MemoryDB</code> for cluster-compatible endpoints, or <code>Redis Sentinel</code> for Sentinel discovery.</li>
|
|
148
|
-
<li><b>Host</b>: Standalone Redis host name or IP address.</li>
|
|
149
|
-
<li><b>Port</b>: Standalone Redis port. The
|
|
275
|
+
<li><b>Host</b>: Standalone Redis host, or the PostgreSQL server host name or IP address.</li>
|
|
276
|
+
<li><b>Port</b>: Standalone Redis port, or the PostgreSQL port. The defaults are <code>6379</code> for Redis and <code>5432</code> for PostgreSQL. While the dialog is open, switching <b>Backend</b> preserves a separate value for each backend so a custom port is never overwritten.</li>
|
|
150
277
|
<li><b>Cluster Nodes</b>: Comma or newline separated cluster seed nodes such as <code>redis-a:6379, redis-b:6379</code>. AWS MemoryDB cluster configuration endpoints are entered here.</li>
|
|
151
278
|
<li><b>Sentinels</b>: Comma or newline separated Sentinel endpoints such as <code>sentinel-a:26379, sentinel-b:26379</code>.</li>
|
|
152
279
|
<li><b>Master</b>: Sentinel master name, for example <code>mymaster</code>.</li>
|
|
153
280
|
<li><b>Database</b>: Redis database number for standalone or Sentinel data connections. Cluster and MemoryDB deployments use Redis database <code>0</code>.</li>
|
|
154
|
-
<li><b>
|
|
155
|
-
<li><b>
|
|
281
|
+
<li><b>Database Name</b>: PostgreSQL database that holds the BullMQ schema. Distinct from the Redis <b>Database</b> number above, which is an index rather than a name. Left blank, node-postgres falls back to the <code>PGDATABASE</code> environment variable and then to the operating-system user name, as it does for a blank <b>Username</b> with <code>PGUSER</code>.</li>
|
|
282
|
+
<li><b>Schema</b>: PostgreSQL schema for BullMQ's tables. Defaults to <code>bullmq</code>. Separate schemas keep independent queue sets in one database.</li>
|
|
283
|
+
<li><b>Pool Max</b>: Maximum PostgreSQL connections in each pool. Blank uses the default of <code>2</code>; <code>0</code> is rejected, since a pool that can never hand out a connection cannot run a queue. BullMQ builds one pool per queue, worker, event listener, and flow producer; workers and event listeners also hold one extra <code>LISTEN</code> connection each. A config node feeding all four therefore costs up to 4 × <b>Pool Max</b> + 2 server connections — 10 at the default. Start with the default and raise it only when observed pool waits justify the extra server connections; worker <b>Concurrency</b> does not require a one-to-one pool size.</li>
|
|
284
|
+
<li><b>Migrations</b>: Creates and updates BullMQ's PostgreSQL schema when connecting. On by default. Turn it off where the database user is not allowed to change the schema, and apply BullMQ's migrations separately -- a queue pointed at a database whose schema is missing or outdated reports that as an error rather than running.</li>
|
|
285
|
+
<li><b>Username</b>: Redis ACL username, or the PostgreSQL user. Leave empty to use the client's backend default; this is also correct for Redis servers that only use a password.</li>
|
|
286
|
+
<li><b>Password</b>: Password for data connections, for either backend. Stored as a Node-RED credential.</li>
|
|
156
287
|
<li><b>Sentinel User</b>: Redis ACL username for Sentinel discovery connections when Sentinels require separate credentials.</li>
|
|
157
288
|
<li><b>Sentinel Pass</b>: Password for Sentinel discovery connections. Stored as a Node-RED credential.</li>
|
|
158
|
-
<li><b>TLS</b>: Enables TLS for
|
|
289
|
+
<li><b>TLS</b>: Enables TLS for data connections on either backend. Use this for AWS MemoryDB, any Redis deployment that requires encrypted data connections, and PostgreSQL servers that require SSL. <b>Verify TLS</b>, <b>TLS Server Name</b>, <b>CA</b>, <b>Client Cert</b>, and <b>Client Key</b> apply to both.</li>
|
|
159
290
|
<li><b>Sentinel TLS</b>: Enables TLS for Sentinel discovery connections.</li>
|
|
160
291
|
<li><b>Verify TLS</b>: Rejects certificates that cannot be verified. Keep enabled in production unless you intentionally use a private test certificate.</li>
|
|
161
|
-
<li><b>TLS Server Name</b>: Optional server name used for certificate validation when it differs from the host value.</li>
|
|
162
|
-
<li><b>CA</b>: PEM certificate authority text for validating private
|
|
292
|
+
<li><b>TLS Server Name</b>: Optional server name used for certificate validation when it differs from the host value. For PostgreSQL, node-postgres uses the connection host when it is a hostname and honors this override only when <b>Host</b> is a literal IP address.</li>
|
|
293
|
+
<li><b>CA</b>: PEM certificate authority text for validating private backend certificates. Stored as a Node-RED credential.</li>
|
|
163
294
|
<li><b>Client Cert</b>: PEM client certificate for mutual TLS deployments. Stored as a Node-RED credential.</li>
|
|
164
295
|
<li><b>Client Key</b>: PEM client private key for mutual TLS deployments. Stored as a Node-RED credential.</li>
|
|
165
|
-
<li><b>Prefix</b>: BullMQ key prefix. Redis Cluster and MemoryDB prefixes must contain a hash tag such as <code>{bull}</code
|
|
296
|
+
<li><b>Prefix</b>: BullMQ key prefix. Redis Cluster and MemoryDB prefixes must contain a hash tag such as <code>{bull}</code>. Independent queues may use different tags, but prefixes in one flow tree or bulk flow batch must contain the same hash tag for atomic operations. Each worker must use the exact prefix assigned to its queue in that flow.</li>
|
|
297
|
+
<li><b>Keep Completed</b> / <b>Keep Failed</b>: Queue-level auto-removal, applied as BullMQ <code>defaultJobOptions</code>. Each keeps that many of the newest jobs in the state and removes older ones. Leaving a field blank keeps every job, which is BullMQ's own default and grows backend storage without bound, so blank is only appropriate when something else prunes the queue. <code>msg.jobopts</code> overrides these defaults for <code>bullmq cmd</code>. For <code>bullmq flow</code>, per-queue <code>msg.flowopts.queuesOptions</code> defaults and then each job's <code>opts</code> take precedence.</li>
|
|
298
|
+
<li><b>Telemetry</b>: Enables OpenTelemetry tracing for this queue's <code>Queue</code>, <code>Worker</code>, and <code>FlowProducer</code> instances using <a href="https://www.npmjs.com/package/bullmq-otel" target="_blank" rel="noopener noreferrer">bullmq-otel</a>. Off by default. <code>bullmq-otel</code> is an optional dependency and must be installed separately (<code>npm install bullmq-otel</code>) before enabling this switch. This node does not start or configure an OpenTelemetry SDK or exporter; the host Node-RED process owns that (for example NODE_OPTIONS auto-instrumentation, or an SDK bootstrapped from Node-RED's <code>settings.js</code>). When no OpenTelemetry provider is registered, <code>bullmq-otel</code> simply no-ops rather than erroring.</li>
|
|
299
|
+
<li><b>Service Name</b>: Tracer and meter name reported to OpenTelemetry. Leave blank to use the <b>Queue</b> name.</li>
|
|
300
|
+
<li><b>Metrics</b>: Enables OpenTelemetry metrics in addition to tracing. A <code>MeterProvider</code> must be registered with the host process before this queue is first used, otherwise metrics are dropped. For metrics scraping without any OpenTelemetry stack, the <code>bullmq cmd</code> node's <code>msg.cmd</code> <code>exportPrometheusMetrics</code> is a zero-dependency alternative.</li>
|
|
166
301
|
</ul>
|
|
167
302
|
|
|
168
303
|
<h3>Example</h3>
|
|
169
304
|
<p>For local Redis, set <b>Queue</b> to <code>email-jobs</code>, <b>Deployment</b> to <code>Standalone Redis</code>, <b>Host</b> to <code>localhost</code>, and <b>Port</b> to <code>6379</code>.</p>
|
|
305
|
+
<p>For local PostgreSQL, set <b>Backend</b> to <code>PostgreSQL</code>, <b>Host</b> to <code>localhost</code>, <b>Port</b> to <code>5432</code>, <b>Database Name</b> to <code>bullmq</code>, and leave <b>Schema</b>, <b>Pool Max</b>, and <b>Migrations</b> at their defaults. <b>Deployment</b>, <b>Prefix</b>, and the Redis <b>Database</b> number do not apply.</p>
|
|
170
306
|
<p>For AWS MemoryDB, set <b>Deployment</b> to <code>Redis Cluster / AWS MemoryDB</code>, enter the cluster endpoint in <b>Cluster Nodes</b>, enable <b>TLS</b>, keep <b>Verify TLS</b> enabled, and use <code>{bull}</code> as <b>Prefix</b>.</p>
|
|
171
|
-
<p>Redis
|
|
307
|
+
<p>Redis must use <code>maxmemory-policy=noeviction</code> and durable persistence; BullMQ recommends Append Only File (AOF) for self-managed Redis. Job data is stored in clear text, so avoid sensitive payloads or encrypt sensitive fields before adding a job. Bull v4 Redis queue data is not automatically migrated to BullMQ.</p>
|
|
172
308
|
</script>
|
|
173
309
|
|
|
174
|
-
<script type="text/html" data-template-name="
|
|
310
|
+
<script type="text/html" data-template-name="bullmq cmd">
|
|
175
311
|
<div class="form-row">
|
|
176
312
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
177
313
|
<input type="text" id="node-input-name">
|
|
@@ -182,9 +318,9 @@
|
|
|
182
318
|
</div>
|
|
183
319
|
</script>
|
|
184
320
|
|
|
185
|
-
<script type="text/html" data-help-name="
|
|
321
|
+
<script type="text/html" data-help-name="bullmq cmd">
|
|
186
322
|
<p>Executes BullMQ producer and queue-administration commands from an input message.</p>
|
|
187
|
-
<p>API reference: <a href="https://
|
|
323
|
+
<p>API reference: <a href="https://docs.bullmq.io/api/classes/v6.Queue.html" target="_blank" rel="noopener noreferrer">Queue</a>, <a href="https://docs.bullmq.io/api/classes/v6.Queue.html#add" target="_blank" rel="noopener noreferrer">Queue.add</a>, <a href="https://docs.bullmq.io/api/types/v6.JobsOptions.html" target="_blank" rel="noopener noreferrer">JobsOptions</a>, <a href="https://docs.bullmq.io/api/types/v6.DeduplicationOptions.html" target="_blank" rel="noopener noreferrer">DeduplicationOptions</a>, <a href="https://docs.bullmq.io/api/classes/v6.Queue.html#setglobalratelimit" target="_blank" rel="noopener noreferrer">Queue.setGlobalRateLimit</a>, and <a href="https://docs.bullmq.io/api/classes/v6.Queue.html#upsertjobscheduler" target="_blank" rel="noopener noreferrer">Queue.upsertJobScheduler</a>.</p>
|
|
188
324
|
|
|
189
325
|
<h3>Options</h3>
|
|
190
326
|
<ul>
|
|
@@ -194,11 +330,11 @@
|
|
|
194
330
|
|
|
195
331
|
<h3>Input message</h3>
|
|
196
332
|
<ul>
|
|
197
|
-
<li><code>msg.cmd</code>: Command name. Defaults to <code>add</code>. Common commands include <code>add</code>, <code>addBulk</code>, <code>getJob</code>, <code>getJobs</code>, <code>removeJob</code>, <code>retryJob</code>, <code>getDelayed</code>, <code>promoteJob</code>, <code>getPrioritized</code>, <code>changePriority</code>, <code>setGlobalRateLimit</code>, <code>removeGlobalRateLimit</code>, <code>upsertJobScheduler</code>, and <code>
|
|
198
|
-
<li><code>msg.payload</code>: Job data for <code>add</code> when <code>msg.jobData</code> is not set. For some commands it carries command parameters, such as <code>{ "max": 2, "duration": 1000 }</code> for <code>setGlobalRateLimit</code
|
|
333
|
+
<li><code>msg.cmd</code>: Command name. Defaults to <code>add</code>. Common commands include <code>add</code>, <code>addBulk</code>, <code>getJob</code>, <code>getJobs</code>, <code>removeJob</code>, <code>retryJob</code>, <code>getDelayed</code>, <code>promoteJob</code>, <code>getPrioritized</code>, <code>changePriority</code>, <code>setGlobalRateLimit</code>, <code>removeGlobalRateLimit</code>, <code>upsertJobScheduler</code>, <code>removeJobScheduler</code>, <code>isPaused</code>, <code>isMaxed</code>, and <code>getVersion</code>.</li>
|
|
334
|
+
<li><code>msg.payload</code>: Job data for <code>add</code> when <code>msg.jobData</code> is not set. For some commands it carries command parameters, such as <code>{ "max": 2, "duration": 1000 }</code> for <code>setGlobalRateLimit</code>. <code>isPaused</code> and <code>isMaxed</code> return a boolean; <code>getVersion</code> returns BullMQ's queue metadata version string (for example <code>bullmq:6.3.1</code>), not the Redis server version.</li>
|
|
199
335
|
<li><code>msg.jobName</code>: BullMQ job name for <code>add</code>. Defaults to <code>default</code>.</li>
|
|
200
336
|
<li><code>msg.jobData</code>: Full job data object for <code>add</code>. When set, it takes precedence over <code>msg.payload</code>.</li>
|
|
201
|
-
<li><code>msg.jobopts</code>: BullMQ job options for <code>add</code>, including <code>delay</code>, <code>priority</code>, <code>deduplication</code>, <code>attempts</code>, <code>backoff</code>, <code>removeOnComplete</code
|
|
337
|
+
<li><code>msg.jobopts</code>: BullMQ job options for <code>add</code>, including <code>delay</code>, <code>priority</code>, <code>deduplication</code>, <code>attempts</code>, <code>backoff</code>, and <code>removeOnComplete</code>. Repeat options are rejected; use <code>upsertJobScheduler</code>.</li>
|
|
202
338
|
</ul>
|
|
203
339
|
|
|
204
340
|
<h3>Examples</h3>
|
|
@@ -211,6 +347,14 @@ msg.jobopts = {
|
|
|
211
347
|
priority: 1,
|
|
212
348
|
removeOnComplete: true
|
|
213
349
|
};
|
|
350
|
+
return msg;</pre>
|
|
351
|
+
<p>Add three one-off jobs that become eligible after 10, 20, and 30 seconds:</p>
|
|
352
|
+
<pre>msg.cmd = "addBulk";
|
|
353
|
+
msg.payload = [
|
|
354
|
+
{ name: "delayed-1", data: { payload: "first" }, opts: { delay: 10000 } },
|
|
355
|
+
{ name: "delayed-2", data: { payload: "second" }, opts: { delay: 20000 } },
|
|
356
|
+
{ name: "delayed-3", data: { payload: "third" }, opts: { delay: 30000 } }
|
|
357
|
+
];
|
|
214
358
|
return msg;</pre>
|
|
215
359
|
<p>Add one job per deduplication id:</p>
|
|
216
360
|
<pre>msg.cmd = "add";
|
|
@@ -225,36 +369,37 @@ return msg;</pre>
|
|
|
225
369
|
msg.payload = { max: 2, duration: 1000 };
|
|
226
370
|
return msg;</pre>
|
|
227
371
|
<p>Add or update a scheduler every minute:</p>
|
|
228
|
-
<pre>msg.cmd = "
|
|
229
|
-
msg.
|
|
230
|
-
msg.
|
|
231
|
-
msg.
|
|
232
|
-
|
|
233
|
-
|
|
372
|
+
<pre>msg.cmd = "upsertJobScheduler";
|
|
373
|
+
msg.schedulerId = "heartbeat-every-minute";
|
|
374
|
+
msg.repeat = { pattern: "*/1 * * * *" };
|
|
375
|
+
msg.template = {
|
|
376
|
+
name: "heartbeat",
|
|
377
|
+
data: { payload: "scheduled heartbeat" }
|
|
234
378
|
};
|
|
235
379
|
return msg;</pre>
|
|
236
|
-
<p>
|
|
380
|
+
<p>Job Scheduler commands use the native BullMQ v6 fields: <code>msg.schedulerId</code>, <code>msg.repeat.pattern</code>, optional <code>msg.repeat.tz</code>, and <code>msg.template</code>.</p>
|
|
381
|
+
<p>BullMQ v6 removed the <code>paused</code> job state, so <code>getJobCounts</code> no longer includes a <code>paused</code> key in its result.</p>
|
|
237
382
|
</script>
|
|
238
383
|
|
|
239
384
|
<script type="text/javascript">
|
|
240
|
-
RED.nodes.registerType("
|
|
385
|
+
RED.nodes.registerType("bullmq cmd", {
|
|
241
386
|
color: "#ffffff",
|
|
242
387
|
category: "function",
|
|
243
388
|
defaults: {
|
|
244
389
|
name: { value: "" },
|
|
245
|
-
queue: { type: "
|
|
390
|
+
queue: { type: "bullmq-queue-server", required: true }
|
|
246
391
|
},
|
|
247
392
|
inputs: 1,
|
|
248
393
|
outputs: 1,
|
|
249
394
|
align: "right",
|
|
250
395
|
icon: "bull_icon.png",
|
|
251
396
|
label: function() {
|
|
252
|
-
return this.name || "
|
|
397
|
+
return this.name || "bullmq cmd";
|
|
253
398
|
}
|
|
254
399
|
});
|
|
255
400
|
</script>
|
|
256
401
|
|
|
257
|
-
<script type="text/html" data-template-name="
|
|
402
|
+
<script type="text/html" data-template-name="bullmq run">
|
|
258
403
|
<div class="form-row">
|
|
259
404
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
260
405
|
<input type="text" id="node-input-name">
|
|
@@ -276,7 +421,11 @@ return msg;</pre>
|
|
|
276
421
|
</div>
|
|
277
422
|
<div class="form-row">
|
|
278
423
|
<label for="node-input-concurrency"><i class="fa fa-random"></i> Concurrency</label>
|
|
279
|
-
<input type="number" id="node-input-concurrency" placeholder="1">
|
|
424
|
+
<input type="number" id="node-input-concurrency" min="1" step="1" placeholder="1">
|
|
425
|
+
</div>
|
|
426
|
+
<div class="form-row">
|
|
427
|
+
<label for="node-input-maxStartedAttempts"><i class="fa fa-repeat"></i> Max Started Attempts</label>
|
|
428
|
+
<input type="number" id="node-input-maxStartedAttempts" min="1" step="1" placeholder="100">
|
|
280
429
|
</div>
|
|
281
430
|
<div class="form-row">
|
|
282
431
|
<label for="node-input-limiterMax"><i class="fa fa-tachometer"></i> Limiter Max</label>
|
|
@@ -288,17 +437,18 @@ return msg;</pre>
|
|
|
288
437
|
</div>
|
|
289
438
|
</script>
|
|
290
439
|
|
|
291
|
-
<script type="text/html" data-help-name="
|
|
440
|
+
<script type="text/html" data-help-name="bullmq run">
|
|
292
441
|
<p>Creates a BullMQ Worker for the configured queue and emits each job as a Node-RED message.</p>
|
|
293
|
-
<p>API reference: <a href="https://
|
|
442
|
+
<p>API reference: <a href="https://docs.bullmq.io/api/classes/v6.Worker.html" target="_blank" rel="noopener noreferrer">Worker</a> and <a href="https://docs.bullmq.io/api/interfaces/v6.WorkerOptions.html" target="_blank" rel="noopener noreferrer">WorkerOptions</a>.</p>
|
|
294
443
|
|
|
295
444
|
<h3>Options</h3>
|
|
296
445
|
<ul>
|
|
297
446
|
<li><b>Name</b>: Optional label shown in the Node-RED workspace.</li>
|
|
298
447
|
<li><b>Queue</b>: Queue config node used by the worker.</li>
|
|
299
|
-
<li><b>Completion</b>: <code>Immediate</code> completes the BullMQ job after the message is emitted. <code>Manual acknowledgement</code> keeps the job active until a downstream <code>
|
|
448
|
+
<li><b>Completion</b>: <code>Immediate</code> completes the BullMQ job after the message is emitted. <code>Manual acknowledgement</code> keeps the job active until a downstream <code>bullmq job</code> node completes, fails, or updates it.</li>
|
|
300
449
|
<li><b>Ack Timeout</b>: Maximum time in milliseconds to wait for manual acknowledgement before the node fails the active job. Set to <code>0</code> to wait indefinitely.</li>
|
|
301
450
|
<li><b>Concurrency</b>: Number of jobs this worker can process at the same time.</li>
|
|
451
|
+
<li><b>Max Started Attempts</b>: Maximum times one job may start processing. Defaults to <code>100</code>. BullMQ then fails the job unrecoverably, which bounds loops created by repeated <code>moveToWait</code> or <code>moveToDelayed</code> actions.</li>
|
|
302
452
|
<li><b>Limiter Max</b>: Optional worker-side rate limit count.</li>
|
|
303
453
|
<li><b>Limiter Duration</b>: Optional worker-side rate limit window in milliseconds. Set with <b>Limiter Max</b>.</li>
|
|
304
454
|
</ul>
|
|
@@ -307,12 +457,15 @@ return msg;</pre>
|
|
|
307
457
|
<ul>
|
|
308
458
|
<li><code>msg.payload</code>: <code>job.data.payload</code> when present, otherwise the full BullMQ job data.</li>
|
|
309
459
|
<li><code>msg.job</code>: Serialized job metadata, including id, name, queue name, state-related timestamps, progress, attempts, and options.</li>
|
|
310
|
-
<li><code>msg.bull</code>: Queue and acknowledgement context used by downstream <code>
|
|
460
|
+
<li><code>msg.bull</code>: Queue and acknowledgement context used by downstream <code>bullmq job</code> nodes.</li>
|
|
311
461
|
</ul>
|
|
312
462
|
|
|
463
|
+
<p>BullMQ v6 removed the <code>paused</code> job state: <code>job.getState()</code> never returns <code>"paused"</code>, so a job on a paused queue reports as <code>"waiting"</code>.</p>
|
|
464
|
+
<p>Only jobs from a <b>Completion</b> <code>Manual acknowledgement</code> worker can be cancelled through <code>bullmq job</code>'s <code>cancelJob</code> and <code>cancelAllJobs</code> actions, since cancellation is scoped to <code>msg.bull.ackId</code>.</p>
|
|
465
|
+
|
|
313
466
|
<h3>Example</h3>
|
|
314
467
|
<p>For fire-and-forget processing, use <b>Completion</b> <code>Immediate</code> and wire the output to your processing flow.</p>
|
|
315
|
-
<p>For a flow that must decide success or failure, use <b>Completion</b> <code>Manual acknowledgement</code>, wire the output to processing nodes, then wire into <code>
|
|
468
|
+
<p>For a flow that must decide success or failure, use <b>Completion</b> <code>Manual acknowledgement</code>, wire the output to processing nodes, then wire into <code>bullmq job</code> with <b>Action</b> <code>complete</code> or <code>fail</code>.</p>
|
|
316
469
|
</script>
|
|
317
470
|
|
|
318
471
|
<script type="text/javascript">
|
|
@@ -337,15 +490,16 @@ return msg;</pre>
|
|
|
337
490
|
);
|
|
338
491
|
}
|
|
339
492
|
|
|
340
|
-
RED.nodes.registerType("
|
|
493
|
+
RED.nodes.registerType("bullmq run", {
|
|
341
494
|
color: "#ffffff",
|
|
342
495
|
category: "function",
|
|
343
496
|
defaults: {
|
|
344
497
|
name: { value: "" },
|
|
345
|
-
queue: { type: "
|
|
498
|
+
queue: { type: "bullmq-queue-server", required: true },
|
|
346
499
|
completionMode: { value: "immediate" },
|
|
347
500
|
ackTimeout: { value: 300000, validate: RED.validators.number() },
|
|
348
501
|
concurrency: { value: 1, validate: positiveInteger },
|
|
502
|
+
maxStartedAttempts: { value: 100, validate: positiveInteger },
|
|
349
503
|
limiterMax: {
|
|
350
504
|
value: "",
|
|
351
505
|
validate: function(value) {
|
|
@@ -364,7 +518,7 @@ return msg;</pre>
|
|
|
364
518
|
align: "left",
|
|
365
519
|
icon: "bull_icon.png",
|
|
366
520
|
label: function() {
|
|
367
|
-
return this.name || "
|
|
521
|
+
return this.name || "bullmq run";
|
|
368
522
|
},
|
|
369
523
|
oneditprepare: function() {
|
|
370
524
|
$("#node-input-completionMode").on("change", updateBullRunRows);
|
|
@@ -374,7 +528,7 @@ return msg;</pre>
|
|
|
374
528
|
})();
|
|
375
529
|
</script>
|
|
376
530
|
|
|
377
|
-
<script type="text/html" data-template-name="
|
|
531
|
+
<script type="text/html" data-template-name="bullmq job">
|
|
378
532
|
<div class="form-row">
|
|
379
533
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
380
534
|
<input type="text" id="node-input-name">
|
|
@@ -391,13 +545,18 @@ return msg;</pre>
|
|
|
391
545
|
<option value="getChildrenValues">Get children values</option>
|
|
392
546
|
<option value="getFailedChildrenValues">Get failed children values</option>
|
|
393
547
|
<option value="removeUnprocessedChildren">Remove unprocessed children</option>
|
|
548
|
+
<option value="cancelJob">Cancel job</option>
|
|
549
|
+
<option value="cancelAllJobs">Cancel all jobs</option>
|
|
550
|
+
<option value="moveToWait">Requeue (moveToWait)</option>
|
|
551
|
+
<option value="moveToDelayed">Delay and resume (moveToDelayed)</option>
|
|
552
|
+
<option value="updateData">Update job data</option>
|
|
394
553
|
</select>
|
|
395
554
|
</div>
|
|
396
555
|
</script>
|
|
397
556
|
|
|
398
|
-
<script type="text/html" data-help-name="
|
|
399
|
-
<p>Acts on an active job emitted by a manual-mode <code>
|
|
400
|
-
<p>API reference: <a href="https://
|
|
557
|
+
<script type="text/html" data-help-name="bullmq job">
|
|
558
|
+
<p>Acts on an active job emitted by a manual-mode <code>bullmq run</code> node.</p>
|
|
559
|
+
<p>API reference: <a href="https://docs.bullmq.io/api/classes/v6.Job.html" target="_blank" rel="noopener noreferrer">Job</a>, <a href="https://docs.bullmq.io/api/classes/v6.UnrecoverableError.html" target="_blank" rel="noopener noreferrer">UnrecoverableError</a>, and <a href="https://docs.bullmq.io/api/classes/v6.Worker.html#canceljob" target="_blank" rel="noopener noreferrer">Worker.cancelJob</a>.</p>
|
|
401
560
|
|
|
402
561
|
<h3>Options</h3>
|
|
403
562
|
<ul>
|
|
@@ -416,6 +575,11 @@ return msg;</pre>
|
|
|
416
575
|
<li><code>getChildrenValues</code>: Reads completed child return values for a flow parent job.</li>
|
|
417
576
|
<li><code>getFailedChildrenValues</code>: Reads failed child values for a flow parent job.</li>
|
|
418
577
|
<li><code>removeUnprocessedChildren</code>: Removes children that have not yet been processed.</li>
|
|
578
|
+
<li><code>cancelJob</code>: Cancels the active job by aborting its processor signal, which fails the job and lets the queue's normal attempts/backoff retry policy apply. Acknowledgement-scoped: it needs <code>msg.bull.ackId</code>, so it only reaches manual-completion jobs that have not yet settled. <code>msg.reason</code> sets the cancellation reason, default <code>"BullMQ job cancelled"</code>. Outputs <code>true</code> on <code>msg.payload</code>; if BullMQ reports no cancellable processor for the job, the node raises an error instead.</li>
|
|
579
|
+
<li><code>cancelAllJobs</code>: Cancels every active manual job on the same <code>bullmq run</code> node the same way as <code>cancelJob</code>. <code>msg.reason</code> sets the cancellation reason, default <code>"BullMQ job cancelled"</code>. Outputs <code>true</code> on <code>msg.payload</code>.</li>
|
|
580
|
+
<li><code>moveToWait</code>: Puts the active job back in the waiting state to be picked up again, without counting a failed attempt. Terminal for this acknowledgement.</li>
|
|
581
|
+
<li><code>moveToDelayed</code>: Delays the active job by <code>msg.delay</code> milliseconds and resumes it later, without counting a failed attempt. Terminal for this acknowledgement. Combine with <code>updateData</code> to resume from a recorded step.</li>
|
|
582
|
+
<li><code>updateData</code>: Replaces the job's stored data with <code>msg.jobData</code>, or <code>msg.payload</code> when that is absent, and survives a retry. Non-terminal, so the flow still has to settle the acknowledgement. Use it to record which step a job reached before <code>moveToDelayed</code>.</li>
|
|
419
583
|
</ul>
|
|
420
584
|
|
|
421
585
|
<h3>Example</h3>
|
|
@@ -423,7 +587,7 @@ return msg;</pre>
|
|
|
423
587
|
<pre>msg.cmd = "progress";
|
|
424
588
|
msg.progress = 50;
|
|
425
589
|
return msg;</pre>
|
|
426
|
-
<p>To use another <code>
|
|
590
|
+
<p>To use another <code>bullmq job</code> node with configured <b>Action</b> <code>complete</code>, pass the progress output through a Function node that removes the per-message override:</p>
|
|
427
591
|
<pre>delete msg.cmd;
|
|
428
592
|
msg.payload = { ok: true };
|
|
429
593
|
return msg;</pre>
|
|
@@ -431,11 +595,11 @@ return msg;</pre>
|
|
|
431
595
|
<pre>msg.cmd = "complete";
|
|
432
596
|
msg.payload = { ok: true };
|
|
433
597
|
return msg;</pre>
|
|
434
|
-
<p>The node uses the opaque <code>msg.bull.ackId</code> from <code>
|
|
598
|
+
<p>The node uses the opaque <code>msg.bull.ackId</code> from <code>bullmq run</code> and does not expose BullMQ lock tokens.</p>
|
|
435
599
|
</script>
|
|
436
600
|
|
|
437
601
|
<script type="text/javascript">
|
|
438
|
-
RED.nodes.registerType("
|
|
602
|
+
RED.nodes.registerType("bullmq job", {
|
|
439
603
|
color: "#ffffff",
|
|
440
604
|
category: "function",
|
|
441
605
|
defaults: {
|
|
@@ -447,12 +611,12 @@ return msg;</pre>
|
|
|
447
611
|
align: "right",
|
|
448
612
|
icon: "bull_icon.png",
|
|
449
613
|
label: function() {
|
|
450
|
-
return this.name || "
|
|
614
|
+
return this.name || "bullmq job";
|
|
451
615
|
}
|
|
452
616
|
});
|
|
453
617
|
</script>
|
|
454
618
|
|
|
455
|
-
<script type="text/html" data-template-name="
|
|
619
|
+
<script type="text/html" data-template-name="bullmq events">
|
|
456
620
|
<div class="form-row">
|
|
457
621
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
458
622
|
<input type="text" id="node-input-name">
|
|
@@ -467,16 +631,17 @@ return msg;</pre>
|
|
|
467
631
|
</div>
|
|
468
632
|
</script>
|
|
469
633
|
|
|
470
|
-
<script type="text/html" data-help-name="
|
|
634
|
+
<script type="text/html" data-help-name="bullmq events">
|
|
471
635
|
<p>Subscribes to BullMQ QueueEvents and emits global queue events as Node-RED messages.</p>
|
|
472
|
-
<p>API reference: <a href="https://
|
|
636
|
+
<p>API reference: <a href="https://docs.bullmq.io/api/classes/v6.QueueEvents.html" target="_blank" rel="noopener noreferrer">QueueEvents</a>.</p>
|
|
473
637
|
|
|
474
638
|
<h3>Options</h3>
|
|
475
639
|
<ul>
|
|
476
640
|
<li><b>Name</b>: Optional label shown in the Node-RED workspace.</li>
|
|
477
641
|
<li><b>Queue</b>: Queue config node whose global events will be observed.</li>
|
|
478
|
-
<li><b>Events</b>: Comma or newline separated event names. Leave empty to subscribe to the default set. Useful events include <code>completed</code>, <code>failed</code>, <code>progress</code>, <code>delayed</code>, <code>deduplicated</code>, <code>duplicated</code>, <code>waiting</code>, and <code>
|
|
642
|
+
<li><b>Events</b>: Comma or newline separated event names. Leave empty to subscribe to the default set. Useful events include <code>completed</code>, <code>failed</code>, <code>progress</code>, <code>delayed</code>, <code>deduplicated</code>, <code>duplicated</code>, <code>waiting</code>, <code>active</code>, and <code>retries-exhausted</code>.</li>
|
|
479
643
|
</ul>
|
|
644
|
+
<p><code>retries-exhausted</code> is part of the default event set. A flow that leaves <b>Events</b> empty now receives this event in addition to the previous defaults.</p>
|
|
480
645
|
|
|
481
646
|
<h3>Output message</h3>
|
|
482
647
|
<ul>
|
|
@@ -490,12 +655,12 @@ return msg;</pre>
|
|
|
490
655
|
</script>
|
|
491
656
|
|
|
492
657
|
<script type="text/javascript">
|
|
493
|
-
RED.nodes.registerType("
|
|
658
|
+
RED.nodes.registerType("bullmq events", {
|
|
494
659
|
color: "#ffffff",
|
|
495
660
|
category: "function",
|
|
496
661
|
defaults: {
|
|
497
662
|
name: { value: "" },
|
|
498
|
-
queue: { type: "
|
|
663
|
+
queue: { type: "bullmq-queue-server", required: true },
|
|
499
664
|
events: { value: "" }
|
|
500
665
|
},
|
|
501
666
|
inputs: 0,
|
|
@@ -503,12 +668,12 @@ return msg;</pre>
|
|
|
503
668
|
align: "left",
|
|
504
669
|
icon: "bull_icon.png",
|
|
505
670
|
label: function() {
|
|
506
|
-
return this.name || "
|
|
671
|
+
return this.name || "bullmq events";
|
|
507
672
|
}
|
|
508
673
|
});
|
|
509
674
|
</script>
|
|
510
675
|
|
|
511
|
-
<script type="text/html" data-template-name="
|
|
676
|
+
<script type="text/html" data-template-name="bullmq flow">
|
|
512
677
|
<div class="form-row">
|
|
513
678
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
514
679
|
<input type="text" id="node-input-name">
|
|
@@ -519,9 +684,9 @@ return msg;</pre>
|
|
|
519
684
|
</div>
|
|
520
685
|
</script>
|
|
521
686
|
|
|
522
|
-
<script type="text/html" data-help-name="
|
|
687
|
+
<script type="text/html" data-help-name="bullmq flow">
|
|
523
688
|
<p>Adds atomic BullMQ parent and child job trees with <code>FlowProducer</code>.</p>
|
|
524
|
-
<p>API reference: <a href="https://
|
|
689
|
+
<p>API reference: <a href="https://docs.bullmq.io/api/classes/v6.FlowProducer.html" target="_blank" rel="noopener noreferrer">FlowProducer</a> and <a href="https://docs.bullmq.io/api/types/v6.FlowJob.html" target="_blank" rel="noopener noreferrer">FlowJob</a>.</p>
|
|
525
690
|
|
|
526
691
|
<h3>Options</h3>
|
|
527
692
|
<ul>
|
|
@@ -531,10 +696,13 @@ return msg;</pre>
|
|
|
531
696
|
|
|
532
697
|
<h3>Input message</h3>
|
|
533
698
|
<ul>
|
|
534
|
-
<li><code>msg.payload</code>: BullMQ flow tree.
|
|
535
|
-
<li><code>msg.flowopts</code>: Optional FlowProducer options applied to
|
|
699
|
+
<li><code>msg.payload</code>: One BullMQ flow tree, or an array of independent root trees added atomically with <code>FlowProducer.addBulk</code>. A root object contains <code>name</code>, <code>queueName</code>, <code>data</code>, optional <code>opts</code>, and optional <code>children</code>.</li>
|
|
700
|
+
<li><code>msg.flowopts</code>: Optional FlowProducer options applied when adding one tree. It does not apply to an array.</li>
|
|
536
701
|
</ul>
|
|
537
702
|
|
|
703
|
+
<p>A child job without an explicit <code>opts.jobId</code> gets a UUID from BullMQ v6, not the incremental numeric id used before.</p>
|
|
704
|
+
<p>Use one tree for related parent/child jobs, including dependencies that span queues. Use an array only for independent root trees that must all be added or none added. On Redis Cluster, omit each flow job's <code>prefix</code> to use this node's prefix throughout. If prefixes are set per job, they must contain the same hash tag, and each worker must use its queue's exact prefix.</p>
|
|
705
|
+
|
|
538
706
|
<h3>Example</h3>
|
|
539
707
|
<pre>msg.payload = {
|
|
540
708
|
name: "parent-report",
|
|
@@ -549,23 +717,23 @@ return msg;</pre>
|
|
|
549
717
|
]
|
|
550
718
|
};
|
|
551
719
|
return msg;</pre>
|
|
552
|
-
<p>The child jobs are processed before the parent job. A parent can read child results with a manual-mode <code>
|
|
720
|
+
<p>The child jobs are processed before the parent job. A parent can read child results with a manual-mode <code>bullmq run</code> and a <code>bullmq job</code> action such as <code>getChildrenValues</code>.</p>
|
|
553
721
|
</script>
|
|
554
722
|
|
|
555
723
|
<script type="text/javascript">
|
|
556
|
-
RED.nodes.registerType("
|
|
724
|
+
RED.nodes.registerType("bullmq flow", {
|
|
557
725
|
color: "#ffffff",
|
|
558
726
|
category: "function",
|
|
559
727
|
defaults: {
|
|
560
728
|
name: { value: "" },
|
|
561
|
-
queue: { type: "
|
|
729
|
+
queue: { type: "bullmq-queue-server", required: true }
|
|
562
730
|
},
|
|
563
731
|
inputs: 1,
|
|
564
732
|
outputs: 1,
|
|
565
733
|
align: "right",
|
|
566
734
|
icon: "bull_icon.png",
|
|
567
735
|
label: function() {
|
|
568
|
-
return this.name || "
|
|
736
|
+
return this.name || "bullmq flow";
|
|
569
737
|
}
|
|
570
738
|
});
|
|
571
739
|
</script>
|