@rpcbase/worker 0.31.0 → 0.33.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/dist/index.js CHANGED
@@ -22,7 +22,9 @@ const getConcurrency = () => {
22
22
  if (!Number.isFinite(value) || value <= 0) return DEFAULT_CONCURRENCY;
23
23
  return Math.floor(value);
24
24
  };
25
- const getConnection = () => ({ url: getRedisUrl() });
25
+ const getConnection = () => ({
26
+ url: getRedisUrl()
27
+ });
26
28
  const ensureQueue = () => {
27
29
  if (queueInstance) return queueInstance;
28
30
  queueInstance = new Queue(getQueueName(), {
@@ -49,26 +51,26 @@ const start = async () => {
49
51
  hasStarted = true;
50
52
  const queue = ensureQueue();
51
53
  const concurrency = getConcurrency();
52
- console.log("start worker queue", { queue: queue.name, redisUrl: getRedisUrl(), concurrency });
54
+ console.log("start worker queue", {
55
+ queue: queue.name,
56
+ redisUrl: getRedisUrl(),
57
+ concurrency
58
+ });
53
59
  queue.on("error", (err) => {
54
60
  console.log(`queue error: ${err.message}`);
55
61
  });
56
62
  if (!workerInstance) {
57
- workerInstance = new Worker(
58
- queue.name,
59
- async (job) => {
60
- const taskName = job.name;
61
- const handler = tasksByName[taskName];
62
- if (!handler) {
63
- throw new Error(`No task registered for '${taskName}'`);
64
- }
65
- return await handler(job.data, job);
66
- },
67
- {
68
- concurrency,
69
- connection: getConnection()
63
+ workerInstance = new Worker(queue.name, async (job) => {
64
+ const taskName = job.name;
65
+ const handler = tasksByName[taskName];
66
+ if (!handler) {
67
+ throw new Error(`No task registered for '${taskName}'`);
70
68
  }
71
- );
69
+ return await handler(job.data, job);
70
+ }, {
71
+ concurrency,
72
+ connection: getConnection()
73
+ });
72
74
  }
73
75
  workerInstance.on("error", (err) => {
74
76
  console.log(`worker error: ${err.message}`);
@@ -95,7 +97,11 @@ const close = async () => {
95
97
  };
96
98
  const getUrl = () => getRedisUrl();
97
99
  async function scheduleTask(taskName, payload, options) {
98
- const { jobId, repeat, ...rest } = options;
100
+ const {
101
+ jobId,
102
+ repeat,
103
+ ...rest
104
+ } = options;
99
105
  return add(taskName, payload, {
100
106
  ...rest,
101
107
  jobId: jobId ?? `schedule|${taskName}`,
@@ -186,7 +192,10 @@ const dispatchWorkerQueue = async ({
186
192
  const handlerName = `on-${taskOp}-${modelName}`;
187
193
  if (!tasks[handlerName]) return;
188
194
  const normalizedUpdateDescription = normalizeUpdateDescription(updateDescription);
189
- await queueApi.add(handlerName, { doc, updateDescription: normalizedUpdateDescription }, {
195
+ await queueApi.add(handlerName, {
196
+ doc,
197
+ updateDescription: normalizedUpdateDescription
198
+ }, {
190
199
  jobId: `${dbName}|${taskOp}-${getDocumentId(doc) ?? "unknown"}`,
191
200
  removeOnComplete: true,
192
201
  removeOnFail: true
@@ -200,7 +209,11 @@ const normalizeRetryDelays = (input) => {
200
209
  const rawMaxMs = Math.max(0, Math.floor(input?.maxMs ?? RETRY_MAXIMUM_DELAY_MS));
201
210
  const maxMs = Math.max(minMs, rawMaxMs);
202
211
  const factor = Math.max(1, Number.isFinite(input?.factor) ? input?.factor ?? RETRY_DEFAULT_FACTOR : RETRY_DEFAULT_FACTOR);
203
- return { minMs, maxMs, factor };
212
+ return {
213
+ minMs,
214
+ maxMs,
215
+ factor
216
+ };
204
217
  };
205
218
  const getRetryDelayMs = (attempt, delays) => Math.min(delays.maxMs, Math.round(delays.minMs * Math.pow(delays.factor, Math.max(0, attempt - 1))));
206
219
  const normalizeMaxRetries = (value) => {
@@ -229,7 +242,10 @@ const registerQueueListener = async (options = {}) => {
229
242
  let stream = null;
230
243
  let resumeAfter = null;
231
244
  let processing = Promise.resolve();
232
- let status = { state: "connecting", attempt: 1 };
245
+ let status = {
246
+ state: "connecting",
247
+ attempt: 1
248
+ };
233
249
  const setStatus = (next) => {
234
250
  status = next;
235
251
  try {
@@ -279,7 +295,9 @@ const registerQueueListener = async (options = {}) => {
279
295
  if (!readySettled) {
280
296
  rejectReady(new Error("queue listener closed before ready"));
281
297
  }
282
- setStatus({ state: "closed" });
298
+ setStatus({
299
+ state: "closed"
300
+ });
283
301
  };
284
302
  const closeResources = async () => {
285
303
  try {
@@ -295,7 +313,11 @@ const registerQueueListener = async (options = {}) => {
295
313
  client = null;
296
314
  };
297
315
  const startStream = async () => {
298
- if (stopped) return { stoppedPromise: Promise.resolve({ reason: "close" }) };
316
+ if (stopped) return {
317
+ stoppedPromise: Promise.resolve({
318
+ reason: "close"
319
+ })
320
+ };
299
321
  if (stream) {
300
322
  try {
301
323
  stream.removeAllListeners();
@@ -313,23 +335,37 @@ const registerQueueListener = async (options = {}) => {
313
335
  }
314
336
  client = new MongoClient(mongoUrl, mongoClientOptions);
315
337
  await client.connect();
316
- const dbMatch = { "ns.db": { $regex: `^${escapeRegex(appName)}-.*-db$` } };
317
- const pipeline = [
318
- { $match: dbMatch },
319
- {
320
- $match: {
321
- operationType: { $in: ["insert", "update", "replace", "delete"] }
338
+ const dbMatch = {
339
+ "ns.db": {
340
+ $regex: `^${escapeRegex(appName)}-.*-db$`
341
+ }
342
+ };
343
+ const pipeline = [{
344
+ $match: dbMatch
345
+ }, {
346
+ $match: {
347
+ operationType: {
348
+ $in: ["insert", "update", "replace", "delete"]
349
+ }
350
+ }
351
+ }, {
352
+ $match: {
353
+ "ns.coll": {
354
+ $nin: Array.from(INTERNAL_IGNORED_COLLECTION_NAMES)
322
355
  }
323
- },
324
- { $match: { "ns.coll": { $nin: Array.from(INTERNAL_IGNORED_COLLECTION_NAMES) } } }
325
- ];
356
+ }
357
+ }];
326
358
  stream = client.watch(pipeline, {
327
359
  fullDocument: "updateLookup",
328
- ...resumeAfter ? { resumeAfter } : {}
360
+ ...resumeAfter ? {
361
+ resumeAfter
362
+ } : {}
329
363
  });
330
364
  const stoppedPromise = new Promise((resolve) => {
331
365
  let settled = false;
332
- const onAbort = () => settle({ reason: "close" });
366
+ const onAbort = () => settle({
367
+ reason: "close"
368
+ });
333
369
  const settle = (result) => {
334
370
  if (settled) return;
335
371
  settled = true;
@@ -337,8 +373,13 @@ const registerQueueListener = async (options = {}) => {
337
373
  resolve(result);
338
374
  };
339
375
  abortController.signal.addEventListener("abort", onAbort);
340
- stream?.once("close", () => settle({ reason: "close" }));
341
- stream?.once("error", (err) => settle({ reason: "error", error: err }));
376
+ stream?.once("close", () => settle({
377
+ reason: "close"
378
+ }));
379
+ stream?.once("error", (err) => settle({
380
+ reason: "error",
381
+ error: err
382
+ }));
342
383
  });
343
384
  stream.on("change", (change) => {
344
385
  const streamRef = stream;
@@ -393,23 +434,36 @@ const registerQueueListener = async (options = {}) => {
393
434
  } catch {
394
435
  }
395
436
  });
396
- return { stoppedPromise };
437
+ return {
438
+ stoppedPromise
439
+ };
397
440
  };
398
441
  const run = async () => {
399
442
  let retryCounter = 0;
400
443
  while (!stopped) {
401
444
  try {
402
- setStatus({ state: "connecting", attempt: retryCounter + 1 });
403
- const { stoppedPromise } = await startStream();
445
+ setStatus({
446
+ state: "connecting",
447
+ attempt: retryCounter + 1
448
+ });
449
+ const {
450
+ stoppedPromise
451
+ } = await startStream();
404
452
  retryCounter = 0;
405
- setStatus({ state: "ready" });
453
+ setStatus({
454
+ state: "ready"
455
+ });
406
456
  resolveReady();
407
457
  const end = await stoppedPromise;
408
458
  if (stopped) return;
409
459
  retryCounter += 1;
410
460
  if (maxRetries !== "infinite" && retryCounter > maxRetries) {
411
461
  const err2 = end.reason === "error" ? end.error : new Error("queue listener closed");
412
- setStatus({ state: "failed", attempt: retryCounter, error: err2 });
462
+ setStatus({
463
+ state: "failed",
464
+ attempt: retryCounter,
465
+ error: err2
466
+ });
413
467
  if (fatalOnMaxRetries) {
414
468
  try {
415
469
  options.onFatal?.(err2);
@@ -425,14 +479,23 @@ const registerQueueListener = async (options = {}) => {
425
479
  const delayMs = getRetryDelayMs(retryCounter, retryDelays);
426
480
  const err = end.reason === "error" ? end.error : new Error("queue listener closed");
427
481
  console.warn("queue listener not ready, retrying in", delayMs, err);
428
- setStatus({ state: "error", attempt: retryCounter, error: err, nextRetryInMs: delayMs });
482
+ setStatus({
483
+ state: "error",
484
+ attempt: retryCounter,
485
+ error: err,
486
+ nextRetryInMs: delayMs
487
+ });
429
488
  await closeResources();
430
489
  await sleep(delayMs, abortController.signal);
431
490
  } catch (err) {
432
491
  if (stopped) return;
433
492
  retryCounter += 1;
434
493
  if (maxRetries !== "infinite" && retryCounter > maxRetries) {
435
- setStatus({ state: "failed", attempt: retryCounter, error: err });
494
+ setStatus({
495
+ state: "failed",
496
+ attempt: retryCounter,
497
+ error: err
498
+ });
436
499
  if (fatalOnMaxRetries) {
437
500
  try {
438
501
  options.onFatal?.(err);
@@ -447,7 +510,12 @@ const registerQueueListener = async (options = {}) => {
447
510
  }
448
511
  const delayMs = getRetryDelayMs(retryCounter, retryDelays);
449
512
  console.warn("queue listener not ready, retrying in", delayMs, err);
450
- setStatus({ state: "error", attempt: retryCounter, error: err, nextRetryInMs: delayMs });
513
+ setStatus({
514
+ state: "error",
515
+ attempt: retryCounter,
516
+ error: err,
517
+ nextRetryInMs: delayMs
518
+ });
451
519
  await closeResources();
452
520
  await sleep(delayMs, abortController.signal);
453
521
  }
@@ -460,7 +528,11 @@ const registerQueueListener = async (options = {}) => {
460
528
  };
461
529
  void run().catch(async (err) => {
462
530
  if (stopped) return;
463
- setStatus({ state: "failed", attempt: 0, error: err });
531
+ setStatus({
532
+ state: "failed",
533
+ attempt: 0,
534
+ error: err
535
+ });
464
536
  rejectReady(err);
465
537
  await closeResources();
466
538
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/queue.ts","../src/queueListener.ts","../src/taskNames.ts"],"sourcesContent":["import { Queue, Worker, type Job, type JobsOptions as JobOptions } from \"bullmq\"\n\nimport type { WorkerTasksMap } from \"./tasksMap\"\n\n\nexport type TaskHandler<TPayload = unknown> = (payload: TPayload, job: Job) => unknown | Promise<unknown>\n\nconst DEFAULT_QUEUE_NAME = \"rb-queue-default\"\nconst DEFAULT_CONCURRENCY = 2\nconst DEFAULT_RENTENTION = 128\n\nconst tasksByName: Record<string, TaskHandler<unknown>> = Object.create(null)\n\nlet queueInstance: Queue | null = null\nlet workerInstance: Worker | null = null\nlet hasStarted = false\n\nconst getRedisUrl = (): string => {\n const redisUrl = process.env.REDIS_URL?.trim()\n if (!redisUrl) {\n throw new Error(\"Missing REDIS_URL (required for @rpcbase/worker queue)\")\n }\n return redisUrl\n}\n\nconst getQueueName = (): string => process.env.RB_QUEUE_NAME?.trim() || DEFAULT_QUEUE_NAME\n\nconst getConcurrency = (): number => {\n const raw = process.env.RB_QUEUE_CONCURRENCY?.trim()\n const value = raw ? Number(raw) : DEFAULT_CONCURRENCY\n if (!Number.isFinite(value) || value <= 0) return DEFAULT_CONCURRENCY\n return Math.floor(value)\n}\n\nconst getConnection = () => ({ url: getRedisUrl() })\n\nconst ensureQueue = (): Queue => {\n if (queueInstance) return queueInstance\n queueInstance = new Queue(getQueueName(), {\n connection: getConnection(),\n defaultJobOptions: {\n removeOnComplete: DEFAULT_RENTENTION,\n removeOnFail: DEFAULT_RENTENTION\n },\n })\n\n return queueInstance\n}\n\nexport function registerTask<TName extends keyof WorkerTasksMap & string>(\n name: TName,\n handler: TaskHandler<WorkerTasksMap[TName]>,\n): void\nexport function registerTask(name: string, handler: TaskHandler<unknown>): void\nexport function registerTask(name: string, handler: TaskHandler<unknown>): void {\n tasksByName[name] = handler\n}\n\nexport const getTasks = (): Record<string, TaskHandler<unknown>> => tasksByName\n\nexport function add<TName extends keyof WorkerTasksMap & string>(\n taskName: TName,\n payload: WorkerTasksMap[TName],\n options?: JobOptions,\n): Promise<Job>\nexport function add(taskName: string, payload: unknown, options?: JobOptions): Promise<Job>\nexport function add(taskName: string, payload: unknown, options?: JobOptions): Promise<Job> {\n return ensureQueue().add(taskName, payload, options)\n}\n\nexport const getJob = async (jobId: string): Promise<Job | null> => (await ensureQueue().getJob(jobId)) ?? null\n\nexport const getJobs = async (...args: Parameters<Queue[\"getJobs\"]>): Promise<Job[]> =>\n ensureQueue().getJobs(...args) as unknown as Job[]\n\nexport const getInstance = (): Queue => ensureQueue()\n\nexport const start = async (): Promise<Queue> => {\n if (hasStarted) return ensureQueue()\n hasStarted = true\n\n const queue = ensureQueue()\n const concurrency = getConcurrency()\n\n console.log(\"start worker queue\", { queue: queue.name, redisUrl: getRedisUrl(), concurrency })\n\n queue.on(\"error\", (err) => {\n console.log(`queue error: ${err.message}`)\n })\n\n if (!workerInstance) {\n workerInstance = new Worker(\n queue.name,\n async (job) => {\n const taskName = job.name\n\n const handler = tasksByName[taskName]\n if (!handler) {\n throw new Error(`No task registered for '${taskName}'`)\n }\n\n return await handler(job.data, job)\n },\n {\n concurrency,\n connection: getConnection(),\n },\n )\n }\n\n workerInstance.on(\"error\", (err) => {\n console.log(`worker error: ${err.message}`)\n })\n\n workerInstance.on(\"stalled\", (jobId) => {\n console.log(`job ${jobId} stalled`)\n })\n\n workerInstance.on(\"failed\", (job, err) => {\n console.log(`job ${job?.id ?? \"unknown\"} failed`, err)\n })\n\n await workerInstance.waitUntilReady()\n\n return queue\n}\n\nexport const close = async (): Promise<void> => {\n if (!queueInstance && !workerInstance) return\n try {\n await workerInstance?.close()\n await queueInstance?.close()\n } finally {\n workerInstance = null\n queueInstance = null\n hasStarted = false\n }\n}\n\nexport const getUrl = (): string => getRedisUrl()\n\nexport type ScheduleTaskOptions = Omit<JobOptions, \"repeat\"> & {\n jobId?: string\n repeat: NonNullable<JobOptions[\"repeat\"]>\n}\n\nexport function scheduleTask<TName extends keyof WorkerTasksMap & string>(\n taskName: TName,\n payload: WorkerTasksMap[TName],\n options: ScheduleTaskOptions,\n): Promise<Job>\nexport function scheduleTask(taskName: string, payload: unknown, options: ScheduleTaskOptions): Promise<Job>\nexport async function scheduleTask(taskName: string, payload: unknown, options: ScheduleTaskOptions): Promise<Job> {\n const { jobId, repeat, ...rest } = options\n return add(taskName, payload, {\n ...rest,\n jobId: jobId ?? `schedule|${taskName}`,\n repeat,\n })\n}\n\nconst queueApi = {\n start,\n close,\n registerTask,\n getTasks,\n add,\n scheduleTask,\n getJob,\n getJobs,\n getInstance,\n getUrl,\n}\n\nexport default queueApi\n","import {\n MongoClient,\n type ChangeStream,\n type ChangeStreamDocument,\n type Document,\n type MongoClientOptions,\n} from \"mongodb\"\nimport mongoose from \"mongoose\"\n\nimport queue from \"./queue\"\n\n\nexport type QueueListenerRetryDelays = {\n minMs?: number\n maxMs?: number\n factor?: number\n}\n\nexport type QueueListenerStatus =\n | { state: \"connecting\"; attempt: number }\n | { state: \"ready\" }\n | { state: \"error\"; attempt: number; error: unknown; nextRetryInMs: number }\n | { state: \"failed\"; attempt: number; error: unknown }\n | { state: \"closed\" }\n\nexport type QueueListenerHandle = {\n ready: Promise<void>\n close: () => Promise<void>\n getStatus: () => QueueListenerStatus\n}\n\nexport type QueueListenerOptions = {\n maxRetries?: number | \"infinite\"\n fatalOnMaxRetries?: boolean\n onStateChange?: (status: QueueListenerStatus) => void\n onFatal?: (err: unknown) => void\n retryDelays?: QueueListenerRetryDelays\n mongoClientOptions?: MongoClientOptions\n}\n\nconst RETRY_MAXIMUM_DELAY_MS = 3000\nconst RETRY_MINIMUM_DELAY_MS = 50\nconst RETRY_DEFAULT_FACTOR = 2\n\nconst sleep = async (ms: number, signal?: AbortSignal): Promise<void> => new Promise((resolve) => {\n if (signal?.aborted) {\n resolve()\n return\n }\n\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n const cleanup = () => {\n if (timeout) clearTimeout(timeout)\n signal?.removeEventListener(\"abort\", onAbort)\n }\n\n const onAbort = () => {\n cleanup()\n resolve()\n }\n\n timeout = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n timeout.unref?.()\n\n signal?.addEventListener(\"abort\", onAbort)\n})\n\nconst getMongoUrl = (): string => {\n const explicit =\n process.env.MONGODB_URL\n ?? process.env.MONGO_URL\n ?? process.env.MONGODB_URI\n ?? process.env.DB_URL\n\n if (explicit && explicit.trim()) return explicit.trim()\n\n const port = process.env.DB_PORT?.trim()\n if (!port) throw new Error(\"Missing Mongo connection details (MONGODB_URL/MONGO_URL/MONGODB_URI/DB_URL/DB_PORT)\")\n\n const host = process.env.DB_HOST?.trim() || \"localhost\"\n return `mongodb://${host}:${port}`\n}\n\nconst escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\ntype ModelWithCollection = {\n collection?: {\n collectionName?: string\n name?: string\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null\n\nconst getDocumentId = (doc: unknown): unknown => {\n if (!isRecord(doc)) return undefined\n return doc._id\n}\n\nconst resolveModelNameFromCollection = (collName: string): string | null => {\n const models = mongoose.models\n\n for (const modelName of Object.keys(models)) {\n const model = models[modelName] as ModelWithCollection\n const collectionName =\n model.collection?.collectionName\n ?? model.collection?.name\n\n if (collectionName === collName) {\n return modelName\n }\n }\n\n return null\n}\n\nconst normalizeUpdateDescription = (updateDescription: unknown): unknown => {\n if (!isRecord(updateDescription)) return updateDescription\n if (isRecord(updateDescription.updatedFields)) {\n return {\n ...updateDescription,\n updatedFieldsKeys: Object.keys(updateDescription.updatedFields),\n }\n }\n\n return updateDescription\n}\n\nconst normalizeOpForTaskName = (op: string): string => (op === \"replace\" ? \"update\" : op)\n\nconst dispatchWorkerQueue = async ({\n dbName,\n modelName,\n op,\n doc,\n updateDescription,\n}: {\n dbName: string\n modelName: string\n op: string\n doc: unknown\n updateDescription?: unknown\n}): Promise<void> => {\n const tasks = queue.getTasks()\n const taskOp = normalizeOpForTaskName(op)\n const handlerName = `on-${taskOp}-${modelName}`\n\n if (!tasks[handlerName]) return\n\n const normalizedUpdateDescription = normalizeUpdateDescription(updateDescription)\n\n await queue.add(handlerName, { doc, updateDescription: normalizedUpdateDescription }, {\n jobId: `${dbName}|${taskOp}-${getDocumentId(doc) ?? \"unknown\"}`,\n removeOnComplete: true,\n removeOnFail: true,\n })\n}\n\nconst shouldSkipCollection = (collName: string): boolean =>\n collName.endsWith(\".files\") || collName.endsWith(\".chunks\")\n\nconst INTERNAL_IGNORED_MODEL_NAMES = new Set([\"RBRtsChange\", \"RBRtsCounter\"])\n\nconst INTERNAL_IGNORED_COLLECTION_NAMES = new Set([\"rtschanges\", \"rtscounters\"])\n\nconst normalizeRetryDelays = (input: QueueListenerRetryDelays | undefined): Required<QueueListenerRetryDelays> => {\n const minMs = Math.max(0, Math.floor(input?.minMs ?? RETRY_MINIMUM_DELAY_MS))\n const rawMaxMs = Math.max(0, Math.floor(input?.maxMs ?? RETRY_MAXIMUM_DELAY_MS))\n const maxMs = Math.max(minMs, rawMaxMs)\n const factor = Math.max(1, Number.isFinite(input?.factor) ? (input?.factor ?? RETRY_DEFAULT_FACTOR) : RETRY_DEFAULT_FACTOR)\n return { minMs, maxMs, factor }\n}\n\nconst getRetryDelayMs = (attempt: number, delays: Required<QueueListenerRetryDelays>): number =>\n Math.min(delays.maxMs, Math.round(delays.minMs * Math.pow(delays.factor, Math.max(0, attempt - 1))))\n\nconst normalizeMaxRetries = (value: number | \"infinite\"): number | \"infinite\" => {\n if (value === \"infinite\") return value\n const parsed = Math.floor(value)\n return Number.isFinite(parsed) ? Math.max(0, parsed) : 0\n}\n\nexport const registerQueueListener = async (options: QueueListenerOptions = {}): Promise<QueueListenerHandle> => {\n const maxRetries = normalizeMaxRetries(options.maxRetries ?? \"infinite\")\n const fatalOnMaxRetries = options.fatalOnMaxRetries ?? false\n const retryDelays = normalizeRetryDelays(options.retryDelays)\n\n const appName = process.env.APP_NAME?.trim()\n if (!appName) {\n throw new Error(\"Missing APP_NAME (required to configure the worker DB change listener)\")\n }\n\n const mongoUrl = getMongoUrl()\n const mongoClientOptions: MongoClientOptions = {\n family: 4,\n serverSelectionTimeoutMS: 2000,\n connectTimeoutMS: 2000,\n ...options.mongoClientOptions,\n }\n\n let stopped = false\n const abortController = new AbortController()\n let client: MongoClient | null = null\n let stream: ChangeStream<Document> | null = null\n let resumeAfter: Document | null = null\n let processing = Promise.resolve()\n\n let status: QueueListenerStatus = { state: \"connecting\", attempt: 1 }\n const setStatus = (next: QueueListenerStatus): void => {\n status = next\n try {\n options.onStateChange?.(next)\n } catch (err) {\n console.warn(\"queue listener onStateChange failed\", err)\n }\n }\n\n let readySettled = false\n let readyResolve: (() => void) | null = null\n let readyReject: ((err: unknown) => void) | null = null\n const ready = new Promise<void>((resolve, reject) => {\n readyResolve = resolve\n readyReject = reject\n })\n\n const resolveReady = (): void => {\n if (readySettled) return\n readySettled = true\n readyResolve?.()\n }\n\n const rejectReady = (err: unknown): void => {\n if (readySettled) return\n readySettled = true\n readyReject?.(err)\n }\n\n const isChangeStreamHistoryLost = (err: unknown): boolean => {\n const maybeErr = err as { code?: unknown; codeName?: unknown }\n const code = typeof maybeErr.code === \"number\" ? maybeErr.code : null\n const codeName = typeof maybeErr.codeName === \"string\" ? maybeErr.codeName : \"\"\n const message = err instanceof Error ? err.message : String(err ?? \"\")\n\n return (\n code === 286\n || codeName === \"ChangeStreamHistoryLost\"\n || message.includes(\"ChangeStreamHistoryLost\")\n || message.includes(\"resume token\")\n || message.includes(\"Resume token\")\n || message.includes(\"resume of change stream was not possible\")\n || message.includes(\"cannot resume\")\n )\n }\n\n const close = async (): Promise<void> => {\n stopped = true\n abortController.abort()\n try {\n stream?.removeAllListeners()\n await stream?.close()\n } catch {\n // ignore\n }\n stream = null\n\n try {\n await client?.close()\n } catch {\n // ignore\n }\n client = null\n\n if (!readySettled) {\n rejectReady(new Error(\"queue listener closed before ready\"))\n }\n\n setStatus({ state: \"closed\" })\n }\n\n const closeResources = async (): Promise<void> => {\n try {\n stream?.removeAllListeners()\n await stream?.close()\n } catch {\n // ignore\n }\n stream = null\n\n try {\n await client?.close()\n } catch {\n // ignore\n }\n client = null\n }\n\n const startStream = async (): Promise<{ stoppedPromise: Promise<{ reason: \"close\" | \"error\"; error?: unknown }> }> => {\n if (stopped) return { stoppedPromise: Promise.resolve({ reason: \"close\" }) }\n\n if (stream) {\n try {\n stream.removeAllListeners()\n await stream.close()\n } catch {\n // ignore\n }\n stream = null\n }\n\n if (client) {\n try {\n await client.close()\n } catch {\n // ignore\n }\n client = null\n }\n\n client = new MongoClient(mongoUrl, mongoClientOptions)\n\n await client.connect()\n\n const dbMatch = { \"ns.db\": { $regex: `^${escapeRegex(appName)}-.*-db$` } }\n\n const pipeline: Document[] = [\n { $match: dbMatch },\n {\n $match: {\n operationType: { $in: [\"insert\", \"update\", \"replace\", \"delete\"] },\n }\n },\n { $match: { \"ns.coll\": { $nin: Array.from(INTERNAL_IGNORED_COLLECTION_NAMES) } } },\n ]\n\n stream = client.watch(pipeline, {\n fullDocument: \"updateLookup\",\n ...(resumeAfter ? { resumeAfter } : {}),\n })\n\n const stoppedPromise = new Promise<{ reason: \"close\" | \"error\"; error?: unknown }>((resolve) => {\n let settled = false\n const onAbort = () => settle({ reason: \"close\" })\n\n const settle = (result: { reason: \"close\" | \"error\"; error?: unknown }) => {\n if (settled) return\n settled = true\n abortController.signal.removeEventListener(\"abort\", onAbort)\n resolve(result)\n }\n\n abortController.signal.addEventListener(\"abort\", onAbort)\n stream?.once(\"close\", () => settle({ reason: \"close\" }))\n stream?.once(\"error\", (err) => settle({ reason: \"error\", error: err }))\n })\n\n stream.on(\"change\", (change: ChangeStreamDocument<Document>) => {\n const streamRef = stream\n processing = processing.then(async () => {\n const ns = \"ns\" in change ? change.ns : undefined\n const dbName = String(ns?.db ?? \"\")\n if (!dbName) return\n\n const collName = String(ns && \"coll\" in ns ? ns.coll : \"\")\n if (!collName) return\n if (shouldSkipCollection(collName)) return\n if (INTERNAL_IGNORED_COLLECTION_NAMES.has(collName)) return\n\n const modelName = resolveModelNameFromCollection(collName)\n if (!modelName) return\n if (INTERNAL_IGNORED_MODEL_NAMES.has(modelName)) return\n\n const op = String(change.operationType ?? \"\")\n if (!op) return\n const normalizedOp = normalizeOpForTaskName(op)\n\n let doc = \"fullDocument\" in change ? change.fullDocument : undefined\n if (!doc && normalizedOp === \"delete\") {\n doc = \"documentKey\" in change ? change.documentKey : undefined\n }\n if (!doc) return\n\n const updateDescription = \"updateDescription\" in change ? change.updateDescription : undefined\n\n try {\n await dispatchWorkerQueue({\n dbName,\n modelName,\n op: normalizedOp,\n doc,\n updateDescription,\n })\n\n resumeAfter = change?._id ?? resumeAfter\n } catch (err) {\n console.warn(\"queue listener failed to dispatch change\", err)\n try {\n await streamRef?.close()\n } catch {\n // ignore\n }\n }\n }).catch((err) => {\n console.warn(\"queue listener change handler failed\", err)\n })\n })\n\n stream.on(\"error\", (err) => {\n if (stopped) return\n if (resumeAfter && isChangeStreamHistoryLost(err)) {\n resumeAfter = null\n }\n try {\n void Promise.resolve(stream?.close()).catch(() => {})\n } catch {\n // ignore\n }\n })\n\n return { stoppedPromise }\n }\n\n const run = async (): Promise<void> => {\n let retryCounter = 0\n\n while (!stopped) {\n try {\n setStatus({ state: \"connecting\", attempt: retryCounter + 1 })\n\n const { stoppedPromise } = await startStream()\n retryCounter = 0\n setStatus({ state: \"ready\" })\n resolveReady()\n\n const end = await stoppedPromise\n if (stopped) return\n\n retryCounter += 1\n if (maxRetries !== \"infinite\" && retryCounter > maxRetries) {\n const err = end.reason === \"error\" ? end.error : new Error(\"queue listener closed\")\n setStatus({ state: \"failed\", attempt: retryCounter, error: err })\n if (fatalOnMaxRetries) {\n try {\n options.onFatal?.(err)\n } catch (fatalErr) {\n console.warn(\"queue listener onFatal failed\", fatalErr)\n }\n }\n rejectReady(err)\n abortController.abort()\n await closeResources()\n return\n }\n\n const delayMs = getRetryDelayMs(retryCounter, retryDelays)\n const err = end.reason === \"error\" ? end.error : new Error(\"queue listener closed\")\n console.warn(\"queue listener not ready, retrying in\", delayMs, err)\n setStatus({ state: \"error\", attempt: retryCounter, error: err, nextRetryInMs: delayMs })\n await closeResources()\n await sleep(delayMs, abortController.signal)\n } catch (err) {\n if (stopped) return\n\n retryCounter += 1\n if (maxRetries !== \"infinite\" && retryCounter > maxRetries) {\n setStatus({ state: \"failed\", attempt: retryCounter, error: err })\n if (fatalOnMaxRetries) {\n try {\n options.onFatal?.(err)\n } catch (fatalErr) {\n console.warn(\"queue listener onFatal failed\", fatalErr)\n }\n }\n rejectReady(err)\n abortController.abort()\n await closeResources()\n return\n }\n\n const delayMs = getRetryDelayMs(retryCounter, retryDelays)\n console.warn(\"queue listener not ready, retrying in\", delayMs, err)\n setStatus({ state: \"error\", attempt: retryCounter, error: err, nextRetryInMs: delayMs })\n await closeResources()\n await sleep(delayMs, abortController.signal)\n }\n }\n }\n\n const handle: QueueListenerHandle = {\n ready,\n close,\n getStatus: () => status,\n }\n\n void run().catch(async (err) => {\n if (stopped) return\n setStatus({ state: \"failed\", attempt: 0, error: err })\n rejectReady(err)\n await closeResources()\n })\n\n return handle\n}\n","export type DbEventOp = \"insert\" | \"update\" | \"delete\"\n\nexport type DbEventTaskName<TOp extends DbEventOp = DbEventOp, TModelName extends string = string> =\n `on-${TOp}-${TModelName}`\n\nexport type DbEventTaskPayload<TDoc = unknown, TUpdateDescription = unknown> = {\n doc: TDoc\n updateDescription?: TUpdateDescription\n}\n\nexport const dbEventTaskName = <TOp extends DbEventOp, TModelName extends string>(\n op: TOp,\n modelName: TModelName,\n): DbEventTaskName<TOp, TModelName> => `on-${op}-${modelName}`\n"],"names":["queue","close","err"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/queue.ts","../src/queueListener.ts","../src/taskNames.ts"],"sourcesContent":["import { Queue, Worker, type Job, type JobsOptions as JobOptions } from \"bullmq\"\n\nimport type { WorkerTasksMap } from \"./tasksMap\"\n\n\nexport type TaskHandler<TPayload = unknown> = (payload: TPayload, job: Job) => unknown | Promise<unknown>\n\nconst DEFAULT_QUEUE_NAME = \"rb-queue-default\"\nconst DEFAULT_CONCURRENCY = 2\nconst DEFAULT_RENTENTION = 128\n\nconst tasksByName: Record<string, TaskHandler<unknown>> = Object.create(null)\n\nlet queueInstance: Queue | null = null\nlet workerInstance: Worker | null = null\nlet hasStarted = false\n\nconst getRedisUrl = (): string => {\n const redisUrl = process.env.REDIS_URL?.trim()\n if (!redisUrl) {\n throw new Error(\"Missing REDIS_URL (required for @rpcbase/worker queue)\")\n }\n return redisUrl\n}\n\nconst getQueueName = (): string => process.env.RB_QUEUE_NAME?.trim() || DEFAULT_QUEUE_NAME\n\nconst getConcurrency = (): number => {\n const raw = process.env.RB_QUEUE_CONCURRENCY?.trim()\n const value = raw ? Number(raw) : DEFAULT_CONCURRENCY\n if (!Number.isFinite(value) || value <= 0) return DEFAULT_CONCURRENCY\n return Math.floor(value)\n}\n\nconst getConnection = () => ({ url: getRedisUrl() })\n\nconst ensureQueue = (): Queue => {\n if (queueInstance) return queueInstance\n queueInstance = new Queue(getQueueName(), {\n connection: getConnection(),\n defaultJobOptions: {\n removeOnComplete: DEFAULT_RENTENTION,\n removeOnFail: DEFAULT_RENTENTION\n },\n })\n\n return queueInstance\n}\n\nexport function registerTask<TName extends keyof WorkerTasksMap & string>(\n name: TName,\n handler: TaskHandler<WorkerTasksMap[TName]>,\n): void\nexport function registerTask(name: string, handler: TaskHandler<unknown>): void\nexport function registerTask(name: string, handler: TaskHandler<unknown>): void {\n tasksByName[name] = handler\n}\n\nexport const getTasks = (): Record<string, TaskHandler<unknown>> => tasksByName\n\nexport function add<TName extends keyof WorkerTasksMap & string>(\n taskName: TName,\n payload: WorkerTasksMap[TName],\n options?: JobOptions,\n): Promise<Job>\nexport function add(taskName: string, payload: unknown, options?: JobOptions): Promise<Job>\nexport function add(taskName: string, payload: unknown, options?: JobOptions): Promise<Job> {\n return ensureQueue().add(taskName, payload, options)\n}\n\nexport const getJob = async (jobId: string): Promise<Job | null> => (await ensureQueue().getJob(jobId)) ?? null\n\nexport const getJobs = async (...args: Parameters<Queue[\"getJobs\"]>): Promise<Job[]> =>\n ensureQueue().getJobs(...args) as unknown as Job[]\n\nexport const getInstance = (): Queue => ensureQueue()\n\nexport const start = async (): Promise<Queue> => {\n if (hasStarted) return ensureQueue()\n hasStarted = true\n\n const queue = ensureQueue()\n const concurrency = getConcurrency()\n\n console.log(\"start worker queue\", { queue: queue.name, redisUrl: getRedisUrl(), concurrency })\n\n queue.on(\"error\", (err) => {\n console.log(`queue error: ${err.message}`)\n })\n\n if (!workerInstance) {\n workerInstance = new Worker(\n queue.name,\n async (job) => {\n const taskName = job.name\n\n const handler = tasksByName[taskName]\n if (!handler) {\n throw new Error(`No task registered for '${taskName}'`)\n }\n\n return await handler(job.data, job)\n },\n {\n concurrency,\n connection: getConnection(),\n },\n )\n }\n\n workerInstance.on(\"error\", (err) => {\n console.log(`worker error: ${err.message}`)\n })\n\n workerInstance.on(\"stalled\", (jobId) => {\n console.log(`job ${jobId} stalled`)\n })\n\n workerInstance.on(\"failed\", (job, err) => {\n console.log(`job ${job?.id ?? \"unknown\"} failed`, err)\n })\n\n await workerInstance.waitUntilReady()\n\n return queue\n}\n\nexport const close = async (): Promise<void> => {\n if (!queueInstance && !workerInstance) return\n try {\n await workerInstance?.close()\n await queueInstance?.close()\n } finally {\n workerInstance = null\n queueInstance = null\n hasStarted = false\n }\n}\n\nexport const getUrl = (): string => getRedisUrl()\n\nexport type ScheduleTaskOptions = Omit<JobOptions, \"repeat\"> & {\n jobId?: string\n repeat: NonNullable<JobOptions[\"repeat\"]>\n}\n\nexport function scheduleTask<TName extends keyof WorkerTasksMap & string>(\n taskName: TName,\n payload: WorkerTasksMap[TName],\n options: ScheduleTaskOptions,\n): Promise<Job>\nexport function scheduleTask(taskName: string, payload: unknown, options: ScheduleTaskOptions): Promise<Job>\nexport async function scheduleTask(taskName: string, payload: unknown, options: ScheduleTaskOptions): Promise<Job> {\n const { jobId, repeat, ...rest } = options\n return add(taskName, payload, {\n ...rest,\n jobId: jobId ?? `schedule|${taskName}`,\n repeat,\n })\n}\n\nconst queueApi = {\n start,\n close,\n registerTask,\n getTasks,\n add,\n scheduleTask,\n getJob,\n getJobs,\n getInstance,\n getUrl,\n}\n\nexport default queueApi\n","import {\n MongoClient,\n type ChangeStream,\n type ChangeStreamDocument,\n type Document,\n type MongoClientOptions,\n} from \"mongodb\"\nimport mongoose from \"mongoose\"\n\nimport queue from \"./queue\"\n\n\nexport type QueueListenerRetryDelays = {\n minMs?: number\n maxMs?: number\n factor?: number\n}\n\nexport type QueueListenerStatus =\n | { state: \"connecting\"; attempt: number }\n | { state: \"ready\" }\n | { state: \"error\"; attempt: number; error: unknown; nextRetryInMs: number }\n | { state: \"failed\"; attempt: number; error: unknown }\n | { state: \"closed\" }\n\nexport type QueueListenerHandle = {\n ready: Promise<void>\n close: () => Promise<void>\n getStatus: () => QueueListenerStatus\n}\n\nexport type QueueListenerOptions = {\n maxRetries?: number | \"infinite\"\n fatalOnMaxRetries?: boolean\n onStateChange?: (status: QueueListenerStatus) => void\n onFatal?: (err: unknown) => void\n retryDelays?: QueueListenerRetryDelays\n mongoClientOptions?: MongoClientOptions\n}\n\nconst RETRY_MAXIMUM_DELAY_MS = 3000\nconst RETRY_MINIMUM_DELAY_MS = 50\nconst RETRY_DEFAULT_FACTOR = 2\n\nconst sleep = async (ms: number, signal?: AbortSignal): Promise<void> => new Promise((resolve) => {\n if (signal?.aborted) {\n resolve()\n return\n }\n\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n const cleanup = () => {\n if (timeout) clearTimeout(timeout)\n signal?.removeEventListener(\"abort\", onAbort)\n }\n\n const onAbort = () => {\n cleanup()\n resolve()\n }\n\n timeout = setTimeout(() => {\n cleanup()\n resolve()\n }, ms)\n timeout.unref?.()\n\n signal?.addEventListener(\"abort\", onAbort)\n})\n\nconst getMongoUrl = (): string => {\n const explicit =\n process.env.MONGODB_URL\n ?? process.env.MONGO_URL\n ?? process.env.MONGODB_URI\n ?? process.env.DB_URL\n\n if (explicit && explicit.trim()) return explicit.trim()\n\n const port = process.env.DB_PORT?.trim()\n if (!port) throw new Error(\"Missing Mongo connection details (MONGODB_URL/MONGO_URL/MONGODB_URI/DB_URL/DB_PORT)\")\n\n const host = process.env.DB_HOST?.trim() || \"localhost\"\n return `mongodb://${host}:${port}`\n}\n\nconst escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\ntype ModelWithCollection = {\n collection?: {\n collectionName?: string\n name?: string\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null\n\nconst getDocumentId = (doc: unknown): unknown => {\n if (!isRecord(doc)) return undefined\n return doc._id\n}\n\nconst resolveModelNameFromCollection = (collName: string): string | null => {\n const models = mongoose.models\n\n for (const modelName of Object.keys(models)) {\n const model = models[modelName] as ModelWithCollection\n const collectionName =\n model.collection?.collectionName\n ?? model.collection?.name\n\n if (collectionName === collName) {\n return modelName\n }\n }\n\n return null\n}\n\nconst normalizeUpdateDescription = (updateDescription: unknown): unknown => {\n if (!isRecord(updateDescription)) return updateDescription\n if (isRecord(updateDescription.updatedFields)) {\n return {\n ...updateDescription,\n updatedFieldsKeys: Object.keys(updateDescription.updatedFields),\n }\n }\n\n return updateDescription\n}\n\nconst normalizeOpForTaskName = (op: string): string => (op === \"replace\" ? \"update\" : op)\n\nconst dispatchWorkerQueue = async ({\n dbName,\n modelName,\n op,\n doc,\n updateDescription,\n}: {\n dbName: string\n modelName: string\n op: string\n doc: unknown\n updateDescription?: unknown\n}): Promise<void> => {\n const tasks = queue.getTasks()\n const taskOp = normalizeOpForTaskName(op)\n const handlerName = `on-${taskOp}-${modelName}`\n\n if (!tasks[handlerName]) return\n\n const normalizedUpdateDescription = normalizeUpdateDescription(updateDescription)\n\n await queue.add(handlerName, { doc, updateDescription: normalizedUpdateDescription }, {\n jobId: `${dbName}|${taskOp}-${getDocumentId(doc) ?? \"unknown\"}`,\n removeOnComplete: true,\n removeOnFail: true,\n })\n}\n\nconst shouldSkipCollection = (collName: string): boolean =>\n collName.endsWith(\".files\") || collName.endsWith(\".chunks\")\n\nconst INTERNAL_IGNORED_MODEL_NAMES = new Set([\"RBRtsChange\", \"RBRtsCounter\"])\n\nconst INTERNAL_IGNORED_COLLECTION_NAMES = new Set([\"rtschanges\", \"rtscounters\"])\n\nconst normalizeRetryDelays = (input: QueueListenerRetryDelays | undefined): Required<QueueListenerRetryDelays> => {\n const minMs = Math.max(0, Math.floor(input?.minMs ?? RETRY_MINIMUM_DELAY_MS))\n const rawMaxMs = Math.max(0, Math.floor(input?.maxMs ?? RETRY_MAXIMUM_DELAY_MS))\n const maxMs = Math.max(minMs, rawMaxMs)\n const factor = Math.max(1, Number.isFinite(input?.factor) ? (input?.factor ?? RETRY_DEFAULT_FACTOR) : RETRY_DEFAULT_FACTOR)\n return { minMs, maxMs, factor }\n}\n\nconst getRetryDelayMs = (attempt: number, delays: Required<QueueListenerRetryDelays>): number =>\n Math.min(delays.maxMs, Math.round(delays.minMs * Math.pow(delays.factor, Math.max(0, attempt - 1))))\n\nconst normalizeMaxRetries = (value: number | \"infinite\"): number | \"infinite\" => {\n if (value === \"infinite\") return value\n const parsed = Math.floor(value)\n return Number.isFinite(parsed) ? Math.max(0, parsed) : 0\n}\n\nexport const registerQueueListener = async (options: QueueListenerOptions = {}): Promise<QueueListenerHandle> => {\n const maxRetries = normalizeMaxRetries(options.maxRetries ?? \"infinite\")\n const fatalOnMaxRetries = options.fatalOnMaxRetries ?? false\n const retryDelays = normalizeRetryDelays(options.retryDelays)\n\n const appName = process.env.APP_NAME?.trim()\n if (!appName) {\n throw new Error(\"Missing APP_NAME (required to configure the worker DB change listener)\")\n }\n\n const mongoUrl = getMongoUrl()\n const mongoClientOptions: MongoClientOptions = {\n family: 4,\n serverSelectionTimeoutMS: 2000,\n connectTimeoutMS: 2000,\n ...options.mongoClientOptions,\n }\n\n let stopped = false\n const abortController = new AbortController()\n let client: MongoClient | null = null\n let stream: ChangeStream<Document> | null = null\n let resumeAfter: Document | null = null\n let processing = Promise.resolve()\n\n let status: QueueListenerStatus = { state: \"connecting\", attempt: 1 }\n const setStatus = (next: QueueListenerStatus): void => {\n status = next\n try {\n options.onStateChange?.(next)\n } catch (err) {\n console.warn(\"queue listener onStateChange failed\", err)\n }\n }\n\n let readySettled = false\n let readyResolve: (() => void) | null = null\n let readyReject: ((err: unknown) => void) | null = null\n const ready = new Promise<void>((resolve, reject) => {\n readyResolve = resolve\n readyReject = reject\n })\n\n const resolveReady = (): void => {\n if (readySettled) return\n readySettled = true\n readyResolve?.()\n }\n\n const rejectReady = (err: unknown): void => {\n if (readySettled) return\n readySettled = true\n readyReject?.(err)\n }\n\n const isChangeStreamHistoryLost = (err: unknown): boolean => {\n const maybeErr = err as { code?: unknown; codeName?: unknown }\n const code = typeof maybeErr.code === \"number\" ? maybeErr.code : null\n const codeName = typeof maybeErr.codeName === \"string\" ? maybeErr.codeName : \"\"\n const message = err instanceof Error ? err.message : String(err ?? \"\")\n\n return (\n code === 286\n || codeName === \"ChangeStreamHistoryLost\"\n || message.includes(\"ChangeStreamHistoryLost\")\n || message.includes(\"resume token\")\n || message.includes(\"Resume token\")\n || message.includes(\"resume of change stream was not possible\")\n || message.includes(\"cannot resume\")\n )\n }\n\n const close = async (): Promise<void> => {\n stopped = true\n abortController.abort()\n try {\n stream?.removeAllListeners()\n await stream?.close()\n } catch {\n // ignore\n }\n stream = null\n\n try {\n await client?.close()\n } catch {\n // ignore\n }\n client = null\n\n if (!readySettled) {\n rejectReady(new Error(\"queue listener closed before ready\"))\n }\n\n setStatus({ state: \"closed\" })\n }\n\n const closeResources = async (): Promise<void> => {\n try {\n stream?.removeAllListeners()\n await stream?.close()\n } catch {\n // ignore\n }\n stream = null\n\n try {\n await client?.close()\n } catch {\n // ignore\n }\n client = null\n }\n\n const startStream = async (): Promise<{ stoppedPromise: Promise<{ reason: \"close\" | \"error\"; error?: unknown }> }> => {\n if (stopped) return { stoppedPromise: Promise.resolve({ reason: \"close\" }) }\n\n if (stream) {\n try {\n stream.removeAllListeners()\n await stream.close()\n } catch {\n // ignore\n }\n stream = null\n }\n\n if (client) {\n try {\n await client.close()\n } catch {\n // ignore\n }\n client = null\n }\n\n client = new MongoClient(mongoUrl, mongoClientOptions)\n\n await client.connect()\n\n const dbMatch = { \"ns.db\": { $regex: `^${escapeRegex(appName)}-.*-db$` } }\n\n const pipeline: Document[] = [\n { $match: dbMatch },\n {\n $match: {\n operationType: { $in: [\"insert\", \"update\", \"replace\", \"delete\"] },\n }\n },\n { $match: { \"ns.coll\": { $nin: Array.from(INTERNAL_IGNORED_COLLECTION_NAMES) } } },\n ]\n\n stream = client.watch(pipeline, {\n fullDocument: \"updateLookup\",\n ...(resumeAfter ? { resumeAfter } : {}),\n })\n\n const stoppedPromise = new Promise<{ reason: \"close\" | \"error\"; error?: unknown }>((resolve) => {\n let settled = false\n const onAbort = () => settle({ reason: \"close\" })\n\n const settle = (result: { reason: \"close\" | \"error\"; error?: unknown }) => {\n if (settled) return\n settled = true\n abortController.signal.removeEventListener(\"abort\", onAbort)\n resolve(result)\n }\n\n abortController.signal.addEventListener(\"abort\", onAbort)\n stream?.once(\"close\", () => settle({ reason: \"close\" }))\n stream?.once(\"error\", (err) => settle({ reason: \"error\", error: err }))\n })\n\n stream.on(\"change\", (change: ChangeStreamDocument<Document>) => {\n const streamRef = stream\n processing = processing.then(async () => {\n const ns = \"ns\" in change ? change.ns : undefined\n const dbName = String(ns?.db ?? \"\")\n if (!dbName) return\n\n const collName = String(ns && \"coll\" in ns ? ns.coll : \"\")\n if (!collName) return\n if (shouldSkipCollection(collName)) return\n if (INTERNAL_IGNORED_COLLECTION_NAMES.has(collName)) return\n\n const modelName = resolveModelNameFromCollection(collName)\n if (!modelName) return\n if (INTERNAL_IGNORED_MODEL_NAMES.has(modelName)) return\n\n const op = String(change.operationType ?? \"\")\n if (!op) return\n const normalizedOp = normalizeOpForTaskName(op)\n\n let doc = \"fullDocument\" in change ? change.fullDocument : undefined\n if (!doc && normalizedOp === \"delete\") {\n doc = \"documentKey\" in change ? change.documentKey : undefined\n }\n if (!doc) return\n\n const updateDescription = \"updateDescription\" in change ? change.updateDescription : undefined\n\n try {\n await dispatchWorkerQueue({\n dbName,\n modelName,\n op: normalizedOp,\n doc,\n updateDescription,\n })\n\n resumeAfter = change?._id ?? resumeAfter\n } catch (err) {\n console.warn(\"queue listener failed to dispatch change\", err)\n try {\n await streamRef?.close()\n } catch {\n // ignore\n }\n }\n }).catch((err) => {\n console.warn(\"queue listener change handler failed\", err)\n })\n })\n\n stream.on(\"error\", (err) => {\n if (stopped) return\n if (resumeAfter && isChangeStreamHistoryLost(err)) {\n resumeAfter = null\n }\n try {\n void Promise.resolve(stream?.close()).catch(() => {})\n } catch {\n // ignore\n }\n })\n\n return { stoppedPromise }\n }\n\n const run = async (): Promise<void> => {\n let retryCounter = 0\n\n while (!stopped) {\n try {\n setStatus({ state: \"connecting\", attempt: retryCounter + 1 })\n\n const { stoppedPromise } = await startStream()\n retryCounter = 0\n setStatus({ state: \"ready\" })\n resolveReady()\n\n const end = await stoppedPromise\n if (stopped) return\n\n retryCounter += 1\n if (maxRetries !== \"infinite\" && retryCounter > maxRetries) {\n const err = end.reason === \"error\" ? end.error : new Error(\"queue listener closed\")\n setStatus({ state: \"failed\", attempt: retryCounter, error: err })\n if (fatalOnMaxRetries) {\n try {\n options.onFatal?.(err)\n } catch (fatalErr) {\n console.warn(\"queue listener onFatal failed\", fatalErr)\n }\n }\n rejectReady(err)\n abortController.abort()\n await closeResources()\n return\n }\n\n const delayMs = getRetryDelayMs(retryCounter, retryDelays)\n const err = end.reason === \"error\" ? end.error : new Error(\"queue listener closed\")\n console.warn(\"queue listener not ready, retrying in\", delayMs, err)\n setStatus({ state: \"error\", attempt: retryCounter, error: err, nextRetryInMs: delayMs })\n await closeResources()\n await sleep(delayMs, abortController.signal)\n } catch (err) {\n if (stopped) return\n\n retryCounter += 1\n if (maxRetries !== \"infinite\" && retryCounter > maxRetries) {\n setStatus({ state: \"failed\", attempt: retryCounter, error: err })\n if (fatalOnMaxRetries) {\n try {\n options.onFatal?.(err)\n } catch (fatalErr) {\n console.warn(\"queue listener onFatal failed\", fatalErr)\n }\n }\n rejectReady(err)\n abortController.abort()\n await closeResources()\n return\n }\n\n const delayMs = getRetryDelayMs(retryCounter, retryDelays)\n console.warn(\"queue listener not ready, retrying in\", delayMs, err)\n setStatus({ state: \"error\", attempt: retryCounter, error: err, nextRetryInMs: delayMs })\n await closeResources()\n await sleep(delayMs, abortController.signal)\n }\n }\n }\n\n const handle: QueueListenerHandle = {\n ready,\n close,\n getStatus: () => status,\n }\n\n void run().catch(async (err) => {\n if (stopped) return\n setStatus({ state: \"failed\", attempt: 0, error: err })\n rejectReady(err)\n await closeResources()\n })\n\n return handle\n}\n","export type DbEventOp = \"insert\" | \"update\" | \"delete\"\n\nexport type DbEventTaskName<TOp extends DbEventOp = DbEventOp, TModelName extends string = string> =\n `on-${TOp}-${TModelName}`\n\nexport type DbEventTaskPayload<TDoc = unknown, TUpdateDescription = unknown> = {\n doc: TDoc\n updateDescription?: TUpdateDescription\n}\n\nexport const dbEventTaskName = <TOp extends DbEventOp, TModelName extends string>(\n op: TOp,\n modelName: TModelName,\n): DbEventTaskName<TOp, TModelName> => `on-${op}-${modelName}`\n"],"names":["DEFAULT_QUEUE_NAME","DEFAULT_CONCURRENCY","DEFAULT_RENTENTION","tasksByName","Object","create","queueInstance","workerInstance","hasStarted","getRedisUrl","redisUrl","process","env","REDIS_URL","trim","Error","getQueueName","RB_QUEUE_NAME","getConcurrency","raw","RB_QUEUE_CONCURRENCY","value","Number","isFinite","Math","floor","getConnection","url","ensureQueue","Queue","connection","defaultJobOptions","removeOnComplete","removeOnFail","registerTask","name","handler","getTasks","add","taskName","payload","options","getJob","jobId","getJobs","args","getInstance","start","queue","concurrency","console","log","on","err","message","Worker","job","data","id","waitUntilReady","close","getUrl","scheduleTask","repeat","rest","queueApi","RETRY_MAXIMUM_DELAY_MS","RETRY_MINIMUM_DELAY_MS","RETRY_DEFAULT_FACTOR","sleep","ms","signal","Promise","resolve","aborted","timeout","cleanup","removeEventListener","onAbort","setTimeout","unref","addEventListener","getMongoUrl","explicit","MONGODB_URL","MONGO_URL","MONGODB_URI","DB_URL","port","DB_PORT","host","DB_HOST","escapeRegex","replace","isRecord","getDocumentId","doc","undefined","_id","resolveModelNameFromCollection","collName","models","mongoose","modelName","keys","model","collectionName","collection","normalizeUpdateDescription","updateDescription","updatedFields","updatedFieldsKeys","normalizeOpForTaskName","op","dispatchWorkerQueue","dbName","tasks","taskOp","handlerName","normalizedUpdateDescription","shouldSkipCollection","endsWith","INTERNAL_IGNORED_MODEL_NAMES","Set","INTERNAL_IGNORED_COLLECTION_NAMES","normalizeRetryDelays","input","minMs","max","rawMaxMs","maxMs","factor","getRetryDelayMs","attempt","delays","min","round","pow","normalizeMaxRetries","parsed","registerQueueListener","maxRetries","fatalOnMaxRetries","retryDelays","appName","APP_NAME","mongoUrl","mongoClientOptions","family","serverSelectionTimeoutMS","connectTimeoutMS","stopped","abortController","AbortController","client","stream","resumeAfter","processing","status","state","setStatus","next","onStateChange","warn","readySettled","readyResolve","readyReject","ready","reject","resolveReady","rejectReady","isChangeStreamHistoryLost","maybeErr","code","codeName","String","includes","abort","removeAllListeners","closeResources","startStream","stoppedPromise","reason","MongoClient","connect","dbMatch","$regex","pipeline","$match","operationType","$in","$nin","Array","from","watch","fullDocument","settled","settle","result","once","error","change","streamRef","then","ns","db","coll","has","normalizedOp","documentKey","catch","run","retryCounter","end","onFatal","fatalErr","delayMs","nextRetryInMs","handle","getStatus","dbEventTaskName"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/worker",
3
- "version": "0.31.0",
3
+ "version": "0.33.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"