@pauldeng/node-red-contrib-bullmq 1.0.2 → 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 +62 -42
- package/bull-queue.html +300 -91
- package/bull-queue.js +686 -143
- package/docs/ARCHITECTURE.md +63 -17
- package/docs/CHANGE_WORKFLOW.md +10 -11
- package/docs/COMMANDS.md +72 -11
- package/docs/CONNECTIONS.md +74 -7
- package/docs/MIGRATION.md +56 -22
- package/docs/NODE_GUIDE.md +52 -14
- package/docs/REFERENCE_MAP.md +29 -10
- package/docs/RELEASE.md +18 -5
- 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 +271 -48
- package/lib/scheduler.js +5 -74
- package/lib/serialization.js +1 -4
- package/package.json +25 -9
package/docs/REFERENCE_MAP.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
## Runtime
|
|
4
4
|
|
|
5
5
|
- `bull-queue.js`: Node-RED registration and runtime glue.
|
|
6
|
-
- `lib/connections.js`: Redis deployment normalization and ioredis descriptors.
|
|
7
|
-
- `lib/scheduler.js`:
|
|
8
|
-
- `lib/commands.js`: `
|
|
6
|
+
- `lib/connections.js`: backend selection, Redis deployment normalization and ioredis descriptors, and PostgreSQL pool configuration.
|
|
7
|
+
- `lib/scheduler.js`: BullMQ v6 Job Scheduler id handling and serialization.
|
|
8
|
+
- `lib/commands.js`: `bullmq cmd` dispatch.
|
|
9
9
|
- `lib/serialization.js`: message-safe BullMQ serialization.
|
|
10
|
-
- `lib/acknowledgements.js`: manual-acknowledgement registry for `
|
|
10
|
+
- `lib/acknowledgements.js`: manual-acknowledgement registry for `bullmq run`/`bullmq job`. Entries self-remove on settle.
|
|
11
11
|
|
|
12
12
|
## Editor
|
|
13
13
|
|
|
@@ -17,16 +17,26 @@
|
|
|
17
17
|
## Tests
|
|
18
18
|
|
|
19
19
|
- `test/package-contract.test.js`: dependency and runtime import contract.
|
|
20
|
-
- `test/connections.test.js`: Redis
|
|
21
|
-
- `test/scheduler.test.js`:
|
|
20
|
+
- `test/connections.test.js`: backend selection and Redis/PostgreSQL config normalization.
|
|
21
|
+
- `test/scheduler.test.js`: native Job Scheduler id and serialization contracts.
|
|
22
22
|
- `test/commands.test.js`: command dispatch behavior.
|
|
23
23
|
- `test/acknowledgements.test.js`: manual-acknowledgement registry lifecycle and leak prevention.
|
|
24
|
+
- `test/shutdown.test.js`: BullMQ/ioredis resource ownership, partial redeploy cleanup, and concurrent shutdown.
|
|
25
|
+
- `test/async-style.test.js`: bounded-close async implementation constraints.
|
|
24
26
|
- `test/node-red-registration.test.js`: Node-RED node type registration.
|
|
25
27
|
- `test/editor-contract.test.js`: static editor surface.
|
|
26
28
|
- `test/docs-contract.test.js`: required docs and examples.
|
|
29
|
+
- `test/serialization.test.js`: message-safe job serialization, including that no lock token escapes.
|
|
30
|
+
- `test/telemetry.test.js`: opt-in telemetry wiring, including the QueueEvents exclusion.
|
|
27
31
|
- `test/docker-matrix-contract.test.js`: Docker deployment fixture and runner contract.
|
|
28
|
-
- `test/
|
|
29
|
-
- `test/
|
|
32
|
+
- `test/redis-characterization.test.js`: pins the Redis descriptors and BullMQ options against backend-seam drift.
|
|
33
|
+
- `test/postgres-wiring.test.js`: PostgreSQL pool config, backend factory positions, and error categories.
|
|
34
|
+
- `test/integration-postgres.test.js`: opt-in PostgreSQL migrations, custom schema, and close behavior against a container.
|
|
35
|
+
- `test/integration-postgres-tls.test.js`: opt-in PostgreSQL TLS connection and `ssl` object shape.
|
|
36
|
+
- `test/integration-standalone.test.js`: opt-in local Redis/PostgreSQL Node-RED runtime flows, standing command/action coverage, schedulers, delayed jobs, events, and flow producer jobs.
|
|
37
|
+
- `test/integration-deployment.test.js`: opt-in external Redis/PostgreSQL deployment flow test used by Docker and MemoryDB.
|
|
38
|
+
- `test/helpers/stores.js`: local Redis/PostgreSQL integration fixtures and backend adapters.
|
|
39
|
+
- `test/playwright/editor.spec.js`: editor dialog behavior in a real Node-RED browser session.
|
|
30
40
|
|
|
31
41
|
## Deployment Test Fixtures
|
|
32
42
|
|
|
@@ -38,14 +48,23 @@
|
|
|
38
48
|
- `test/deployments/cluster-tls/`: Redis Cluster with TLS.
|
|
39
49
|
- `test/deployments/sentinel-auth/`: Redis Sentinel with data-node ACL auth.
|
|
40
50
|
- `test/deployments/sentinel-tls/`: Redis Sentinel with TLS for data-node and Sentinel connections.
|
|
51
|
+
- `test/deployments/postgres-plain/`: PostgreSQL without TLS.
|
|
52
|
+
- `test/deployments/postgres-tls/`: PostgreSQL with TLS.
|
|
41
53
|
- `test/deployments/tls-certs/`: local self-signed certificates for Docker TLS fixtures.
|
|
42
54
|
|
|
55
|
+
## Agent Docs
|
|
56
|
+
|
|
57
|
+
- `AGENTS.md`: entry point; `CLAUDE.md` imports it.
|
|
58
|
+
- `docs/RULES.md`: hard constraints.
|
|
59
|
+
- `docs/CHANGE_WORKFLOW.md`: change procedure.
|
|
60
|
+
|
|
43
61
|
## User Docs
|
|
44
62
|
|
|
45
63
|
- `README.md`: overview and installation.
|
|
46
64
|
- `docs/NODE_GUIDE.md`: node behavior.
|
|
47
65
|
- `docs/COMMANDS.md`: command reference.
|
|
48
|
-
- `docs/CONNECTIONS.md`: Redis
|
|
49
|
-
- `docs/
|
|
66
|
+
- `docs/CONNECTIONS.md`: Redis and PostgreSQL backends.
|
|
67
|
+
- `docs/TELEMETRY.md`: opt-in OpenTelemetry tracing and metrics.
|
|
68
|
+
- `docs/MIGRATION.md`: breaking upgrade from older package versions.
|
|
50
69
|
- `docs/TESTING.md`: verification plan.
|
|
51
70
|
- `docs/TROUBLESHOOTING.md`: operational issues.
|
package/docs/RELEASE.md
CHANGED
|
@@ -13,9 +13,11 @@ used here only for the one-time first publish.)
|
|
|
13
13
|
|
|
14
14
|
1. Confirm `package.json` has the intended `version` and the name `@pauldeng/node-red-contrib-bullmq`.
|
|
15
15
|
2. Confirm the GitHub repository is `https://github.com/pauldeng/node-red-contrib-bullmq`.
|
|
16
|
-
3. Confirm BullMQ is pinned to exactly `
|
|
17
|
-
4. Confirm no examples, docs, fixtures, or logs contain Redis, Sentinel, or
|
|
18
|
-
5.
|
|
16
|
+
3. Confirm BullMQ is pinned to exactly `6.3.1`.
|
|
17
|
+
4. Confirm no examples, docs, fixtures, or logs contain Redis, Sentinel, MemoryDB, or PostgreSQL secrets. A shipped example flow carries no password, CA, or client key at all.
|
|
18
|
+
5. Confirm `pg` is declared only as an optional peer dependency, never a dependency: it must stay uninstalled for Redis-only users.
|
|
19
|
+
6. Update `CHANGELOG.md` for the new version.
|
|
20
|
+
7. For a major version bump, confirm `CHANGELOG.md` names every breaking change and `docs/MIGRATION.md` covers the upgrade path before tagging.
|
|
19
21
|
|
|
20
22
|
## 2. Local verification
|
|
21
23
|
|
|
@@ -29,12 +31,23 @@ npm audit --omit=dev --audit-level=moderate
|
|
|
29
31
|
npm pack --dry-run # confirm the tarball is clean
|
|
30
32
|
```
|
|
31
33
|
|
|
32
|
-
For deployment changes, also run
|
|
34
|
+
For deployment changes, also run the Docker matrix, which covers the Redis
|
|
35
|
+
topologies plus the `postgres-plain` and `postgres-tls` fixtures:
|
|
33
36
|
|
|
34
37
|
```sh
|
|
35
38
|
npm run test:deployments
|
|
36
39
|
```
|
|
37
40
|
|
|
41
|
+
For backend changes, also run the live backend suites. `npm run test:integration`
|
|
42
|
+
covers both backends when Docker is available and reports a reason when it is
|
|
43
|
+
not; the PostgreSQL schema and TLS suites are separate:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm run test:integration
|
|
47
|
+
BULLMQ_INTEGRATION_POSTGRES=1 node --test test/integration-postgres.test.js
|
|
48
|
+
BULLMQ_INTEGRATION_POSTGRES=1 node --test test/integration-postgres-tls.test.js
|
|
49
|
+
```
|
|
50
|
+
|
|
38
51
|
MemoryDB verification is opt-in and environment-only:
|
|
39
52
|
|
|
40
53
|
```sh
|
|
@@ -56,7 +69,7 @@ Do these once, before the first release.
|
|
|
56
69
|
- [ ] **Branch ruleset** on `master` (Settings -> Rules -> Rulesets): require a pull request with at least one review, require the CI status checks to pass, block force pushes, restrict deletions. Optionally require linear history and signed commits.
|
|
57
70
|
- [ ] **Code security and analysis** (Settings): enable Dependabot alerts, Dependabot security updates, secret scanning, push protection, and private vulnerability reporting.
|
|
58
71
|
- [ ] **Workflow permissions** (Settings -> Actions -> General): set the default `GITHUB_TOKEN` to read-only.
|
|
59
|
-
- [ ] **CodeQL**:
|
|
72
|
+
- [ ] **CodeQL**: enable Code scanning "default setup" in the Security tab.
|
|
60
73
|
- [ ] **`release` environment** (Settings -> Environments -> New environment -> `release`): add yourself as a required reviewer so `publish.yml` waits for manual approval.
|
|
61
74
|
|
|
62
75
|
## 4. First publish (one time, manual)
|
package/docs/RULES.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Rules
|
|
2
|
+
|
|
3
|
+
Hard constraints. Each one exists because breaking it breaks a released contract, loses jobs, or leaks a secret. Everything not listed here is a normal judgment call.
|
|
4
|
+
|
|
5
|
+
## Public Surface
|
|
6
|
+
|
|
7
|
+
- Register only the BullMQ v6 node types: `bullmq-queue-server`, `bullmq cmd`, `bullmq run`, `bullmq job`, `bullmq events`, and `bullmq flow`.
|
|
8
|
+
- Accept only `msg.cmd` for command dispatch and only the native Job Scheduler command names and fields.
|
|
9
|
+
- `msg.cmd` dispatch maps to explicit BullMQ calls only. Never expose arbitrary method names through it.
|
|
10
|
+
- Record unsupported BullMQ behavior with a reason instead of silently omitting it.
|
|
11
|
+
|
|
12
|
+
## Dependencies
|
|
13
|
+
|
|
14
|
+
- BullMQ is pinned to an exact version. Do not widen the range; `package.json` holds the value and `test/package-contract.test.js` enforces it.
|
|
15
|
+
- Changing the BullMQ pin means re-verifying the connection-readiness and shutdown paths against BullMQ's own source, not just running the suite. Three separate defects in the v5 to v6 upgrade came from behavior invisible at the public API: `close()` and `disconnect()` both await a connection-ready promise that never settles while Redis is unreachable, `Worker.close()` clears its lock-renewal and stalled-check timers only after the step that hangs, and `increaseMaxListeners` computes `getMaxListeners() + n`, which turns an unlimited emitter into a cap of 3. The code that works around these is in `bull-queue.js` (`forceDisconnect`, `closeBudgetFor` — including the PostgreSQL budget beyond pg's connection timeout — and the config node's single backend watcher, which replaced a per-node listener budget) and `lib/connections.js` (`skipWaitingForReady`, Redis-only: `createPostgresBackend` never reads it); each carries a comment naming the measured behavior it depends on. Read those, then confirm they still hold.
|
|
16
|
+
- The shutdown escape hatch is tied to the **Redis adapter**, not to the pin alone: `forceDisconnect` reaches into `backend.connection._client` because `RedisQueueBackend` is the only installed backend exposing a raw handle. The PostgreSQL adapter needs a different answer and has one — no raw disconnect, and a close budget that outlasts pg's own connection timeout instead of capping below it. Hold both to the same standard: measured against a real unreachable server, commented with what was measured, and re-verified when the pin moves. What the suite proves automatically is the shape, not the wall-clock number: `test/shutdown.test.js` drives ten redeploys against a real local blackhole socket and asserts that the producer command rejects, that close outlives the Redis-only fast budget, and that no client socket survives (`process.getActiveResourcesInfo()`). It shortens `connectionTimeoutMillis` to do so, because ten full-length closes would be a hundred-second test. The full-length number is therefore a **manual** measurement, not a regression test: with the shipped 10-second `connectionTimeoutMillis`, `Queue`, `Worker`, `QueueEvents`, and `FlowProducer` each settled on their own in about 9.8 seconds against a blackholed server, leaving no active handles. Re-measure it by hand when the pin moves; a green suite does not re-confirm it.
|
|
17
|
+
- Do not reintroduce `bull` or `sprintf-js`.
|
|
18
|
+
- The runtime floor is Node.js 22.9 with Node-RED 5.x, for the published package and for local development alike.
|
|
19
|
+
|
|
20
|
+
## Secrets
|
|
21
|
+
|
|
22
|
+
- Credentials belong in Node-RED credentials or environment variables. Never in examples, docs, logs, fixtures, snapshots, or committed flows.
|
|
23
|
+
- Never commit real credentials, Redis or PostgreSQL passwords, MemoryDB endpoints, or production private keys. One sanctioned exception: the local self-signed certificates in `test/deployments/tls-certs/` are committed Docker-only fixtures that grant access to nothing.
|
|
24
|
+
- Editor credential fields must not export secrets into flow JSON.
|
|
25
|
+
- MemoryDB tests read credentials only from environment variables.
|
|
26
|
+
|
|
27
|
+
## Runtime Invariants
|
|
28
|
+
|
|
29
|
+
- Never put BullMQ lock tokens in a Node-RED message.
|
|
30
|
+
- Repeat scheduler lookup and removal use exact scheduler ids. Never substring-match scheduler keys, and never call the deprecated repeatable-job APIs.
|
|
31
|
+
- Cluster and MemoryDB deployments default their BullMQ prefix to `{bull}`. A custom prefix must contain a Redis hash tag; `lib/connections.js` rejects one that does not. Redis-only: `prefix` is a Redis key-namespacing concept and is never sent on the PostgreSQL path.
|
|
32
|
+
- Do not pass arbitrary ioredis options through messages or editor fields.
|
|
33
|
+
- Keep TLS certificate verification on by default. Disable it only for a controlled deployment that cannot be given a trusted CA.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Telemetry Guide
|
|
2
|
+
|
|
3
|
+
## What It Gives You
|
|
4
|
+
|
|
5
|
+
OpenTelemetry traces for producer, consumer, and internal BullMQ operations (`add`, `process`, `addFlow`, and similar) on Queue, Worker, and FlowProducer. Span names follow `{operation} {destination}`, where destination is normally the queue name (for example `process myQueue`, `addFlow myQueue`) but includes the job name for `add` (`add myQueue.myJobName`). Metrics are optional and separately switched.
|
|
6
|
+
|
|
7
|
+
Telemetry is off by default. With the master switch off, the word `telemetry` never reaches a BullMQ constructor and `bullmq-otel` is never required.
|
|
8
|
+
|
|
9
|
+
## Config Fields
|
|
10
|
+
|
|
11
|
+
`bullmq-queue-server` has three telemetry fields:
|
|
12
|
+
|
|
13
|
+
- `telemetry` (boolean, default `false`): master switch.
|
|
14
|
+
- `telemetryServiceName` (string, default `""`): used as both the tracer name and the meter name; falls back to the queue name when blank.
|
|
15
|
+
- `telemetryMetrics` (boolean, default `false`): sets `enableMetrics` on the telemetry client.
|
|
16
|
+
|
|
17
|
+
One telemetry client is built per config node; the Queue, Worker, and FlowProducer backed by that config node share it.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
`bullmq-otel` is an optional peer dependency, pinned to `>=2.0.0`. It is not installed automatically. Install it alongside Node-RED:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install bullmq-otel
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
If `telemetry` is enabled and `bullmq-otel` cannot be required, the node reports one `node.error` naming `npm install bullmq-otel` and keeps running untraced; jobs keep flowing either way.
|
|
28
|
+
|
|
29
|
+
## Host Requirements
|
|
30
|
+
|
|
31
|
+
This package does not own the OpenTelemetry SDK or an exporter. The host process registers the `TracerProvider` (and, for metrics, the `MeterProvider`) — for example via `NODE_OPTIONS` auto-instrumentation, or SDK setup in Node-RED's `settings.js`.
|
|
32
|
+
|
|
33
|
+
With nothing registered, the OpenTelemetry API no-ops. An enabled toggle without a configured host is harmless but exports nothing.
|
|
34
|
+
|
|
35
|
+
## Metrics
|
|
36
|
+
|
|
37
|
+
`telemetryMetrics` requires a `MeterProvider` registered _before_ the queue is first used — BullMQ reads it at telemetry-client construction time.
|
|
38
|
+
|
|
39
|
+
BullMQ emits:
|
|
40
|
+
|
|
41
|
+
- Counters, one per job state transition: `bullmq.jobs.completed`, `bullmq.jobs.failed`, `bullmq.jobs.delayed`, `bullmq.jobs.retried`, `bullmq.jobs.waiting`, `bullmq.jobs.waiting_children`. Attributes: `bullmq.queue.name`, `bullmq.job.name`, `bullmq.job.state`.
|
|
42
|
+
- Histogram `bullmq.job.duration` (milliseconds), recorded alongside the counter above whenever the job has a `processedOn` timestamp. Same attributes.
|
|
43
|
+
- Gauge `bullmq.queue.jobs`, the job count per state. Attributes: `bullmq.queue.name`, `bullmq.queue.jobs.state`. BullMQ only records this gauge when something calls `queue.recordJobCountsMetric()`; this package does not call it on a timer, so the gauge stays empty unless a host script invokes that method directly.
|
|
44
|
+
|
|
45
|
+
## `bullmq events` Is Not Traced
|
|
46
|
+
|
|
47
|
+
BullMQ 6.3.1 types `QueueEventsOptions` as `Omit<QueueBaseOptions, 'telemetry'>`. `QueueEvents` accepts no telemetry client at all, so `bullmq events` never emits spans or metrics regardless of the config-node toggles.
|
|
48
|
+
|
|
49
|
+
## Zero-Dependency Alternative
|
|
50
|
+
|
|
51
|
+
`msg.cmd` `exportPrometheusMetrics` (see `docs/COMMANDS.md`) needs no OpenTelemetry stack. Install nothing extra if Prometheus scraping is all you want.
|
|
52
|
+
|
|
53
|
+
## Security
|
|
54
|
+
|
|
55
|
+
Never put a secret in `telemetryServiceName` — it appears as an attribute on every span and every metric this package emits.
|
package/docs/TESTING.md
CHANGED
|
@@ -4,37 +4,48 @@
|
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
npm test
|
|
7
|
+
npm run format:check
|
|
7
8
|
```
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
`npm test` runs built-in `node:test` suites for package metadata, connection normalization, Job Scheduler commands, command dispatch, editor surface, registration, resource shutdown, async style, telemetry wiring, Docker fixture contracts, docs, and examples. The lifecycle checks live in `test/shutdown.test.js`; bounded-close implementation constraints live in `test/async-style.test.js`. `npm run format:check` runs Prettier. CI gates both on every pull request.
|
|
10
11
|
|
|
11
12
|
## Node-RED Runtime Tests
|
|
12
13
|
|
|
13
14
|
Use `node-red-node-test-helper` for flow-level tests. Runtime coverage should load actual Node-RED flows for:
|
|
14
15
|
|
|
15
|
-
- `
|
|
16
|
-
- `
|
|
17
|
-
- `
|
|
18
|
-
- `
|
|
19
|
-
- `
|
|
20
|
-
-
|
|
16
|
+
- `bullmq cmd` success and failure paths;
|
|
17
|
+
- `bullmq run` immediate and manual modes;
|
|
18
|
+
- `bullmq job` acknowledgement actions;
|
|
19
|
+
- `bullmq events`;
|
|
20
|
+
- `bullmq flow`;
|
|
21
|
+
- BullMQ v6 Job Scheduler commands.
|
|
21
22
|
|
|
22
|
-
The
|
|
23
|
+
The local Redis/PostgreSQL integration suite is opt-in:
|
|
23
24
|
|
|
24
25
|
```sh
|
|
25
26
|
npm run test:integration
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
It
|
|
29
|
+
It runs each backend-neutral flow against a temporary local `redis-server`
|
|
30
|
+
(falling back to a temporary Redis container) and a temporary PostgreSQL
|
|
31
|
+
container. When neither backend prerequisite is available, its tests are
|
|
32
|
+
reported as skipped with the reason rather than silently omitted.
|
|
33
|
+
It verifies:
|
|
29
34
|
|
|
30
|
-
- `
|
|
31
|
-
- manual `
|
|
32
|
-
-
|
|
35
|
+
- `bullmq cmd` add/run behavior;
|
|
36
|
+
- manual `bullmq run` acknowledgement through `bullmq job`;
|
|
37
|
+
- native Job Scheduler creation, lookup, and removal;
|
|
33
38
|
- delayed-job commands;
|
|
34
39
|
- priority listing and counts;
|
|
35
40
|
- global rate-limit commands;
|
|
36
|
-
-
|
|
37
|
-
- `
|
|
41
|
+
- every `msg.cmd` and `bullmq job` action, derived from their runtime switches;
|
|
42
|
+
- deduplication commands and `bullmq events` delivery;
|
|
43
|
+
- `bullmq flow` parent/child and bulk FlowProducer output;
|
|
44
|
+
- worker and producer recovery after Redis restarts;
|
|
45
|
+
- graceful Node-RED shutdown while a manual job is active;
|
|
46
|
+
- one-off delayed notification series and cron notification schedulers.
|
|
47
|
+
|
|
48
|
+
One test is explicitly Redis-only and says so in its name: the restart check, which stops and restarts the store process on the same port and waits on raw ioredis `ready` events. The PostgreSQL fixture is a container on a Docker-assigned port with no raw client to observe.
|
|
38
49
|
|
|
39
50
|
## Playwright
|
|
40
51
|
|
|
@@ -54,7 +65,8 @@ Use Docker for the topology matrix:
|
|
|
54
65
|
npm run test:deployments
|
|
55
66
|
```
|
|
56
67
|
|
|
57
|
-
The runner starts each fixture, waits for Redis readiness, runs
|
|
68
|
+
The runner starts each fixture, waits for Redis or PostgreSQL readiness, runs
|
|
69
|
+
`test/integration-deployment.test.js`, and removes volumes between deployments.
|
|
58
70
|
|
|
59
71
|
Current executable fixtures:
|
|
60
72
|
|
|
@@ -65,8 +77,10 @@ Current executable fixtures:
|
|
|
65
77
|
- `cluster-tls`: two-node Redis Cluster with TLS and BullMQ `{bull}` prefix coverage
|
|
66
78
|
- `sentinel-auth`: Redis master, two replicas, and three Sentinels with data-node ACL auth
|
|
67
79
|
- `sentinel-tls`: Redis master, two replicas, and three TLS-enabled Sentinels
|
|
80
|
+
- `postgres-plain`: PostgreSQL without TLS
|
|
81
|
+
- `postgres-tls`: PostgreSQL with the Docker-only self-signed TLS fixture
|
|
68
82
|
|
|
69
|
-
The shared deployment test proves Node-RED load,
|
|
83
|
+
The shared deployment test proves Node-RED load, credential-backed auth, add/run delivery, native scheduler creation/removal, absolute scheduler minute/second metadata, live cancellation retries and `cancelAllJobs`, and OpenTelemetry add/process spans plus completed/duration metrics. The Docker topology fixtures use local self-signed test certificates and disable certificate verification. The dedicated PostgreSQL TLS integration test verifies that certificate through the credential-backed CA field; MemoryDB covers verified TLS for Redis.
|
|
70
84
|
|
|
71
85
|
## AWS MemoryDB
|
|
72
86
|
|
package/docs/TROUBLESHOOTING.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Worker Does Not Receive Jobs
|
|
4
4
|
|
|
5
|
-
- Confirm `
|
|
6
|
-
- Confirm Redis is reachable from the Node-RED process.
|
|
5
|
+
- Confirm `bullmq run` uses the same `bullmq-queue-server` as `bullmq cmd`.
|
|
6
|
+
- Confirm the backend (Redis or PostgreSQL) is reachable from the Node-RED process.
|
|
7
7
|
- Confirm the queue name is correct.
|
|
8
8
|
- For scheduled jobs, BullMQ creates the next delayed job only as the previous scheduled job starts processing.
|
|
9
9
|
|
|
@@ -15,14 +15,53 @@ Use a BullMQ prefix with a Redis Cluster hash tag, such as `{bull}`. This keeps
|
|
|
15
15
|
|
|
16
16
|
MemoryDB is a Cluster deployment and normally requires TLS from an EC2/VPC client that can reach the endpoint. Use Cluster mode, TLS, ACL username/password, and a reachable VPC network path.
|
|
17
17
|
|
|
18
|
+
## `Cannot find module 'pg'`
|
|
19
|
+
|
|
20
|
+
The PostgreSQL backend needs the optional peer dependency: `npm install pg` in the Node-RED user directory, then redeploy. BullMQ loads `pg` while constructing the queue, so this is reported on first use rather than at load, once per config node.
|
|
21
|
+
|
|
22
|
+
## `PostgreSQL schema "bullmq" is not initialized`
|
|
23
|
+
|
|
24
|
+
The database has no BullMQ schema and this node was told not to create one. Either enable **Migrations** on the queue config node so it initialises the schema, or run BullMQ's PostgreSQL migrations against the database yourself before deploying. The node stays usable and reports the error rather than hanging.
|
|
25
|
+
|
|
26
|
+
## PostgreSQL Schema Version Mismatch
|
|
27
|
+
|
|
28
|
+
The schema was created by a different BullMQ major version. Upgrade this package to a release using the required BullMQ major; PostgreSQL schema downgrades are not supported.
|
|
29
|
+
|
|
30
|
+
## Unsupported PostgreSQL Version
|
|
31
|
+
|
|
32
|
+
BullMQ requires PostgreSQL 13 or newer, and recommends 14+. The server version is checked on connect, so this is reported before any job work rather than discovered mid-job.
|
|
33
|
+
|
|
34
|
+
## PostgreSQL Connections Exhausted
|
|
35
|
+
|
|
36
|
+
PostgreSQL has a server-wide `max_connections` ceiling, commonly 100, shared with every other client. There is one pool per BullMQ resource rather than one per config node; Worker and QueueEvents also hold one dedicated `LISTEN` connection each. A config node feeding `bullmq cmd`, `bullmq run`, `bullmq events`, and `bullmq flow` therefore costs up to 4 × **Pool Max** + 2 connections — 10 at the default — and many queues or many Node-RED instances multiply that. Raise `max_connections`, lower **Pool Max**, or put a pooler in front.
|
|
37
|
+
|
|
38
|
+
## PostgreSQL `timeout exceeded when trying to connect`
|
|
39
|
+
|
|
40
|
+
Two different causes share this message, because node-postgres uses one timeout for both. Either the server is unreachable, or the pool is full and the caller waited 10 seconds for a free connection. Suspect contention when the database is healthy. Raise **Pool Max** only after observing sustained pool waits; worker **Concurrency** does not require a one-to-one pool size because each operation releases its client. Re-check the total against `max_connections` after any increase.
|
|
41
|
+
|
|
42
|
+
## PostgreSQL Events Table Keeps Growing
|
|
43
|
+
|
|
44
|
+
Expected, and not fixable from here: BullMQ's PostgreSQL adapter ignores the `maxEvents` trim argument, so event rows accumulate for as long as the queue is used. Prune the table out of band if a flow relies on `bullmq events`.
|
|
45
|
+
|
|
18
46
|
## TLS Certificate Errors
|
|
19
47
|
|
|
20
|
-
Keep TLS verification enabled when possible. Provide the CA certificate or server name
|
|
48
|
+
Keep TLS verification enabled when possible. Provide the CA certificate or server name the deployment needs. On PostgreSQL, node-postgres takes the TLS server name from the connection host when that host is a hostname, so the server-name override only applies when the host is a literal IP address. Disable verification only for controlled deployments that cannot be configured with a trusted CA.
|
|
21
49
|
|
|
22
|
-
##
|
|
50
|
+
## Job Scheduler Is Not Found
|
|
23
51
|
|
|
24
|
-
|
|
52
|
+
Job Scheduler lookup uses exact ids. Pass the id used during creation in `msg.schedulerId`.
|
|
25
53
|
|
|
26
54
|
## Bull v4 Queue Data Missing After Upgrade
|
|
27
55
|
|
|
28
56
|
Bull v4 Redis data is not automatically migrated. Drain or retire old queues before switching production flows to BullMQ.
|
|
57
|
+
|
|
58
|
+
## Repeat Job Fires At The Wrong Hour
|
|
59
|
+
|
|
60
|
+
BullMQ v6 uses `msg.repeat.pattern` and optional `msg.repeat.tz` with `upsertJobScheduler`. Confirm the IANA timezone name and remove/recreate any scheduler created with the wrong timezone.
|
|
61
|
+
|
|
62
|
+
## `cancelJob` Says No Cancellable Processor
|
|
63
|
+
|
|
64
|
+
`cancelJob`/`cancelAllJobs` need the acknowledgement behind `msg.bull.ackId`, which only exists for a manual-mode job that has not yet settled. Two different failures look similar:
|
|
65
|
+
|
|
66
|
+
- No usable `ackId` at all — an immediate-mode job's output message never carries one, and reusing an `ackId` after its job already completed, failed, timed out, or was already cancelled fails the same way. This raises a missing/stale/already-settled acknowledgement error, not "no cancellable processor".
|
|
67
|
+
- `BullMQ found no cancellable processor for job <id>` — the `ackId` was still valid, but BullMQ was no longer tracking a cancellation signal for that job. BullMQ stops tracking a job the moment its processor promise settles, so this is a narrow race: the job completed, failed, or lost its lock between the worker sending the message and the cancel arriving. It is also what you would see if `bullmq run`'s processor were ever changed to take fewer than three parameters, because BullMQ only creates the per-job `AbortController` when the processor declares the signal argument.
|
package/examples/README.md
CHANGED
|
@@ -4,32 +4,60 @@ Import these files from the Node-RED editor with **Import > Clipboard**.
|
|
|
4
4
|
|
|
5
5
|
## `example_flow.json`
|
|
6
6
|
|
|
7
|
-
End-to-end
|
|
7
|
+
End-to-end BullMQ v6 flow for the `basecasts` queue. It includes a native Job Scheduler pattern, plus basic events, manual acknowledgement, and flow examples.
|
|
8
8
|
|
|
9
9
|
## `bullmq_features.json`
|
|
10
10
|
|
|
11
11
|
Small BullMQ feature examples that all use one local Redis queue config named `bullmq-features`.
|
|
12
12
|
|
|
13
13
|
- Delay: `delay: send later` sets `msg.jobopts.delay = 10000`.
|
|
14
|
+
- Delay batch: `delay: series of one-off jobs` sends `addBulk` jobs with increasing delays.
|
|
15
|
+
- Date-time batch: `delay: series at exact date-times` converts explicit ISO-8601 timestamps to delays. Replace the sample 2030 timestamps before running it.
|
|
14
16
|
- Priority: `priority: high priority` sets `msg.jobopts.priority = 1`.
|
|
15
17
|
- Deduplication: `dedupe: same job once` sets `msg.jobopts.deduplication.id` from `msg.payload`.
|
|
16
18
|
- Rate limit: `rate limit: 2 per second` sends `msg.cmd = "setGlobalRateLimit"` with `{ "max": 2, "duration": 1000 }`.
|
|
17
|
-
- Scheduler: `scheduler: every minute`
|
|
18
|
-
- Events: the `
|
|
19
|
-
- Manual acknowledgement: `manual ack worker` sends a job through `
|
|
20
|
-
-
|
|
19
|
+
- Scheduler: `scheduler: every minute` uses `upsertJobScheduler` with `msg.repeat.pattern`.
|
|
20
|
+
- Events: the `bullmq events` node emits completed, failed, delayed, deduplicated, duplicated, and progress events.
|
|
21
|
+
- Manual acknowledgement: `manual ack worker` sends a job through `bullmq job` progress and complete actions.
|
|
22
|
+
- Cancel: `cancel: stop running job` demonstrates BullMQ v6 cooperative cancellation on its own `bullmq-cancel` queue, with its own manual-mode worker. It is deliberately separate from the manual ack demo: a `cancelJob` node sharing that worker would cancel the very job the acknowledgement demo is completing.
|
|
23
|
+
- Metrics: `metrics: exportPrometheusMetrics` sends `msg.cmd = "exportPrometheusMetrics"` and returns a Prometheus-formatted string.
|
|
24
|
+
- Flow: `flow: parent plus child` sends a parent/child tree to `bullmq flow`.
|
|
21
25
|
|
|
22
26
|
Point `bullmq-features` at your Redis deployment before deploying the flow.
|
|
23
27
|
|
|
28
|
+
## `postgres_backend.json`
|
|
29
|
+
|
|
30
|
+
The same add/run flow on the PostgreSQL backend, for the `pgcasts` queue. It exists to show what changes when the backend does: only the queue config node.
|
|
31
|
+
|
|
32
|
+
- The config node sets `backend` to `postgres` with `database`, `username`, `schema`, `max` and `migrate`, and leaves the Redis-only fields (`deployment`, `db`, `clusterNodes`, `sentinels`, `prefix`) empty so switching the selector back to Redis needs no cleanup.
|
|
33
|
+
- `add order job` and `handle order` use exactly the same `msg.cmd`, job options and worker message shape as the Redis examples. Nothing in a producer or worker flow is backend-specific.
|
|
34
|
+
- Install `pg` first (`npm install pg`). It is an optional peer dependency, so a missing install is reported on first use with the command to run.
|
|
35
|
+
- Set the password on the config node before deploying; a shipped flow carries no credential.
|
|
36
|
+
|
|
37
|
+
## `scheduled_notifications.json`
|
|
38
|
+
|
|
39
|
+
Scheduling a series of user notifications on the `notifycasts` queue, and delivering each one to a worker. Both halves share one queue and one worker.
|
|
40
|
+
|
|
41
|
+
- `notify: schedule user series` builds one delayed job per notification from a per-user schedule of explicit ISO-8601 instants, and enqueues the whole series with a single `addBulk`. BullMQ delays in milliseconds rather than at an absolute time, so each instant is converted to a delay at enqueue time; an instant already in the past becomes a delay of `0` and is delivered immediately. Send your own schedule as `msg.payload` in the same shape -- the built-in sample dates are placeholders.
|
|
42
|
+
- Each job gets a `jobId` derived from the user, the notification type and the scheduled instant, so re-sending the same schedule cannot double-book a notification. The instant is used as epoch milliseconds and the parts joined with `-`, because BullMQ rejects a custom job id containing `:`.
|
|
43
|
+
- `notify: cron daily digest` sends `upsertJobScheduler` with a six-field cron `msg.repeat.pattern` (the leading field is seconds) and `msg.repeat.tz`, carrying the notification in `msg.template.data` so every generated job arrives with it.
|
|
44
|
+
- `notify: remove cron digest` sends `removeJobScheduler`. A Job Scheduler outlives a redeploy, so an example that creates one needs a way to remove it.
|
|
45
|
+
- `notification worker` is an immediate-mode `bullmq run` node; `deliver notification` reads the notification out of `msg.payload.message` and sets `msg.topic` to `userId/type`.
|
|
46
|
+
|
|
47
|
+
A delayed job's time is when it becomes _eligible_, not a guaranteed start: worker availability and concurrency still decide when it actually runs.
|
|
48
|
+
|
|
49
|
+
Point `notifycasts` at your Redis or PostgreSQL deployment before deploying the flow.
|
|
50
|
+
|
|
24
51
|
## `repeatable_jobs.json`
|
|
25
52
|
|
|
26
|
-
|
|
53
|
+
Native BullMQ v6 Job Scheduler commands for the `basecasts` queue.
|
|
27
54
|
|
|
28
|
-
- `
|
|
29
|
-
- `
|
|
30
|
-
- `
|
|
31
|
-
- `
|
|
32
|
-
- `
|
|
33
|
-
- `
|
|
55
|
+
- `scheduler: upsert basecasts job` sends `upsertJobScheduler` with `msg.schedulerId`, `msg.repeat.pattern`, `msg.repeat.tz`, and `msg.template`.
|
|
56
|
+
- `scheduler: upsert with timezone` demonstrates an IANA timezone in `msg.repeat.tz`.
|
|
57
|
+
- `scheduler: getJobSchedulers` lists Job Schedulers.
|
|
58
|
+
- `scheduler: getJobSchedulersCount` counts Job Schedulers.
|
|
59
|
+
- `scheduler: getJobScheduler` reads the exact scheduler id from `msg.payload` into `msg.schedulerId`.
|
|
60
|
+
- `scheduler: removeJobScheduler` removes that exact scheduler id.
|
|
61
|
+
- `scheduler: stopAndRemoveAllJobs` removes schedulers and cleans inactive jobs.
|
|
34
62
|
|
|
35
63
|
Use the add inject first, then inspect with get/count/get-by-key. Use remove-by-key for one scheduler or stopAndRemoveAllJobs for full cleanup.
|