@blamejs/core 0.7.18 → 0.7.19
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/CHANGELOG.md +425 -423
- package/README.md +150 -150
- package/bin/blamejs.js +0 -0
- package/index.js +310 -308
- package/lib/api-key.js +660 -660
- package/lib/api-snapshot.js +338 -338
- package/lib/app-shutdown.js +385 -385
- package/lib/app.js +365 -365
- package/lib/archive.js +250 -250
- package/lib/atomic-file.js +544 -544
- package/lib/audit-chain.js +177 -177
- package/lib/audit-sign.js +344 -344
- package/lib/audit-tools.js +677 -677
- package/lib/audit.js +766 -766
- package/lib/auth/jwt-external.js +365 -0
- package/lib/auth/jwt.js +337 -311
- package/lib/auth/lockout.js +436 -436
- package/lib/auth/oauth.js +721 -721
- package/lib/auth/passkey.js +181 -181
- package/lib/auth/password.js +628 -594
- package/lib/backup/bundle.js +217 -217
- package/lib/backup/crypto.js +176 -176
- package/lib/backup/index.js +515 -515
- package/lib/backup/manifest.js +282 -282
- package/lib/break-glass.js +1338 -1338
- package/lib/bundler.js +441 -441
- package/lib/cache-redis.js +256 -256
- package/lib/cache.js +1206 -1206
- package/lib/canonical-json.js +115 -115
- package/lib/chain-writer.js +234 -234
- package/lib/cli-helpers.js +206 -206
- package/lib/cli.js +2334 -2334
- package/lib/cluster-provider-db.js +317 -317
- package/lib/cluster-storage.js +226 -226
- package/lib/cluster.js +703 -703
- package/lib/config-drift.js +301 -301
- package/lib/consent.js +222 -222
- package/lib/constants.js +191 -191
- package/lib/cookies.js +315 -315
- package/lib/credential-hash.js +322 -322
- package/lib/crypto.js +266 -266
- package/lib/csv.js +275 -275
- package/lib/db-declare-row-policy.js +267 -267
- package/lib/db-declare-view.js +420 -420
- package/lib/db-query.js +406 -406
- package/lib/db-schema.js +319 -319
- package/lib/db.js +1288 -1288
- package/lib/deprecate.js +222 -222
- package/lib/dev.js +335 -335
- package/lib/dual-control.js +473 -473
- package/lib/error-page.js +420 -420
- package/lib/external-db-migrate.js +441 -441
- package/lib/external-db.js +1061 -1061
- package/lib/file-type.js +273 -273
- package/lib/forms.js +422 -422
- package/lib/framework-error.js +293 -293
- package/lib/framework-schema.js +717 -717
- package/lib/handlers.js +350 -350
- package/lib/http-client-cookie-jar.js +508 -508
- package/lib/http-client.js +1195 -1195
- package/lib/i18n.js +878 -878
- package/lib/jobs.js +185 -185
- package/lib/log-stream-cloudwatch.js +369 -369
- package/lib/log-stream-local.js +146 -146
- package/lib/log-stream-otlp-grpc.js +410 -410
- package/lib/log-stream-otlp.js +286 -286
- package/lib/log-stream-syslog.js +302 -302
- package/lib/log-stream-webhook.js +199 -199
- package/lib/log-stream.js +330 -330
- package/lib/log.js +500 -500
- package/lib/mail-bounce.js +528 -528
- package/lib/mail-dkim.js +369 -369
- package/lib/mail.js +981 -981
- package/lib/metrics.js +683 -683
- package/lib/middleware/api-encrypt.js +936 -936
- package/lib/middleware/attach-user.js +157 -157
- package/lib/middleware/bearer-auth.js +152 -0
- package/lib/middleware/body-parser.js +1170 -1170
- package/lib/middleware/bot-guard.js +178 -178
- package/lib/middleware/compression.js +452 -452
- package/lib/middleware/cors.js +314 -314
- package/lib/middleware/csp-nonce.js +348 -348
- package/lib/middleware/csrf-protect.js +316 -316
- package/lib/middleware/db-role-for.js +264 -264
- package/lib/middleware/health.js +392 -392
- package/lib/middleware/index.js +82 -79
- package/lib/middleware/rate-limit.js +358 -358
- package/lib/middleware/request-id.js +61 -61
- package/lib/middleware/request-log.js +168 -168
- package/lib/middleware/require-auth.js +104 -104
- package/lib/middleware/security-headers.js +116 -116
- package/lib/middleware/sse.js +166 -166
- package/lib/migrations.js +383 -383
- package/lib/mtls-ca.js +518 -518
- package/lib/mtls-engine-default.js +481 -481
- package/lib/network-dns.js +632 -632
- package/lib/network-heartbeat.js +290 -290
- package/lib/network-nts.js +574 -574
- package/lib/network-proxy.js +265 -265
- package/lib/network-tls.js +328 -328
- package/lib/network.js +233 -233
- package/lib/notify.js +612 -612
- package/lib/ntp-check.js +229 -229
- package/lib/numeric-bounds.js +111 -111
- package/lib/object-store/azure-blob-bucket-ops.js +349 -349
- package/lib/object-store/azure-blob.js +488 -488
- package/lib/object-store/gcs-bucket-ops.js +351 -351
- package/lib/object-store/gcs.js +519 -519
- package/lib/object-store/http-put.js +153 -153
- package/lib/object-store/index.js +197 -197
- package/lib/object-store/sigv4-bucket-ops.js +1092 -1092
- package/lib/object-store/sigv4.js +903 -903
- package/lib/observability.js +151 -151
- package/lib/otel-export.js +269 -269
- package/lib/pagination.js +464 -464
- package/lib/parsers/index.js +80 -80
- package/lib/parsers/safe-env.js +642 -642
- package/lib/parsers/safe-ini.js +292 -292
- package/lib/parsers/safe-toml.js +784 -784
- package/lib/parsers/safe-xml.js +390 -390
- package/lib/parsers/safe-yaml.js +1015 -1015
- package/lib/permissions.js +708 -708
- package/lib/pqc-agent.js +87 -87
- package/lib/pqc-gate.js +279 -279
- package/lib/protobuf-encoder.js +190 -190
- package/lib/protocol-dispatcher.js +161 -161
- package/lib/pubsub-redis.js +167 -167
- package/lib/pubsub.js +429 -429
- package/lib/queue-local.js +476 -476
- package/lib/queue-redis.js +745 -745
- package/lib/queue-sqs.js +319 -319
- package/lib/queue.js +695 -695
- package/lib/redis-client.js +519 -519
- package/lib/request-helpers.js +340 -340
- package/lib/restore-bundle.js +237 -237
- package/lib/restore-rollback.js +259 -259
- package/lib/restore.js +409 -409
- package/lib/retry.js +376 -376
- package/lib/router.js +748 -748
- package/lib/safe-async.js +735 -735
- package/lib/safe-buffer.js +237 -237
- package/lib/safe-json.js +541 -541
- package/lib/safe-schema.js +1266 -1266
- package/lib/safe-url.js +159 -159
- package/lib/scheduler.js +706 -706
- package/lib/security-assert.js +373 -373
- package/lib/seeders.js +618 -618
- package/lib/session.js +535 -478
- package/lib/slug.js +269 -269
- package/lib/ssrf-guard.js +401 -401
- package/lib/storage.js +471 -471
- package/lib/subject.js +281 -281
- package/lib/template.js +791 -791
- package/lib/testing.js +798 -798
- package/lib/time.js +310 -310
- package/lib/totp.js +302 -302
- package/lib/tracing.js +494 -494
- package/lib/uuid.js +132 -132
- package/lib/validate-opts.js +340 -340
- package/lib/vault/index.js +308 -308
- package/lib/vault/rotate.js +784 -784
- package/lib/vault/wrap.js +296 -296
- package/lib/vendor/noble-ciphers.cjs +9 -9
- package/lib/webhook.js +595 -595
- package/lib/websocket.js +1048 -1048
- package/package.json +77 -77
- package/sbom.cyclonedx.json +7 -7
package/lib/jobs.js
CHANGED
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* jobs — name → handler registry on top of lib/queue.
|
|
4
|
-
*
|
|
5
|
-
* lib/queue handles dispatch (queue backend + lease + retry + breaker
|
|
6
|
-
* + audit emit). lib/jobs is the application-level pattern most apps
|
|
7
|
-
* actually use: register a handler ahead of time, enqueue by name,
|
|
8
|
-
* the framework runs the right code without per-call wiring.
|
|
9
|
-
*
|
|
10
|
-
* var jobs = b.jobs.create();
|
|
11
|
-
* jobs.define("send-welcome", async function ({ userId }) { … });
|
|
12
|
-
* jobs.define("rebuild-index", async function () { … });
|
|
13
|
-
*
|
|
14
|
-
* await jobs.enqueue("send-welcome", { userId: "u-1" });
|
|
15
|
-
*
|
|
16
|
-
* await jobs.start(); // consumers running
|
|
17
|
-
* …
|
|
18
|
-
* await jobs.shutdown(); // drain in-flight + stop consuming
|
|
19
|
-
*
|
|
20
|
-
* Each defined name maps to one queue (queue named after the job
|
|
21
|
-
* name) with one consumer per jobs instance. Operators wanting
|
|
22
|
-
* higher concurrency for a specific job pass concurrency in the
|
|
23
|
-
* define options.
|
|
24
|
-
*
|
|
25
|
-
* Built on b.queue, which must be initialized first:
|
|
26
|
-
*
|
|
27
|
-
* b.queue.init({ backends: { primary: { protocol: "local" } } });
|
|
28
|
-
* var jobs = b.jobs.create();
|
|
29
|
-
* jobs.define(...);
|
|
30
|
-
* await jobs.start();
|
|
31
|
-
*
|
|
32
|
-
* createApp wires this for you when opts.jobs is a function — the
|
|
33
|
-
* factory boots queue with the default 'local' backend, instantiates
|
|
34
|
-
* a jobs registry, calls opts.jobs(jobs) so the operator defines
|
|
35
|
-
* handlers, and starts consumption before listen().
|
|
36
|
-
*
|
|
37
|
-
* Public API:
|
|
38
|
-
*
|
|
39
|
-
* jobs.create(opts?) → instance
|
|
40
|
-
* opts.queueBackend — backend name to dispatch through
|
|
41
|
-
* (default 'primary' — the convention
|
|
42
|
-
* queue.init uses when given a
|
|
43
|
-
* single-backend config)
|
|
44
|
-
* opts.consumerDefaults — defaults forwarded to queue.consume
|
|
45
|
-
* ({ concurrency, leaseDurationMs,
|
|
46
|
-
* pollIntervalMs, fastPollMs })
|
|
47
|
-
* opts.allowUnregisteredEnqueue default false. When true, jobs.enqueue
|
|
48
|
-
* accepts names not yet defined
|
|
49
|
-
* (useful in test fixtures or for
|
|
50
|
-
* apps that expect lazy handler
|
|
51
|
-
* registration).
|
|
52
|
-
*
|
|
53
|
-
* jobs.define(name, handler, defineOpts?)
|
|
54
|
-
* handler signature: async function (job) { … } where job =
|
|
55
|
-
* { jobId, queueName, payload, attempts, maxAttempts, traceId,
|
|
56
|
-
* classification, enqueuedAt, leaseExpiresAt }.
|
|
57
|
-
* defineOpts is forwarded to queue.consume — concurrency etc.
|
|
58
|
-
* Throws if name is already defined.
|
|
59
|
-
*
|
|
60
|
-
* await jobs.enqueue(name, payload, enqueueOpts?)
|
|
61
|
-
* enqueueOpts is forwarded to queue.enqueue — delaySeconds,
|
|
62
|
-
* maxAttempts, traceId, classification.
|
|
63
|
-
* Returns { jobId, queueName, enqueuedAt, ... } from queue.enqueue.
|
|
64
|
-
*
|
|
65
|
-
* await jobs.start()
|
|
66
|
-
* Begins consuming each defined queue. Idempotent — a second
|
|
67
|
-
* start() is a no-op once consumers are already running.
|
|
68
|
-
*
|
|
69
|
-
* await jobs.shutdown(opts?)
|
|
70
|
-
* Stops consumers, drains in-flight via queue.shutdown.
|
|
71
|
-
* opts.timeoutMs forwards to queue.shutdown.
|
|
72
|
-
*
|
|
73
|
-
* jobs.stats()
|
|
74
|
-
* → { defined: [string], started: boolean }
|
|
75
|
-
*/
|
|
76
|
-
var { boot } = require("./log");
|
|
77
|
-
var queue = require("./queue");
|
|
78
|
-
var validateOpts = require("./validate-opts");
|
|
79
|
-
var { JobsError } = require("./framework-error");
|
|
80
|
-
|
|
81
|
-
var log = boot("jobs");
|
|
82
|
-
|
|
83
|
-
function create(opts) {
|
|
84
|
-
opts = opts || {};
|
|
85
|
-
validateOpts(opts, [
|
|
86
|
-
"queueBackend", "consumerDefaults", "allowUnregisteredEnqueue",
|
|
87
|
-
], "b.jobs");
|
|
88
|
-
var queueBackend = opts.queueBackend || "primary";
|
|
89
|
-
var consumerDefaults = opts.consumerDefaults || {};
|
|
90
|
-
var allowUnregistered = !!opts.allowUnregisteredEnqueue;
|
|
91
|
-
|
|
92
|
-
// name → { handler, defineOpts, consumerHandle (after start) }
|
|
93
|
-
var registry = new Map();
|
|
94
|
-
var started = false;
|
|
95
|
-
|
|
96
|
-
var _err = JobsError.factory;
|
|
97
|
-
|
|
98
|
-
function define(name, handler, defineOpts) {
|
|
99
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
100
|
-
throw _err("INVALID_NAME", "jobs.define: name must be a non-empty string", true);
|
|
101
|
-
}
|
|
102
|
-
if (typeof handler !== "function") {
|
|
103
|
-
throw _err("INVALID_HANDLER", "jobs.define: handler must be a function", true);
|
|
104
|
-
}
|
|
105
|
-
if (registry.has(name)) {
|
|
106
|
-
throw _err("DUPLICATE_NAME",
|
|
107
|
-
"jobs.define: '" + name + "' is already defined", true);
|
|
108
|
-
}
|
|
109
|
-
if (started) {
|
|
110
|
-
// Defining after start would mean the new handler doesn't run
|
|
111
|
-
// until the next start cycle. Reject loudly so operators don't
|
|
112
|
-
// wonder why their newly-defined handler is silent.
|
|
113
|
-
throw _err("ALREADY_STARTED",
|
|
114
|
-
"jobs.define: cannot register '" + name + "' after start() — " +
|
|
115
|
-
"define all handlers before calling start()", true);
|
|
116
|
-
}
|
|
117
|
-
registry.set(name, {
|
|
118
|
-
handler: handler,
|
|
119
|
-
defineOpts: defineOpts || {},
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async function enqueue(name, payload, enqueueOpts) {
|
|
124
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
125
|
-
throw _err("INVALID_NAME", "jobs.enqueue: name must be a non-empty string", true);
|
|
126
|
-
}
|
|
127
|
-
if (!allowUnregistered && !registry.has(name)) {
|
|
128
|
-
throw _err("UNDEFINED_NAME",
|
|
129
|
-
"jobs.enqueue: '" + name + "' has no registered handler. " +
|
|
130
|
-
"Either define(name, handler) first, or pass " +
|
|
131
|
-
"{ allowUnregisteredEnqueue: true } to jobs.create.", true);
|
|
132
|
-
}
|
|
133
|
-
return await queue.enqueue(name, payload, Object.assign(
|
|
134
|
-
{ backend: queueBackend },
|
|
135
|
-
enqueueOpts || {}
|
|
136
|
-
));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function start() {
|
|
140
|
-
if (started) return;
|
|
141
|
-
var consumerOpts = Object.assign({ backend: queueBackend }, consumerDefaults);
|
|
142
|
-
registry.forEach(function (entry, name) {
|
|
143
|
-
var perJobOpts = Object.assign({}, consumerOpts, entry.defineOpts);
|
|
144
|
-
entry.consumerHandle = queue.consume(name, entry.handler, perJobOpts);
|
|
145
|
-
});
|
|
146
|
-
started = true;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async function shutdown(shutdownOpts) {
|
|
150
|
-
if (!started) {
|
|
151
|
-
// Even when not started, queue.shutdown handles its own state.
|
|
152
|
-
try { await queue.shutdown(shutdownOpts); }
|
|
153
|
-
catch (e) { log.debug("shutdown-failed", { op: "queue.shutdown", error: e.message }); }
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
started = false;
|
|
157
|
-
await queue.shutdown(shutdownOpts);
|
|
158
|
-
// Don't clear the registry — operators inspecting stats() after
|
|
159
|
-
// shutdown should still see what was defined; only the running
|
|
160
|
-
// state changes.
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function stats() {
|
|
164
|
-
return {
|
|
165
|
-
defined: Array.from(registry.keys()),
|
|
166
|
-
started: started,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function _resetForTest() {
|
|
171
|
-
registry.clear();
|
|
172
|
-
started = false;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
define: define,
|
|
177
|
-
enqueue: enqueue,
|
|
178
|
-
start: start,
|
|
179
|
-
shutdown: shutdown,
|
|
180
|
-
stats: stats,
|
|
181
|
-
_resetForTest: _resetForTest,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
module.exports = { create: create };
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* jobs — name → handler registry on top of lib/queue.
|
|
4
|
+
*
|
|
5
|
+
* lib/queue handles dispatch (queue backend + lease + retry + breaker
|
|
6
|
+
* + audit emit). lib/jobs is the application-level pattern most apps
|
|
7
|
+
* actually use: register a handler ahead of time, enqueue by name,
|
|
8
|
+
* the framework runs the right code without per-call wiring.
|
|
9
|
+
*
|
|
10
|
+
* var jobs = b.jobs.create();
|
|
11
|
+
* jobs.define("send-welcome", async function ({ userId }) { … });
|
|
12
|
+
* jobs.define("rebuild-index", async function () { … });
|
|
13
|
+
*
|
|
14
|
+
* await jobs.enqueue("send-welcome", { userId: "u-1" });
|
|
15
|
+
*
|
|
16
|
+
* await jobs.start(); // consumers running
|
|
17
|
+
* …
|
|
18
|
+
* await jobs.shutdown(); // drain in-flight + stop consuming
|
|
19
|
+
*
|
|
20
|
+
* Each defined name maps to one queue (queue named after the job
|
|
21
|
+
* name) with one consumer per jobs instance. Operators wanting
|
|
22
|
+
* higher concurrency for a specific job pass concurrency in the
|
|
23
|
+
* define options.
|
|
24
|
+
*
|
|
25
|
+
* Built on b.queue, which must be initialized first:
|
|
26
|
+
*
|
|
27
|
+
* b.queue.init({ backends: { primary: { protocol: "local" } } });
|
|
28
|
+
* var jobs = b.jobs.create();
|
|
29
|
+
* jobs.define(...);
|
|
30
|
+
* await jobs.start();
|
|
31
|
+
*
|
|
32
|
+
* createApp wires this for you when opts.jobs is a function — the
|
|
33
|
+
* factory boots queue with the default 'local' backend, instantiates
|
|
34
|
+
* a jobs registry, calls opts.jobs(jobs) so the operator defines
|
|
35
|
+
* handlers, and starts consumption before listen().
|
|
36
|
+
*
|
|
37
|
+
* Public API:
|
|
38
|
+
*
|
|
39
|
+
* jobs.create(opts?) → instance
|
|
40
|
+
* opts.queueBackend — backend name to dispatch through
|
|
41
|
+
* (default 'primary' — the convention
|
|
42
|
+
* queue.init uses when given a
|
|
43
|
+
* single-backend config)
|
|
44
|
+
* opts.consumerDefaults — defaults forwarded to queue.consume
|
|
45
|
+
* ({ concurrency, leaseDurationMs,
|
|
46
|
+
* pollIntervalMs, fastPollMs })
|
|
47
|
+
* opts.allowUnregisteredEnqueue default false. When true, jobs.enqueue
|
|
48
|
+
* accepts names not yet defined
|
|
49
|
+
* (useful in test fixtures or for
|
|
50
|
+
* apps that expect lazy handler
|
|
51
|
+
* registration).
|
|
52
|
+
*
|
|
53
|
+
* jobs.define(name, handler, defineOpts?)
|
|
54
|
+
* handler signature: async function (job) { … } where job =
|
|
55
|
+
* { jobId, queueName, payload, attempts, maxAttempts, traceId,
|
|
56
|
+
* classification, enqueuedAt, leaseExpiresAt }.
|
|
57
|
+
* defineOpts is forwarded to queue.consume — concurrency etc.
|
|
58
|
+
* Throws if name is already defined.
|
|
59
|
+
*
|
|
60
|
+
* await jobs.enqueue(name, payload, enqueueOpts?)
|
|
61
|
+
* enqueueOpts is forwarded to queue.enqueue — delaySeconds,
|
|
62
|
+
* maxAttempts, traceId, classification.
|
|
63
|
+
* Returns { jobId, queueName, enqueuedAt, ... } from queue.enqueue.
|
|
64
|
+
*
|
|
65
|
+
* await jobs.start()
|
|
66
|
+
* Begins consuming each defined queue. Idempotent — a second
|
|
67
|
+
* start() is a no-op once consumers are already running.
|
|
68
|
+
*
|
|
69
|
+
* await jobs.shutdown(opts?)
|
|
70
|
+
* Stops consumers, drains in-flight via queue.shutdown.
|
|
71
|
+
* opts.timeoutMs forwards to queue.shutdown.
|
|
72
|
+
*
|
|
73
|
+
* jobs.stats()
|
|
74
|
+
* → { defined: [string], started: boolean }
|
|
75
|
+
*/
|
|
76
|
+
var { boot } = require("./log");
|
|
77
|
+
var queue = require("./queue");
|
|
78
|
+
var validateOpts = require("./validate-opts");
|
|
79
|
+
var { JobsError } = require("./framework-error");
|
|
80
|
+
|
|
81
|
+
var log = boot("jobs");
|
|
82
|
+
|
|
83
|
+
function create(opts) {
|
|
84
|
+
opts = opts || {};
|
|
85
|
+
validateOpts(opts, [
|
|
86
|
+
"queueBackend", "consumerDefaults", "allowUnregisteredEnqueue",
|
|
87
|
+
], "b.jobs");
|
|
88
|
+
var queueBackend = opts.queueBackend || "primary";
|
|
89
|
+
var consumerDefaults = opts.consumerDefaults || {};
|
|
90
|
+
var allowUnregistered = !!opts.allowUnregisteredEnqueue;
|
|
91
|
+
|
|
92
|
+
// name → { handler, defineOpts, consumerHandle (after start) }
|
|
93
|
+
var registry = new Map();
|
|
94
|
+
var started = false;
|
|
95
|
+
|
|
96
|
+
var _err = JobsError.factory;
|
|
97
|
+
|
|
98
|
+
function define(name, handler, defineOpts) {
|
|
99
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
100
|
+
throw _err("INVALID_NAME", "jobs.define: name must be a non-empty string", true);
|
|
101
|
+
}
|
|
102
|
+
if (typeof handler !== "function") {
|
|
103
|
+
throw _err("INVALID_HANDLER", "jobs.define: handler must be a function", true);
|
|
104
|
+
}
|
|
105
|
+
if (registry.has(name)) {
|
|
106
|
+
throw _err("DUPLICATE_NAME",
|
|
107
|
+
"jobs.define: '" + name + "' is already defined", true);
|
|
108
|
+
}
|
|
109
|
+
if (started) {
|
|
110
|
+
// Defining after start would mean the new handler doesn't run
|
|
111
|
+
// until the next start cycle. Reject loudly so operators don't
|
|
112
|
+
// wonder why their newly-defined handler is silent.
|
|
113
|
+
throw _err("ALREADY_STARTED",
|
|
114
|
+
"jobs.define: cannot register '" + name + "' after start() — " +
|
|
115
|
+
"define all handlers before calling start()", true);
|
|
116
|
+
}
|
|
117
|
+
registry.set(name, {
|
|
118
|
+
handler: handler,
|
|
119
|
+
defineOpts: defineOpts || {},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function enqueue(name, payload, enqueueOpts) {
|
|
124
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
125
|
+
throw _err("INVALID_NAME", "jobs.enqueue: name must be a non-empty string", true);
|
|
126
|
+
}
|
|
127
|
+
if (!allowUnregistered && !registry.has(name)) {
|
|
128
|
+
throw _err("UNDEFINED_NAME",
|
|
129
|
+
"jobs.enqueue: '" + name + "' has no registered handler. " +
|
|
130
|
+
"Either define(name, handler) first, or pass " +
|
|
131
|
+
"{ allowUnregisteredEnqueue: true } to jobs.create.", true);
|
|
132
|
+
}
|
|
133
|
+
return await queue.enqueue(name, payload, Object.assign(
|
|
134
|
+
{ backend: queueBackend },
|
|
135
|
+
enqueueOpts || {}
|
|
136
|
+
));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function start() {
|
|
140
|
+
if (started) return;
|
|
141
|
+
var consumerOpts = Object.assign({ backend: queueBackend }, consumerDefaults);
|
|
142
|
+
registry.forEach(function (entry, name) {
|
|
143
|
+
var perJobOpts = Object.assign({}, consumerOpts, entry.defineOpts);
|
|
144
|
+
entry.consumerHandle = queue.consume(name, entry.handler, perJobOpts);
|
|
145
|
+
});
|
|
146
|
+
started = true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function shutdown(shutdownOpts) {
|
|
150
|
+
if (!started) {
|
|
151
|
+
// Even when not started, queue.shutdown handles its own state.
|
|
152
|
+
try { await queue.shutdown(shutdownOpts); }
|
|
153
|
+
catch (e) { log.debug("shutdown-failed", { op: "queue.shutdown", error: e.message }); }
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
started = false;
|
|
157
|
+
await queue.shutdown(shutdownOpts);
|
|
158
|
+
// Don't clear the registry — operators inspecting stats() after
|
|
159
|
+
// shutdown should still see what was defined; only the running
|
|
160
|
+
// state changes.
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function stats() {
|
|
164
|
+
return {
|
|
165
|
+
defined: Array.from(registry.keys()),
|
|
166
|
+
started: started,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function _resetForTest() {
|
|
171
|
+
registry.clear();
|
|
172
|
+
started = false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
define: define,
|
|
177
|
+
enqueue: enqueue,
|
|
178
|
+
start: start,
|
|
179
|
+
shutdown: shutdown,
|
|
180
|
+
stats: stats,
|
|
181
|
+
_resetForTest: _resetForTest,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = { create: create };
|