@c9up/bay 0.1.11 → 0.1.13
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 +66 -1
- package/dist/BayProvider.d.ts +24 -30
- package/dist/BayProvider.d.ts.map +1 -1
- package/dist/BayProvider.js +58 -9
- package/dist/BayProvider.js.map +1 -1
- package/dist/QueueManager.d.ts +7 -5
- package/dist/QueueManager.d.ts.map +1 -1
- package/dist/QueueManager.js +75 -31
- package/dist/QueueManager.js.map +1 -1
- package/dist/configure.d.ts +18 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +31 -0
- package/dist/configure.js.map +1 -0
- package/dist/drivers/RedisDriver.d.ts +6 -0
- package/dist/drivers/RedisDriver.d.ts.map +1 -1
- package/dist/drivers/RedisDriver.js +49 -17
- package/dist/drivers/RedisDriver.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/nodeEnv.d.ts +16 -0
- package/dist/nodeEnv.d.ts.map +1 -0
- package/dist/nodeEnv.js +32 -0
- package/dist/nodeEnv.js.map +1 -0
- package/dist/services/main.d.ts +5 -0
- package/dist/services/main.d.ts.map +1 -1
- package/dist/services/main.js +7 -0
- package/dist/services/main.js.map +1 -1
- package/dist/stores.d.ts +41 -0
- package/dist/stores.d.ts.map +1 -0
- package/dist/stores.js +46 -0
- package/dist/stores.js.map +1 -0
- package/package.json +5 -1
- package/src/BayProvider.ts +84 -19
- package/src/QueueManager.ts +77 -32
- package/src/configure.ts +45 -0
- package/src/drivers/RedisDriver.ts +69 -22
- package/src/index.ts +1 -0
- package/src/nodeEnv.ts +30 -0
- package/src/services/main.ts +8 -0
- package/src/stores.ts +59 -0
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* { PX: ms }) does NOT satisfy this interface and would drop the lease TTL — it
|
|
18
18
|
* needs a thin adapter.
|
|
19
19
|
*/
|
|
20
|
+
import { inProduction } from "../nodeEnv.js";
|
|
20
21
|
function isValidJob(obj) {
|
|
21
22
|
if (typeof obj !== "object" || obj === null)
|
|
22
23
|
return false;
|
|
@@ -33,13 +34,32 @@ function isValidJob(obj) {
|
|
|
33
34
|
* has no client to inspect yet.
|
|
34
35
|
*/
|
|
35
36
|
const warned = new WeakSet();
|
|
36
|
-
function
|
|
37
|
-
if (typeof client.lmove === "function"
|
|
37
|
+
function checkLmove(client, allowNonAtomicPop) {
|
|
38
|
+
if (typeof client.lmove === "function")
|
|
39
|
+
return;
|
|
40
|
+
// A queue's whole promise is that a job it accepted gets run. Without LMOVE
|
|
41
|
+
// the pop is `lpop` then `rpush`, and a crash between the two deletes the
|
|
42
|
+
// job from pending before it reaches processing: nothing recovers it,
|
|
43
|
+
// because nothing knows it existed. That is a different product, and in
|
|
44
|
+
// production it must be asked for rather than fallen into.
|
|
45
|
+
if (inProduction() && !allowNonAtomicPop) {
|
|
46
|
+
throw new Error("[bay] this Redis client has no LMOVE (Redis < 6.2), so pop() would be a non-atomic lpop+rpush — " +
|
|
47
|
+
"a crash between the two loses the in-flight job, turning at-least-once delivery into at-most-once.\n" +
|
|
48
|
+
" Upgrade to Redis 6.2 or later, or pass `allowNonAtomicPop: true` to state that losing a job is acceptable here.");
|
|
49
|
+
}
|
|
50
|
+
if (warned.has(client))
|
|
38
51
|
return;
|
|
39
52
|
warned.add(client);
|
|
53
|
+
// Said even when the deployment opted in: agreeing to lose a job once, in a
|
|
54
|
+
// config file, is not the same as being reminded that this process is
|
|
55
|
+
// running that way. The line has to be in the logs of the incident.
|
|
56
|
+
const optedIn = inProduction() && allowNonAtomicPop;
|
|
40
57
|
console.warn("[bay] RedisDriver: client lacks LMOVE (Redis <6.2). pop() falls back to " +
|
|
41
58
|
"a non-atomic lpop+rpush, downgrading delivery from at-least-once to " +
|
|
42
|
-
"at-most-once — a crash between the two commands loses the in-flight job."
|
|
59
|
+
"at-most-once — a crash between the two commands loses the in-flight job." +
|
|
60
|
+
(optedIn
|
|
61
|
+
? "\n Running this way in PRODUCTION because allowNonAtomicPop was set."
|
|
62
|
+
: ""));
|
|
43
63
|
}
|
|
44
64
|
/**
|
|
45
65
|
* A key prefix that ends in a separator.
|
|
@@ -67,7 +87,7 @@ export class RedisDriver {
|
|
|
67
87
|
return this.#resolved;
|
|
68
88
|
if (typeof this.#source !== "function") {
|
|
69
89
|
this.#resolved = this.#source;
|
|
70
|
-
|
|
90
|
+
checkLmove(this.#resolved, this.#allowNonAtomicPop);
|
|
71
91
|
return this.#resolved;
|
|
72
92
|
}
|
|
73
93
|
if (!this.#pending) {
|
|
@@ -75,7 +95,7 @@ export class RedisDriver {
|
|
|
75
95
|
this.#pending = Promise.resolve(resolver())
|
|
76
96
|
.then((client) => {
|
|
77
97
|
this.#resolved = client;
|
|
78
|
-
|
|
98
|
+
checkLmove(client, this.#allowNonAtomicPop);
|
|
79
99
|
return client;
|
|
80
100
|
})
|
|
81
101
|
// Cleared on failure too. Clearing only on success left the
|
|
@@ -93,13 +113,15 @@ export class RedisDriver {
|
|
|
93
113
|
// A client handed in directly can be checked now, so the warning keeps
|
|
94
114
|
// landing at construction as it always did. A named connection has no
|
|
95
115
|
// client yet — it is checked when the connection resolves.
|
|
96
|
-
if (typeof source !== "function")
|
|
97
|
-
|
|
116
|
+
if (typeof source !== "function") {
|
|
117
|
+
checkLmove(source, options?.allowNonAtomicPop ?? false);
|
|
118
|
+
}
|
|
98
119
|
// Normalised rather than documented: every key is built by concatenation
|
|
99
120
|
// (`${prefix}pending`), so a prefix without a trailing separator yields
|
|
100
121
|
// "myapppending" — unreadable, and able to collide with a neighbouring
|
|
101
122
|
// prefix. Nothing warned, because nothing failed.
|
|
102
123
|
this.#prefix = withSeparator(options?.prefix ?? "queue:");
|
|
124
|
+
this.#allowNonAtomicPop = options?.allowNonAtomicPop ?? false;
|
|
103
125
|
const visibilityTimeout = options?.visibilityTimeoutMs ?? 30_000;
|
|
104
126
|
// A non-positive / non-integer timeout makes pop()'s `SET … PX <ms>` fail
|
|
105
127
|
// on a real Redis; the catch then removes the job from `processing` and
|
|
@@ -112,6 +134,7 @@ export class RedisDriver {
|
|
|
112
134
|
}
|
|
113
135
|
#pendingKey = () => `${this.#prefix}pending`;
|
|
114
136
|
#processingKey = () => `${this.#prefix}processing`;
|
|
137
|
+
#allowNonAtomicPop = false;
|
|
115
138
|
#failedKey = () => `${this.#prefix}failed`;
|
|
116
139
|
#leaseKey = (jobId) => `${this.#prefix}lease:${jobId}`;
|
|
117
140
|
async push(job) {
|
|
@@ -131,22 +154,31 @@ export class RedisDriver {
|
|
|
131
154
|
}
|
|
132
155
|
if (!raw)
|
|
133
156
|
return null;
|
|
157
|
+
// Only a payload that can never be run is purged. Everything past this
|
|
158
|
+
// point is a REAL job that already sits in `processing`, and deleting
|
|
159
|
+
// it there is the one thing that loses it for good: it is gone from
|
|
160
|
+
// pending too, and recoverStale() scans processing, so nothing would
|
|
161
|
+
// ever find it again.
|
|
162
|
+
let parsed;
|
|
134
163
|
try {
|
|
135
|
-
|
|
136
|
-
if (!isValidJob(parsed)) {
|
|
137
|
-
// Malformed payload — purge from `processing` so it can't sit
|
|
138
|
-
// there indefinitely as a poison pill. recoverStale() also
|
|
139
|
-
// catches survivors but pop()'s own move is the primary path.
|
|
140
|
-
await client.lrem(this.#processingKey(), 1, raw);
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
await client.set(this.#leaseKey(parsed.id), raw, "PX", String(this.#visibilityTimeout));
|
|
144
|
-
return parsed;
|
|
164
|
+
parsed = JSON.parse(raw);
|
|
145
165
|
}
|
|
146
166
|
catch {
|
|
167
|
+
// A poison pill: unparseable, and it would sit in processing
|
|
168
|
+
// forever blocking nothing but wasting every recovery pass.
|
|
169
|
+
await client.lrem(this.#processingKey(), 1, raw);
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
if (!isValidJob(parsed)) {
|
|
147
173
|
await client.lrem(this.#processingKey(), 1, raw);
|
|
148
174
|
return null;
|
|
149
175
|
}
|
|
176
|
+
// A lease that cannot be written is a transient Redis failure, not a
|
|
177
|
+
// bad job. The error propagates and the job STAYS in processing with
|
|
178
|
+
// no lease, which is precisely the state recoverStale() puts back in
|
|
179
|
+
// pending — so the delivery guarantee survives the blip.
|
|
180
|
+
await client.set(this.#leaseKey(parsed.id), raw, "PX", String(this.#visibilityTimeout));
|
|
181
|
+
return parsed;
|
|
150
182
|
}
|
|
151
183
|
async complete(job) {
|
|
152
184
|
const client = await this.#client();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedisDriver.js","sourceRoot":"","sources":["../../src/drivers/RedisDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"RedisDriver.js","sourceRoot":"","sources":["../../src/drivers/RedisDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAoB7C,SAAS,UAAU,CAAC,GAAY;IAC/B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,OAAO,CACN,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ;QACxB,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;QAC1B,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAC9B,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ;QACjC,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAC5B,CAAC;AACH,CAAC;AAYD;;;;GAIG;AACH,MAAM,MAAM,GAAG,IAAI,OAAO,EAAU,CAAC;AACrC,SAAS,UAAU,CAAC,MAAmB,EAAE,iBAA0B;IAClE,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,UAAU;QAAE,OAAO;IAE/C,4EAA4E;IAC5E,0EAA0E;IAC1E,sEAAsE;IACtE,wEAAwE;IACxE,2DAA2D;IAC3D,IAAI,YAAY,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACd,kGAAkG;YACjG,sGAAsG;YACtG,mHAAmH,CACpH,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO;IAC/B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEnB,4EAA4E;IAC5E,sEAAsE;IACtE,oEAAoE;IACpE,MAAM,OAAO,GAAG,YAAY,EAAE,IAAI,iBAAiB,CAAC;IACpD,OAAO,CAAC,IAAI,CACX,0EAA0E;QACzE,sEAAsE;QACtE,0EAA0E;QAC1E,CAAC,OAAO;YACP,CAAC,CAAC,uEAAuE;YACzE,CAAC,CAAC,EAAE,CAAC,CACP,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,MAAc;IACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACvC,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,CAAC;AACzD,CAAC;AAED,MAAM,OAAO,WAAW;IACvB,OAAO,CAAoB;IAC3B,SAAS,CAA0B;IACnC,QAAQ,CAAmC;IAC3C,OAAO,CAAS;IAChB,kBAAkB,CAAS;IAE3B;;;OAGG;IACH,KAAK,CAAC,OAAO;QACZ,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC;QAC1C,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC;YAC9B,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;YACpD,OAAO,IAAI,CAAC,SAAS,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;YAC9B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;iBACzC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBAChB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC;gBACxB,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBAC5C,OAAO,MAAM,CAAC;YACf,CAAC,CAAC;gBACF,4DAA4D;gBAC5D,8DAA8D;gBAC9D,+DAA+D;gBAC/D,8DAA8D;iBAC7D,OAAO,CAAC,GAAG,EAAE;gBACb,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED,YACC,MAAyB,EACzB,OASC;QAED,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,uEAAuE;QACvE,sEAAsE;QACtE,2DAA2D;QAC3D,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;YAClC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,iBAAiB,IAAI,KAAK,CAAC,CAAC;QACzD,CAAC;QACD,yEAAyE;QACzE,wEAAwE;QACxE,uEAAuE;QACvE,kDAAkD;QAClD,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,MAAM,IAAI,QAAQ,CAAC,CAAC;QAC1D,IAAI,CAAC,kBAAkB,GAAG,OAAO,EAAE,iBAAiB,IAAI,KAAK,CAAC;QAC9D,MAAM,iBAAiB,GAAG,OAAO,EAAE,mBAAmB,IAAI,MAAM,CAAC;QACjE,0EAA0E;QAC1E,wEAAwE;QACxE,2EAA2E;QAC3E,gBAAgB;QAChB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,IAAI,CAAC,EAAE,CAAC;YACpE,MAAM,IAAI,KAAK,CACd,8EAA8E,iBAAiB,EAAE,CACjG,CAAC;QACH,CAAC;QACD,IAAI,CAAC,kBAAkB,GAAG,iBAAiB,CAAC;IAC7C,CAAC;IAED,WAAW,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,SAAS,CAAC;IAC7C,cAAc,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,YAAY,CAAC;IACnD,kBAAkB,GAAG,KAAK,CAAC;IAC3B,UAAU,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,QAAQ,CAAC;IAC3C,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,SAAS,KAAK,EAAE,CAAC;IAE/D,KAAK,CAAC,IAAI,CAAC,GAAQ;QAClB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,GAAG;QACR,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,GAAG,GAAkB,IAAI,CAAC;QAE9B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CACvB,IAAI,CAAC,WAAW,EAAE,EAClB,IAAI,CAAC,cAAc,EAAE,EACrB,MAAM,EACN,OAAO,CACP,CAAC;QACH,CAAC;aAAM,CAAC;YACP,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YAC5C,IAAI,GAAG;gBAAE,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,uEAAuE;QACvE,sEAAsE;QACtE,oEAAoE;QACpE,qEAAqE;QACrE,sBAAsB;QACtB,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACR,6DAA6D;YAC7D,4DAA4D;YAC5D,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;YACjD,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;YACjD,OAAO,IAAI,CAAC;QACb,CAAC;QAED,qEAAqE;QACrE,qEAAqE;QACrE,qEAAqE;QACrE,yDAAyD;QACzD,MAAM,MAAM,CAAC,GAAG,CACf,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EACzB,GAAG,EACH,IAAI,EACJ,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAC/B,CAAC;QACF,OAAO,MAAM,CAAC;IACf,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAQ;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAQ,EAAE,KAAa;QACjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACzC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;QAClB,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;QACtB,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAQ;QACnB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACzC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;QACvB,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,YAAY;QACjB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrE,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACR,6DAA6D;gBAC7D,8CAA8C;gBAC9C,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;gBACjD,SAAS;YACV,CAAC;YACD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzB,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;gBACjD,SAAS;YACV,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1D,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACpB,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;gBACjD,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC;gBAC1B,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC/D,SAAS,EAAE,CAAC;YACb,CAAC;QACF,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,qBAAqB,CAAC,GAAQ;QACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACxD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;YACpE,IAAI,OAAO,GAAG,CAAC;gBAAE,OAAO;QACzB,CAAC;QACD,qEAAqE;QACrE,kEAAkE;QAClE,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACR,SAAS;YACV,CAAC;YACD,IAAI,UAAU,CAAC,MAAM,CAAC,IAAK,MAAyB,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC;gBACpE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;gBAClD,OAAO;YACR,CAAC;QACF,CAAC;IACF,CAAC;IAED,KAAK,CAAC,MAAM;QACX,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3D,OAAO,IAAI;aACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;gBACR,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAY,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,IAAI;QACT,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACxC,CAAC;CACD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type { RedisClient } from "./drivers/RedisDriver.js";
|
|
|
11
11
|
export { RedisDriver } from "./drivers/RedisDriver.js";
|
|
12
12
|
export type { Job, JobHandler, QueueDriver } from "./QueueManager.js";
|
|
13
13
|
export { QueueManager } from "./QueueManager.js";
|
|
14
|
+
export { type QueueStoreFactory, stores } from "./stores.js";
|
|
14
15
|
import type { BayProviderConfig } from "./BayProvider.js";
|
|
15
16
|
/**
|
|
16
17
|
* Author-time config helper for `config/queue.ts` — AdonisJS `defineConfig`
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,iBAAiB,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAEtE;AACD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
export { MemoryDriver } from "./drivers/MemoryDriver.js";
|
|
9
9
|
export { RedisDriver } from "./drivers/RedisDriver.js";
|
|
10
10
|
export { QueueManager } from "./QueueManager.js";
|
|
11
|
+
export { stores } from "./stores.js";
|
|
11
12
|
/**
|
|
12
13
|
* Author-time config helper for `config/queue.ts` — AdonisJS `defineConfig`
|
|
13
14
|
* parity. Identity at runtime; the generic preserves literal types for inference.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAA0B,MAAM,EAAE,MAAM,aAAa,CAAC;AAI7D;;;GAGG;AACH,MAAM,UAAU,YAAY,CAA8B,MAAS;IAClE,OAAO,MAAM,CAAC;AACf,CAAC;AACD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading `NODE_ENV`, with the aliases people actually set.
|
|
3
|
+
*
|
|
4
|
+
* `NODE_ENV=prod` is ordinary in a Dockerfile or a platform dashboard. Read
|
|
5
|
+
* verbatim it answers "not production" — and here that decides whether a queue
|
|
6
|
+
* silently accepts a delivery guarantee weaker than the one it advertises.
|
|
7
|
+
*
|
|
8
|
+
* Duplicated rather than imported: bay depends on no other package in this
|
|
9
|
+
* workspace, and a safety decision that only holds when an optional peer is
|
|
10
|
+
* installed is not a decision.
|
|
11
|
+
*/
|
|
12
|
+
/** The canonical name for whatever `NODE_ENV` holds. */
|
|
13
|
+
export declare function normalizeNodeEnv(value: string | undefined): string;
|
|
14
|
+
/** Whether this process is running in production, under any spelling. */
|
|
15
|
+
export declare function inProduction(): boolean;
|
|
16
|
+
//# sourceMappingURL=nodeEnv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeEnv.d.ts","sourceRoot":"","sources":["../src/nodeEnv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOlE;AAED,yEAAyE;AACzE,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
|
package/dist/nodeEnv.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading `NODE_ENV`, with the aliases people actually set.
|
|
3
|
+
*
|
|
4
|
+
* `NODE_ENV=prod` is ordinary in a Dockerfile or a platform dashboard. Read
|
|
5
|
+
* verbatim it answers "not production" — and here that decides whether a queue
|
|
6
|
+
* silently accepts a delivery guarantee weaker than the one it advertises.
|
|
7
|
+
*
|
|
8
|
+
* Duplicated rather than imported: bay depends on no other package in this
|
|
9
|
+
* workspace, and a safety decision that only holds when an optional peer is
|
|
10
|
+
* installed is not a decision.
|
|
11
|
+
*/
|
|
12
|
+
const DEV_ENVS = ["dev", "develop", "development"];
|
|
13
|
+
const PROD_ENVS = ["prod", "production"];
|
|
14
|
+
const TEST_ENVS = ["test", "testing"];
|
|
15
|
+
/** The canonical name for whatever `NODE_ENV` holds. */
|
|
16
|
+
export function normalizeNodeEnv(value) {
|
|
17
|
+
if (!value || typeof value !== "string")
|
|
18
|
+
return "unknown";
|
|
19
|
+
const env = value.toLowerCase();
|
|
20
|
+
if (DEV_ENVS.includes(env))
|
|
21
|
+
return "development";
|
|
22
|
+
if (PROD_ENVS.includes(env))
|
|
23
|
+
return "production";
|
|
24
|
+
if (TEST_ENVS.includes(env))
|
|
25
|
+
return "test";
|
|
26
|
+
return env;
|
|
27
|
+
}
|
|
28
|
+
/** Whether this process is running in production, under any spelling. */
|
|
29
|
+
export function inProduction() {
|
|
30
|
+
return normalizeNodeEnv(process.env.NODE_ENV) === "production";
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=nodeEnv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeEnv.js","sourceRoot":"","sources":["../src/nodeEnv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;AACnD,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AACzC,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAEtC,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAAC,KAAyB;IACzD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC1D,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAChC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,aAAa,CAAC;IACjD,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,YAAY,CAAC;IACjD,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC3C,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY;IAC3B,OAAO,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,YAAY,CAAC;AAChE,CAAC"}
|
package/dist/services/main.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ import type { QueueManager } from "../QueueManager.js";
|
|
|
17
17
|
export declare function setQueue(value: QueueManager): void;
|
|
18
18
|
/** @internal Read the singleton (or `undefined` pre-boot). */
|
|
19
19
|
export declare function getQueue(): QueueManager | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* @internal Release the singleton, so a shut-down application does not leave a
|
|
22
|
+
* dead queue reachable through `services/main`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function clearQueue(): void;
|
|
20
25
|
declare const queue: QueueManager;
|
|
21
26
|
export default queue;
|
|
22
27
|
//# sourceMappingURL=main.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAElD;AAED,8DAA8D;AAC9D,wBAAgB,QAAQ,IAAI,YAAY,GAAG,SAAS,CAEnD;AAED,QAAA,MAAM,KAAK,EAAE,YAoBX,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAElD;AAED,8DAA8D;AAC9D,wBAAgB,QAAQ,IAAI,YAAY,GAAG,SAAS,CAEnD;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,QAAA,MAAM,KAAK,EAAE,YAoBX,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
package/dist/services/main.js
CHANGED
|
@@ -21,6 +21,13 @@ export function setQueue(value) {
|
|
|
21
21
|
export function getQueue() {
|
|
22
22
|
return instance;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* @internal Release the singleton, so a shut-down application does not leave a
|
|
26
|
+
* dead queue reachable through `services/main`.
|
|
27
|
+
*/
|
|
28
|
+
export function clearQueue() {
|
|
29
|
+
instance = undefined;
|
|
30
|
+
}
|
|
24
31
|
const queue = new Proxy({}, {
|
|
25
32
|
get(_target, prop) {
|
|
26
33
|
// A module loader inspects what it imports before anyone uses it: it reads
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,IAAI,QAAkC,CAAC;AAEvC,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CAAC,KAAmB;IAC3C,QAAQ,GAAG,KAAK,CAAC;AAClB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,QAAQ;IACvB,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,MAAM,KAAK,GAAiB,IAAI,KAAK,CAAC,EAAkB,EAAE;IACzD,GAAG,CAAC,OAAO,EAAE,IAAI;QAChB,2EAA2E;QAC3E,0EAA0E;QAC1E,8DAA8D;QAC9D,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACjD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACd,sEAAsE;gBACrE,4DAA4D,CAC7D,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACpD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,CAAC;CACD,CAAC,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,IAAI,QAAkC,CAAC;AAEvC,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CAAC,KAAmB;IAC3C,QAAQ,GAAG,KAAK,CAAC;AAClB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,QAAQ;IACvB,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACzB,QAAQ,GAAG,SAAS,CAAC;AACtB,CAAC;AAED,MAAM,KAAK,GAAiB,IAAI,KAAK,CAAC,EAAkB,EAAE;IACzD,GAAG,CAAC,OAAO,EAAE,IAAI;QAChB,2EAA2E;QAC3E,0EAA0E;QAC1E,8DAA8D;QAC9D,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACjD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACd,sEAAsE;gBACrE,4DAA4D,CAC7D,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACpD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACnE,CAAC;CACD,CAAC,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
package/dist/stores.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The queue store factories a config file names — `{ default, stores }`.
|
|
3
|
+
*
|
|
4
|
+
* The shape AdonisJS gives a package with several backends and one selected:
|
|
5
|
+
* a `stores` namespace imported beside `defineConfig`, each entry that
|
|
6
|
+
* namespace's result, and the selection read from the environment. Bay had a
|
|
7
|
+
* single `driver: "memory"` and told everyone else to build the manager by
|
|
8
|
+
* hand, which meant Redis could not be reached from a config file at all.
|
|
9
|
+
*
|
|
10
|
+
* import { defineConfig, stores } from '@c9up/bay'
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* default: env.get('QUEUE_STORE'),
|
|
14
|
+
* stores: {
|
|
15
|
+
* memory: stores.memory(),
|
|
16
|
+
* redis: stores.redis({ connection: 'main' }),
|
|
17
|
+
* },
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* Factories are lazy: only the store an application actually uses is built, so
|
|
21
|
+
* naming a Redis queue in a config that runs in memory opens no connection.
|
|
22
|
+
*/
|
|
23
|
+
import type { RedisClientSource } from "./drivers/RedisDriver.js";
|
|
24
|
+
import type { QueueDriver } from "./QueueManager.js";
|
|
25
|
+
/** A driver, built on first use. */
|
|
26
|
+
export type QueueStoreFactory = () => QueueDriver;
|
|
27
|
+
export declare const stores: {
|
|
28
|
+
/** In memory. Jobs do not survive a restart — for tests and dev. */
|
|
29
|
+
memory(): QueueStoreFactory;
|
|
30
|
+
/**
|
|
31
|
+
* Redis. `connection` takes an ioredis-shaped client, a function answering
|
|
32
|
+
* one, or the NAME of a `@c9up/quasar` connection — the last resolved at
|
|
33
|
+
* first use, without bay importing quasar, which stays an optional peer.
|
|
34
|
+
*/
|
|
35
|
+
redis(options: {
|
|
36
|
+
connection: RedisClientSource | string;
|
|
37
|
+
prefix?: string;
|
|
38
|
+
visibilityTimeoutMs?: number;
|
|
39
|
+
}): QueueStoreFactory;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=stores.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../src/stores.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,oCAAoC;AACpC,MAAM,MAAM,iBAAiB,GAAG,MAAM,WAAW,CAAC;AAElD,eAAO,MAAM,MAAM;IAClB,oEAAoE;cAC1D,iBAAiB;IAI3B;;;;OAIG;mBACY;QACd,UAAU,EAAE,iBAAiB,GAAG,MAAM,CAAC;QACvC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC7B,GAAG,iBAAiB;CAWrB,CAAC"}
|
package/dist/stores.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The queue store factories a config file names — `{ default, stores }`.
|
|
3
|
+
*
|
|
4
|
+
* The shape AdonisJS gives a package with several backends and one selected:
|
|
5
|
+
* a `stores` namespace imported beside `defineConfig`, each entry that
|
|
6
|
+
* namespace's result, and the selection read from the environment. Bay had a
|
|
7
|
+
* single `driver: "memory"` and told everyone else to build the manager by
|
|
8
|
+
* hand, which meant Redis could not be reached from a config file at all.
|
|
9
|
+
*
|
|
10
|
+
* import { defineConfig, stores } from '@c9up/bay'
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* default: env.get('QUEUE_STORE'),
|
|
14
|
+
* stores: {
|
|
15
|
+
* memory: stores.memory(),
|
|
16
|
+
* redis: stores.redis({ connection: 'main' }),
|
|
17
|
+
* },
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* Factories are lazy: only the store an application actually uses is built, so
|
|
21
|
+
* naming a Redis queue in a config that runs in memory opens no connection.
|
|
22
|
+
*/
|
|
23
|
+
import { MemoryDriver } from "./drivers/MemoryDriver.js";
|
|
24
|
+
import { RedisDriver } from "./drivers/RedisDriver.js";
|
|
25
|
+
import { quasarConnection } from "./quasar.js";
|
|
26
|
+
export const stores = {
|
|
27
|
+
/** In memory. Jobs do not survive a restart — for tests and dev. */
|
|
28
|
+
memory() {
|
|
29
|
+
return () => new MemoryDriver();
|
|
30
|
+
},
|
|
31
|
+
/**
|
|
32
|
+
* Redis. `connection` takes an ioredis-shaped client, a function answering
|
|
33
|
+
* one, or the NAME of a `@c9up/quasar` connection — the last resolved at
|
|
34
|
+
* first use, without bay importing quasar, which stays an optional peer.
|
|
35
|
+
*/
|
|
36
|
+
redis(options) {
|
|
37
|
+
const source = typeof options.connection === "string"
|
|
38
|
+
? quasarConnection(options.connection)
|
|
39
|
+
: options.connection;
|
|
40
|
+
return () => new RedisDriver(source, {
|
|
41
|
+
prefix: options.prefix,
|
|
42
|
+
visibilityTimeoutMs: options.visibilityTimeoutMs,
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=stores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stores.js","sourceRoot":"","sources":["../src/stores.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAK/C,MAAM,CAAC,MAAM,MAAM,GAAG;IACrB,oEAAoE;IACpE,MAAM;QACL,OAAO,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAIL;QACA,MAAM,MAAM,GACX,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ;YACrC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC;YACtC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QACvB,OAAO,GAAG,EAAE,CACX,IAAI,WAAW,CAAC,MAAM,EAAE;YACvB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;SAChD,CAAC,CAAC;IACL,CAAC;CACD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c9up/bay",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Queue — pluggable job-queue contract with memory + Redis drivers for the Ream framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
"types": "./dist/BayProvider.d.ts",
|
|
16
16
|
"import": "./dist/BayProvider.js"
|
|
17
17
|
},
|
|
18
|
+
"./configure": {
|
|
19
|
+
"types": "./dist/configure.d.ts",
|
|
20
|
+
"import": "./dist/configure.js"
|
|
21
|
+
},
|
|
18
22
|
"./services/main": {
|
|
19
23
|
"types": "./dist/services/main.d.ts",
|
|
20
24
|
"import": "./dist/services/main.js"
|
package/src/BayProvider.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { MemoryDriver } from "./drivers/MemoryDriver.js";
|
|
2
|
+
import type { QueueDriver } from "./QueueManager.js";
|
|
2
3
|
import { QueueManager } from "./QueueManager.js";
|
|
3
|
-
import { setQueue } from "./services/main.js";
|
|
4
|
+
import { clearQueue, getQueue, setQueue } from "./services/main.js";
|
|
5
|
+
import type { QueueStoreFactory } from "./stores.js";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Slim, duck-typed host context — bay stays publishable without
|
|
@@ -22,14 +24,21 @@ export interface BayAppContext {
|
|
|
22
24
|
|
|
23
25
|
export interface BayProviderConfig {
|
|
24
26
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
*
|
|
27
|
+
* Which named store to use — a key of {@link stores}. Read from the
|
|
28
|
+
* environment in the generated config, so a deployment picks its queue
|
|
29
|
+
* backend without editing a file.
|
|
30
|
+
*/
|
|
31
|
+
default?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The queue stores this application can use, by name. Each is a factory
|
|
34
|
+
* from `stores.*`, built only when it is the one selected.
|
|
35
|
+
*/
|
|
36
|
+
stores?: Record<string, QueueStoreFactory>;
|
|
37
|
+
/**
|
|
38
|
+
* The single-store form, kept for configs written against it: only
|
|
39
|
+
* `"memory"` was ever accepted. Prefer `default` + `stores`, which is how a
|
|
40
|
+
* pluggable backend is configured everywhere else and what lets the
|
|
41
|
+
* environment choose.
|
|
33
42
|
*/
|
|
34
43
|
driver?: "memory";
|
|
35
44
|
}
|
|
@@ -56,31 +65,87 @@ export interface BayProviderConfig {
|
|
|
56
65
|
* queue.register('send-email', new SendEmailJob())
|
|
57
66
|
* await queue.dispatch('send-email', { to: 'user@example.com' })
|
|
58
67
|
*/
|
|
68
|
+
/**
|
|
69
|
+
* The driver the config asks for.
|
|
70
|
+
*
|
|
71
|
+
* `default` + `stores` first — the form an environment variable can steer. The
|
|
72
|
+
* `driver` key is the single-store form kept for configs written against it.
|
|
73
|
+
* Naming a store that does not exist throws rather than falling back to memory:
|
|
74
|
+
* an application that meant to queue in Redis and silently got an in-process
|
|
75
|
+
* queue would only find out when a restart dropped every pending job.
|
|
76
|
+
*/
|
|
77
|
+
function buildDriver(config: BayProviderConfig | undefined): QueueDriver {
|
|
78
|
+
const stores = config?.stores;
|
|
79
|
+
const name = config?.default;
|
|
80
|
+
|
|
81
|
+
if (stores && name !== undefined) {
|
|
82
|
+
const selected = stores[name];
|
|
83
|
+
if (!selected) {
|
|
84
|
+
const known = Object.keys(stores);
|
|
85
|
+
throw new Error(
|
|
86
|
+
`[bay] config.queue names the store '${name}', which is not in \`stores\`. ` +
|
|
87
|
+
(known.length > 0
|
|
88
|
+
? `Declared: ${known.join(", ")}.`
|
|
89
|
+
: "`stores` is empty — declare one with stores.memory() or stores.redis()."),
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return selected();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (stores && name === undefined) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"[bay] config.queue declares `stores` but no `default` naming which one to use. " +
|
|
98
|
+
`Set default to one of: ${Object.keys(stores).join(", ")}.`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const driverName = config?.driver ?? "memory";
|
|
103
|
+
if (driverName !== "memory") {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`[bay] Unsupported driver '${driverName}' — name it under \`stores\` instead: ` +
|
|
106
|
+
"stores: { redis: stores.redis({ connection: 'main' }) }.",
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return new MemoryDriver();
|
|
110
|
+
}
|
|
111
|
+
|
|
59
112
|
export default class BayProvider {
|
|
60
113
|
constructor(protected app: BayAppContext) {}
|
|
61
114
|
|
|
62
115
|
register(): void {
|
|
63
116
|
this.app.container.singleton(QueueManager, () => {
|
|
64
117
|
const config = this.app.config.get<BayProviderConfig>("queue");
|
|
65
|
-
|
|
66
|
-
if (driverName !== "memory") {
|
|
67
|
-
throw new Error(
|
|
68
|
-
`[bay] Unsupported driver '${driverName}' for default provider — ` +
|
|
69
|
-
"wire QueueManager yourself in start/queue.ts for non-memory drivers.",
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
return new QueueManager(new MemoryDriver());
|
|
118
|
+
return new QueueManager(buildDriver(config));
|
|
73
119
|
});
|
|
74
120
|
this.app.container.singleton("queue", () =>
|
|
75
121
|
this.app.container.resolve<QueueManager>(QueueManager),
|
|
76
122
|
);
|
|
77
123
|
}
|
|
78
124
|
|
|
125
|
+
/** The queue THIS provider booted — not whatever the module singleton holds. */
|
|
126
|
+
#queue: QueueManager | undefined;
|
|
127
|
+
|
|
79
128
|
async boot(): Promise<void> {
|
|
80
129
|
// Populate the `@c9up/bay/services/main` singleton so apps can
|
|
81
130
|
// `import queue from '@c9up/bay/services/main'` from anywhere.
|
|
82
|
-
|
|
131
|
+
this.#queue = await this.app.container.resolve<QueueManager>(QueueManager);
|
|
132
|
+
setQueue(this.#queue);
|
|
83
133
|
}
|
|
84
134
|
|
|
85
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Stop the worker the app started, and let the job in flight finish.
|
|
137
|
+
*
|
|
138
|
+
* A worker polls on a timer. Left running, it survives a dev reload, a test
|
|
139
|
+
* teardown and a SIGTERM — so the old process keeps pulling jobs the new
|
|
140
|
+
* one is also pulling, and the same job runs twice.
|
|
141
|
+
*/
|
|
142
|
+
async shutdown(): Promise<void> {
|
|
143
|
+
if (!this.#queue) return;
|
|
144
|
+
await this.#queue.stop();
|
|
145
|
+
// Two applications can share a process — parallel tests, a hot reload.
|
|
146
|
+
// The module singleton holds whichever booted last, so it is only ours
|
|
147
|
+
// to clear while it still points at the queue this provider booted.
|
|
148
|
+
if (getQueue() === this.#queue) clearQueue();
|
|
149
|
+
this.#queue = undefined;
|
|
150
|
+
}
|
|
86
151
|
}
|