@prsm/queue 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 +56 -15
- package/package.json +11 -21
- package/src/index.js +1 -0
- package/src/queue.js +271 -0
- package/types/index.d.ts +1 -0
- package/types/queue.d.ts +4759 -0
- package/dist/index.cjs +0 -290
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -77
- package/dist/index.d.ts +0 -77
- package/dist/index.js +0 -257
- package/dist/index.js.map +0 -1
package/dist/index.js
DELETED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
// src/queue.ts
|
|
2
|
-
import { createClient } from "redis";
|
|
3
|
-
import { EventEmitter } from "events";
|
|
4
|
-
import { randomUUID } from "crypto";
|
|
5
|
-
import ms from "@prsm/ms";
|
|
6
|
-
var Queue = class extends EventEmitter {
|
|
7
|
-
redis;
|
|
8
|
-
workerClients = [];
|
|
9
|
-
options;
|
|
10
|
-
handler;
|
|
11
|
-
workers = /* @__PURE__ */ new Map();
|
|
12
|
-
groupWorkers = /* @__PURE__ */ new Map();
|
|
13
|
-
cleanupTimer;
|
|
14
|
-
_ready;
|
|
15
|
-
_inFlight = 0;
|
|
16
|
-
_totalSettled = 0;
|
|
17
|
-
constructor(options = {}) {
|
|
18
|
-
super();
|
|
19
|
-
this.options = {
|
|
20
|
-
concurrency: options.concurrency ?? 1,
|
|
21
|
-
delay: ms(options.delay ?? 0),
|
|
22
|
-
timeout: ms(options.timeout ?? 0),
|
|
23
|
-
maxRetries: options.maxRetries ?? 3,
|
|
24
|
-
groups: {
|
|
25
|
-
concurrency: options.groups?.concurrency ?? options.concurrency ?? 1,
|
|
26
|
-
delay: ms(options.groups?.delay ?? options.delay ?? 0),
|
|
27
|
-
timeout: ms(options.groups?.timeout ?? options.timeout ?? 0),
|
|
28
|
-
maxRetries: options.groups?.maxRetries ?? options.maxRetries ?? 3
|
|
29
|
-
},
|
|
30
|
-
redisOptions: options.redisOptions ?? {},
|
|
31
|
-
cleanupInterval: options.cleanupInterval ?? 3e4
|
|
32
|
-
};
|
|
33
|
-
this.redis = createClient(this.options.redisOptions);
|
|
34
|
-
this.redis.on("error", () => {
|
|
35
|
-
});
|
|
36
|
-
this._ready = this.initializeRedis();
|
|
37
|
-
}
|
|
38
|
-
/** resolves when redis is connected and all workers are ready to accept tasks */
|
|
39
|
-
ready() {
|
|
40
|
-
return this._ready;
|
|
41
|
-
}
|
|
42
|
-
get inFlight() {
|
|
43
|
-
return this._inFlight;
|
|
44
|
-
}
|
|
45
|
-
/** register the handler that processes each task. only one handler per queue. */
|
|
46
|
-
process(handler) {
|
|
47
|
-
this.handler = handler;
|
|
48
|
-
}
|
|
49
|
-
/** push a task to the main queue. returns the task uuid. */
|
|
50
|
-
async push(payload) {
|
|
51
|
-
const task = {
|
|
52
|
-
uuid: randomUUID(),
|
|
53
|
-
payload,
|
|
54
|
-
createdAt: Date.now(),
|
|
55
|
-
attempts: 0
|
|
56
|
-
};
|
|
57
|
-
await this.redis.lPush("queue:tasks", JSON.stringify(task));
|
|
58
|
-
this.emit("new", { task });
|
|
59
|
-
return task.uuid;
|
|
60
|
-
}
|
|
61
|
-
/** returns a scoped pusher for a named group. each group gets its own worker pool, spun up on first push. */
|
|
62
|
-
group(key) {
|
|
63
|
-
return {
|
|
64
|
-
push: async (payload) => {
|
|
65
|
-
const task = {
|
|
66
|
-
uuid: randomUUID(),
|
|
67
|
-
payload,
|
|
68
|
-
createdAt: Date.now(),
|
|
69
|
-
groupKey: key,
|
|
70
|
-
attempts: 0
|
|
71
|
-
};
|
|
72
|
-
await this.redis.lPush(`queue:groups:${key}`, JSON.stringify(task));
|
|
73
|
-
this.emit("new", { task });
|
|
74
|
-
if (!this.groupWorkers.has(key)) {
|
|
75
|
-
this.groupWorkers.set(key, /* @__PURE__ */ new Map());
|
|
76
|
-
await this.startGroupWorkers(key);
|
|
77
|
-
}
|
|
78
|
-
return task.uuid;
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
async createWorkerClient() {
|
|
83
|
-
const client = this.redis.duplicate();
|
|
84
|
-
client.on("error", () => {
|
|
85
|
-
});
|
|
86
|
-
await client.connect();
|
|
87
|
-
this.workerClients.push(client);
|
|
88
|
-
return client;
|
|
89
|
-
}
|
|
90
|
-
async startWorkers() {
|
|
91
|
-
const ready = [];
|
|
92
|
-
for (let i = 0; i < this.options.concurrency; i++) {
|
|
93
|
-
ready.push(this.startWorker(`worker-${i}`));
|
|
94
|
-
}
|
|
95
|
-
await Promise.all(ready);
|
|
96
|
-
}
|
|
97
|
-
async startGroupWorkers(groupKey) {
|
|
98
|
-
const groupWorkers = this.groupWorkers.get(groupKey);
|
|
99
|
-
const ready = [];
|
|
100
|
-
for (let i = 0; i < this.options.groups.concurrency; i++) {
|
|
101
|
-
const workerId = `group-${groupKey}-worker-${i}`;
|
|
102
|
-
groupWorkers.set(workerId, true);
|
|
103
|
-
ready.push(this.startGroupWorker(workerId, groupKey));
|
|
104
|
-
}
|
|
105
|
-
await Promise.all(ready);
|
|
106
|
-
}
|
|
107
|
-
async startWorker(workerId) {
|
|
108
|
-
this.workers.set(workerId, true);
|
|
109
|
-
const client = await this.createWorkerClient();
|
|
110
|
-
this.runWorkerLoop(workerId, client, "queue:tasks", this.workers, (task) => this.processTask(task));
|
|
111
|
-
}
|
|
112
|
-
async startGroupWorker(workerId, groupKey) {
|
|
113
|
-
const groupWorkers = this.groupWorkers.get(groupKey);
|
|
114
|
-
const client = await this.createWorkerClient();
|
|
115
|
-
this.runWorkerLoop(workerId, client, `queue:groups:${groupKey}`, groupWorkers, (task) => this.processGroupTask(task));
|
|
116
|
-
}
|
|
117
|
-
async runWorkerLoop(workerId, client, key, activeMap, processFn) {
|
|
118
|
-
const isGrouped = key.startsWith("queue:groups:");
|
|
119
|
-
const delay = isGrouped ? this.options.groups.delay : this.options.delay;
|
|
120
|
-
while (activeMap.get(workerId)) {
|
|
121
|
-
try {
|
|
122
|
-
if (!client.isOpen) break;
|
|
123
|
-
const taskData = await client.brPop(key, 1);
|
|
124
|
-
if (taskData) {
|
|
125
|
-
const task = JSON.parse(taskData.element);
|
|
126
|
-
this._inFlight++;
|
|
127
|
-
await processFn(task);
|
|
128
|
-
}
|
|
129
|
-
if (delay > 0) {
|
|
130
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
131
|
-
}
|
|
132
|
-
} catch (err) {
|
|
133
|
-
const error = err;
|
|
134
|
-
if (error.message?.includes("closed") || error.message?.includes("ClientClosedError")) {
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
async processTask(task) {
|
|
141
|
-
task.attempts++;
|
|
142
|
-
try {
|
|
143
|
-
if (!this.handler) {
|
|
144
|
-
this.emit("complete", { task, result: void 0 });
|
|
145
|
-
this.settle();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const timeoutPromise = this.options.timeout > 0 ? new Promise(
|
|
149
|
-
(_, reject) => setTimeout(() => reject(new Error("Task timeout")), this.options.timeout)
|
|
150
|
-
) : null;
|
|
151
|
-
const workPromise = Promise.resolve(this.handler(task.payload, task));
|
|
152
|
-
const result = timeoutPromise ? await Promise.race([workPromise, timeoutPromise]) : await workPromise;
|
|
153
|
-
this.emit("complete", { task, result });
|
|
154
|
-
this.settle();
|
|
155
|
-
} catch (error) {
|
|
156
|
-
if (task.attempts < this.options.maxRetries) {
|
|
157
|
-
this.emit("retry", { task, error, attempt: task.attempts });
|
|
158
|
-
this._inFlight--;
|
|
159
|
-
await this.redis.lPush("queue:tasks", JSON.stringify(task));
|
|
160
|
-
} else {
|
|
161
|
-
this.emit("failed", { task, error });
|
|
162
|
-
this.settle();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
async processGroupTask(task) {
|
|
167
|
-
task.attempts++;
|
|
168
|
-
try {
|
|
169
|
-
if (!this.handler) {
|
|
170
|
-
this.emit("complete", { task, result: void 0 });
|
|
171
|
-
this.settle();
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const timeoutPromise = this.options.groups.timeout > 0 ? new Promise(
|
|
175
|
-
(_, reject) => setTimeout(() => reject(new Error("Task timeout")), this.options.groups.timeout)
|
|
176
|
-
) : null;
|
|
177
|
-
const workPromise = Promise.resolve(this.handler(task.payload, task));
|
|
178
|
-
const result = timeoutPromise ? await Promise.race([workPromise, timeoutPromise]) : await workPromise;
|
|
179
|
-
this.emit("complete", { task, result });
|
|
180
|
-
this.settle();
|
|
181
|
-
} catch (error) {
|
|
182
|
-
if (task.attempts < this.options.groups.maxRetries) {
|
|
183
|
-
this.emit("retry", { task, error, attempt: task.attempts });
|
|
184
|
-
this._inFlight--;
|
|
185
|
-
await this.redis.lPush(`queue:groups:${task.groupKey}`, JSON.stringify(task));
|
|
186
|
-
} else {
|
|
187
|
-
this.emit("failed", { task, error });
|
|
188
|
-
this.settle();
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
settle() {
|
|
193
|
-
this._inFlight--;
|
|
194
|
-
this._totalSettled++;
|
|
195
|
-
if (this._inFlight === 0 && this._totalSettled > 0) {
|
|
196
|
-
this.emit("drain");
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
async initializeRedis() {
|
|
200
|
-
await this.redis.connect();
|
|
201
|
-
await this.startWorkers();
|
|
202
|
-
if (this.options.cleanupInterval > 0) {
|
|
203
|
-
this.cleanupTimer = setInterval(() => {
|
|
204
|
-
this.performPeriodicCleanup();
|
|
205
|
-
}, this.options.cleanupInterval);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
async performPeriodicCleanup() {
|
|
209
|
-
try {
|
|
210
|
-
if (!this.redis.isOpen) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
const groupKeys = Array.from(this.groupWorkers.keys());
|
|
214
|
-
for (const groupKey of groupKeys) {
|
|
215
|
-
const length = await this.redis.lLen(`queue:groups:${groupKey}`);
|
|
216
|
-
if (length === 0) {
|
|
217
|
-
const keyExists = await this.redis.exists(`queue:groups:${groupKey}`);
|
|
218
|
-
if (keyExists) {
|
|
219
|
-
await this.redis.del(`queue:groups:${groupKey}`);
|
|
220
|
-
}
|
|
221
|
-
const groupWorkers = this.groupWorkers.get(groupKey);
|
|
222
|
-
if (groupWorkers) {
|
|
223
|
-
groupWorkers.clear();
|
|
224
|
-
this.groupWorkers.delete(groupKey);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
} catch (error) {
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/** shuts down all workers and disconnects from redis. waits for initialization to complete first. */
|
|
232
|
-
async close() {
|
|
233
|
-
await this._ready.catch(() => {
|
|
234
|
-
});
|
|
235
|
-
if (this.cleanupTimer) {
|
|
236
|
-
clearInterval(this.cleanupTimer);
|
|
237
|
-
}
|
|
238
|
-
this.workers.clear();
|
|
239
|
-
for (const groupWorkers of this.groupWorkers.values()) {
|
|
240
|
-
groupWorkers.clear();
|
|
241
|
-
}
|
|
242
|
-
this.groupWorkers.clear();
|
|
243
|
-
for (const client of this.workerClients) {
|
|
244
|
-
if (client.isOpen) {
|
|
245
|
-
await client.disconnect();
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
this.workerClients = [];
|
|
249
|
-
if (this.redis.isOpen) {
|
|
250
|
-
await this.redis.quit();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
export {
|
|
255
|
-
Queue as default
|
|
256
|
-
};
|
|
257
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/queue.ts"],"sourcesContent":["import { createClient, RedisClientType } from 'redis'\nimport { EventEmitter } from 'events'\nimport { randomUUID } from 'crypto'\nimport ms from '@prsm/ms'\n\nexport interface QueueOptions<T = any> {\n /** number of tasks to process in parallel. @default 1 */\n concurrency?: number\n /** wait time between finishing one task and picking up the next (ms or string like \"500ms\"). @default 0 */\n delay?: number | string\n /** max time a single task handler can run before it's killed with a \"Task timeout\" error (ms or string like \"30s\"). 0 = no limit. @default 0 */\n timeout?: number | string\n /** how many times to re-attempt a failed task before emitting \"failed\". @default 3 */\n maxRetries?: number\n /** overrides for grouped queues, falls back to top-level values */\n groups?: {\n concurrency?: number\n delay?: number | string\n timeout?: number | string\n maxRetries?: number\n }\n redisOptions?: {\n url?: string\n host?: string\n port?: number\n password?: string\n }\n /** how often to clean up empty group keys in redis (ms). 0 = disabled. @default 30000 */\n cleanupInterval?: number\n}\n\n/** called for each task, return value is passed to the \"complete\" event */\nexport type TaskHandler<T, R = any> = (payload: T, task: Task<T>) => Promise<R> | R\n\nexport interface Task<T = any> {\n uuid: string\n payload: T\n createdAt: number\n /** present when the task was pushed via queue.group(key).push() */\n groupKey?: string\n /** number of times this task has been attempted so far */\n attempts: number\n}\n\n\nexport default class Queue<T = any, R = any> extends EventEmitter {\n private redis: RedisClientType\n private workerClients: RedisClientType[] = []\n private options: {\n concurrency: number\n delay: number\n timeout: number\n maxRetries: number\n groups: {\n concurrency: number\n delay: number\n timeout: number\n maxRetries: number\n }\n redisOptions: object\n cleanupInterval: number\n }\n private handler?: TaskHandler<T, R>\n private workers = new Map<string, boolean>()\n private groupWorkers = new Map<string, Map<string, boolean>>()\n private cleanupTimer?: NodeJS.Timeout\n private _ready: Promise<void>\n private _inFlight = 0\n private _totalSettled = 0\n\n constructor(options: QueueOptions<T> = {}) {\n super()\n\n this.options = {\n concurrency: options.concurrency ?? 1,\n delay: ms(options.delay ?? 0),\n timeout: ms(options.timeout ?? 0),\n maxRetries: options.maxRetries ?? 3,\n groups: {\n concurrency: options.groups?.concurrency ?? options.concurrency ?? 1,\n delay: ms(options.groups?.delay ?? options.delay ?? 0),\n timeout: ms(options.groups?.timeout ?? options.timeout ?? 0),\n maxRetries: options.groups?.maxRetries ?? options.maxRetries ?? 3\n },\n redisOptions: options.redisOptions ?? {},\n cleanupInterval: options.cleanupInterval ?? 30000\n }\n\n this.redis = createClient(this.options.redisOptions)\n this.redis.on('error', () => {})\n this._ready = this.initializeRedis()\n }\n\n /** resolves when redis is connected and all workers are ready to accept tasks */\n ready() {\n return this._ready\n }\n\n get inFlight() {\n return this._inFlight\n }\n\n /** register the handler that processes each task. only one handler per queue. */\n process(handler: TaskHandler<T, R>) {\n this.handler = handler\n }\n\n /** push a task to the main queue. returns the task uuid. */\n async push(payload: T): Promise<string> {\n const task: Task<T> = {\n uuid: randomUUID(),\n payload,\n createdAt: Date.now(),\n attempts: 0\n }\n\n await this.redis.lPush('queue:tasks', JSON.stringify(task))\n this.emit('new', { task })\n\n return task.uuid\n }\n\n /** returns a scoped pusher for a named group. each group gets its own worker pool, spun up on first push. */\n group(key: string) {\n return {\n push: async (payload: T): Promise<string> => {\n const task: Task<T> = {\n uuid: randomUUID(),\n payload,\n createdAt: Date.now(),\n groupKey: key,\n attempts: 0\n }\n\n await this.redis.lPush(`queue:groups:${key}`, JSON.stringify(task))\n this.emit('new', { task })\n\n if (!this.groupWorkers.has(key)) {\n this.groupWorkers.set(key, new Map())\n await this.startGroupWorkers(key)\n }\n\n return task.uuid\n }\n }\n }\n\n private async createWorkerClient(): Promise<RedisClientType> {\n const client = this.redis.duplicate() as RedisClientType\n client.on('error', () => {})\n await client.connect()\n this.workerClients.push(client)\n return client\n }\n\n private async startWorkers() {\n const ready = []\n for (let i = 0; i < this.options.concurrency; i++) {\n ready.push(this.startWorker(`worker-${i}`))\n }\n await Promise.all(ready)\n }\n\n private async startGroupWorkers(groupKey: string) {\n const groupWorkers = this.groupWorkers.get(groupKey)!\n const ready = []\n for (let i = 0; i < this.options.groups.concurrency; i++) {\n const workerId = `group-${groupKey}-worker-${i}`\n groupWorkers.set(workerId, true)\n ready.push(this.startGroupWorker(workerId, groupKey))\n }\n await Promise.all(ready)\n }\n\n private async startWorker(workerId: string) {\n this.workers.set(workerId, true)\n const client = await this.createWorkerClient()\n\n this.runWorkerLoop(workerId, client, 'queue:tasks', this.workers, (task) => this.processTask(task))\n }\n\n private async startGroupWorker(workerId: string, groupKey: string) {\n const groupWorkers = this.groupWorkers.get(groupKey)!\n const client = await this.createWorkerClient()\n\n this.runWorkerLoop(workerId, client, `queue:groups:${groupKey}`, groupWorkers, (task) => this.processGroupTask(task))\n }\n\n private async runWorkerLoop(\n workerId: string,\n client: RedisClientType,\n key: string,\n activeMap: Map<string, boolean>,\n processFn: (task: Task<T>) => Promise<void>\n ) {\n const isGrouped = key.startsWith('queue:groups:')\n const delay = isGrouped ? this.options.groups.delay : this.options.delay\n\n while (activeMap.get(workerId)) {\n try {\n if (!client.isOpen) break\n\n const taskData = await client.brPop(key, 1)\n\n if (taskData) {\n const task: Task<T> = JSON.parse(taskData.element)\n this._inFlight++\n await processFn(task)\n }\n\n if (delay > 0) {\n await new Promise(resolve => setTimeout(resolve, delay))\n }\n } catch (err) {\n const error = err as Error\n if (error.message?.includes('closed') || error.message?.includes('ClientClosedError')) {\n break\n }\n }\n }\n }\n\n private async processTask(task: Task<T>) {\n task.attempts++\n\n try {\n if (!this.handler) {\n this.emit('complete', { task, result: undefined })\n this.settle()\n return\n }\n\n const timeoutPromise = this.options.timeout > 0\n ? new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Task timeout')), this.options.timeout)\n )\n : null\n\n const workPromise = Promise.resolve(this.handler(task.payload, task))\n\n const result = timeoutPromise\n ? await Promise.race([workPromise, timeoutPromise])\n : await workPromise\n\n this.emit('complete', { task, result })\n this.settle()\n } catch (error) {\n if (task.attempts < this.options.maxRetries) {\n this.emit('retry', { task, error, attempt: task.attempts })\n this._inFlight--\n await this.redis.lPush('queue:tasks', JSON.stringify(task))\n } else {\n this.emit('failed', { task, error })\n this.settle()\n }\n }\n }\n\n private async processGroupTask(task: Task<T>) {\n task.attempts++\n\n try {\n if (!this.handler) {\n this.emit('complete', { task, result: undefined })\n this.settle()\n return\n }\n\n const timeoutPromise = this.options.groups.timeout > 0\n ? new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Task timeout')), this.options.groups.timeout)\n )\n : null\n\n const workPromise = Promise.resolve(this.handler(task.payload, task))\n\n const result = timeoutPromise\n ? await Promise.race([workPromise, timeoutPromise])\n : await workPromise\n\n this.emit('complete', { task, result })\n this.settle()\n } catch (error) {\n if (task.attempts < this.options.groups.maxRetries) {\n this.emit('retry', { task, error, attempt: task.attempts })\n this._inFlight--\n await this.redis.lPush(`queue:groups:${task.groupKey}`, JSON.stringify(task))\n } else {\n this.emit('failed', { task, error })\n this.settle()\n }\n }\n }\n\n private settle() {\n this._inFlight--\n this._totalSettled++\n if (this._inFlight === 0 && this._totalSettled > 0) {\n this.emit('drain')\n }\n }\n\n private async initializeRedis() {\n await this.redis.connect()\n await this.startWorkers()\n\n if (this.options.cleanupInterval > 0) {\n this.cleanupTimer = setInterval(() => {\n this.performPeriodicCleanup()\n }, this.options.cleanupInterval)\n }\n }\n\n private async performPeriodicCleanup() {\n try {\n if (!this.redis.isOpen) {\n return\n }\n\n const groupKeys = Array.from(this.groupWorkers.keys())\n\n for (const groupKey of groupKeys) {\n const length = await this.redis.lLen(`queue:groups:${groupKey}`)\n\n if (length === 0) {\n const keyExists = await this.redis.exists(`queue:groups:${groupKey}`)\n if (keyExists) {\n await this.redis.del(`queue:groups:${groupKey}`)\n }\n\n const groupWorkers = this.groupWorkers.get(groupKey)\n if (groupWorkers) {\n groupWorkers.clear()\n this.groupWorkers.delete(groupKey)\n }\n }\n }\n } catch (error) {\n // cleanup error handled silently\n }\n }\n\n /** shuts down all workers and disconnects from redis. waits for initialization to complete first. */\n async close() {\n await this._ready.catch(() => {})\n\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer)\n }\n this.workers.clear()\n for (const groupWorkers of this.groupWorkers.values()) {\n groupWorkers.clear()\n }\n this.groupWorkers.clear()\n\n for (const client of this.workerClients) {\n if (client.isOpen) {\n await client.disconnect()\n }\n }\n this.workerClients = []\n\n if (this.redis.isOpen) {\n await this.redis.quit()\n }\n }\n}\n"],"mappings":"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","names":[]}
|