@rvoh/psychic-workers 0.2.1

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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/dist/cjs/src/background/BaseBackgroundedModel.js +50 -0
  4. package/dist/cjs/src/background/BaseBackgroundedService.js +40 -0
  5. package/dist/cjs/src/background/BaseScheduledService.js +31 -0
  6. package/dist/cjs/src/background/index.js +529 -0
  7. package/dist/cjs/src/background/types.js +2 -0
  8. package/dist/cjs/src/error/background/NoQueueForSpecifiedQueueName.js +15 -0
  9. package/dist/cjs/src/error/background/NoQueueForSpecifiedWorkstream.js +15 -0
  10. package/dist/cjs/src/helpers/EnvInternal.js +5 -0
  11. package/dist/cjs/src/index.js +19 -0
  12. package/dist/cjs/src/psychic-application-workers/cache.js +17 -0
  13. package/dist/cjs/src/psychic-application-workers/index.js +77 -0
  14. package/dist/esm/src/background/BaseBackgroundedModel.js +47 -0
  15. package/dist/esm/src/background/BaseBackgroundedService.js +37 -0
  16. package/dist/esm/src/background/BaseScheduledService.js +28 -0
  17. package/dist/esm/src/background/index.js +524 -0
  18. package/dist/esm/src/background/types.js +1 -0
  19. package/dist/esm/src/error/background/NoQueueForSpecifiedQueueName.js +12 -0
  20. package/dist/esm/src/error/background/NoQueueForSpecifiedWorkstream.js +12 -0
  21. package/dist/esm/src/helpers/EnvInternal.js +3 -0
  22. package/dist/esm/src/index.js +7 -0
  23. package/dist/esm/src/psychic-application-workers/cache.js +12 -0
  24. package/dist/esm/src/psychic-application-workers/index.js +74 -0
  25. package/dist/types/src/background/BaseBackgroundedModel.d.ts +15 -0
  26. package/dist/types/src/background/BaseBackgroundedService.d.ts +17 -0
  27. package/dist/types/src/background/BaseScheduledService.d.ts +11 -0
  28. package/dist/types/src/background/index.d.ts +101 -0
  29. package/dist/types/src/background/types.d.ts +7 -0
  30. package/dist/types/src/error/background/NoQueueForSpecifiedQueueName.d.ts +5 -0
  31. package/dist/types/src/error/background/NoQueueForSpecifiedWorkstream.d.ts +5 -0
  32. package/dist/types/src/helpers/EnvInternal.d.ts +6 -0
  33. package/dist/types/src/index.d.ts +7 -0
  34. package/dist/types/src/psychic-application-workers/cache.d.ts +4 -0
  35. package/dist/types/src/psychic-application-workers/index.d.ts +200 -0
  36. package/package.json +74 -0
@@ -0,0 +1,529 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Background = void 0;
4
+ exports.stopBackgroundWorkers = stopBackgroundWorkers;
5
+ const dream_1 = require("@rvoh/dream");
6
+ const psychic_1 = require("@rvoh/psychic");
7
+ const bullmq_1 = require("bullmq");
8
+ const ioredis_1 = require("ioredis");
9
+ const NoQueueForSpecifiedQueueName_js_1 = require("../error/background/NoQueueForSpecifiedQueueName.js");
10
+ const NoQueueForSpecifiedWorkstream_js_1 = require("../error/background/NoQueueForSpecifiedWorkstream.js");
11
+ const EnvInternal_js_1 = require("../helpers/EnvInternal.js");
12
+ const index_js_1 = require("../psychic-application-workers/index.js");
13
+ class DefaultBullMQNativeOptionsMissingQueueConnectionAndDefaultQueueConnection extends Error {
14
+ get message() {
15
+ return `
16
+ Native BullMQ options don't include a default queue connection, and the
17
+ default config does not include a queue connection
18
+ `;
19
+ }
20
+ }
21
+ class NamedBullMQNativeOptionsMissingQueueConnectionAndDefaultQueueConnection extends Error {
22
+ queueName;
23
+ constructor(queueName) {
24
+ super();
25
+ this.queueName = queueName;
26
+ }
27
+ get message() {
28
+ return `
29
+ Native BullMQ options don't include a default queue connection, and the
30
+ ${this.queueName} queue does not include a queue connection
31
+ `;
32
+ }
33
+ }
34
+ class ActivatingBackgroundWorkersWithoutDefaultWorkerConnection extends Error {
35
+ get message() {
36
+ return `
37
+ defaultWorkerConnection is required when activating workers. For example,
38
+ it may be omitted on webserver instances, but is required on worker instances.
39
+ `;
40
+ }
41
+ }
42
+ class ActivatingNamedQueueBackgroundWorkersWithoutWorkerConnection extends Error {
43
+ queueName;
44
+ constructor(queueName) {
45
+ super();
46
+ this.queueName = queueName;
47
+ }
48
+ get message() {
49
+ return `
50
+ defaultWorkerConnection is missing, and the ${this.queueName} queue does not
51
+ specify a workerConnection. A worker connection isrequired when activating workers.
52
+ For example, it may be omitted on webserver instances, but is required on worker instances.
53
+ `;
54
+ }
55
+ }
56
+ class Background {
57
+ static get defaultQueueName() {
58
+ const psychicWorkersApp = index_js_1.default.getOrFail();
59
+ return `${(0, dream_1.pascalize)(psychicWorkersApp.psychicApp.appName)}BackgroundJobQueue`;
60
+ }
61
+ static get Worker() {
62
+ const psychicWorkersApp = index_js_1.default.getOrFail();
63
+ return (psychicWorkersApp.backgroundOptions.providers?.Worker || bullmq_1.Worker);
64
+ }
65
+ static get Queue() {
66
+ const psychicWorkersApp = index_js_1.default.getOrFail();
67
+ return (psychicWorkersApp.backgroundOptions.providers?.Queue || bullmq_1.Queue);
68
+ }
69
+ /**
70
+ * Used when adding jobs to the default queue
71
+ */
72
+ defaultQueue = null;
73
+ /**
74
+ * Used when adding jobs to the default transitional queue
75
+ */
76
+ defaultTransitionalQueue = null;
77
+ /**
78
+ * Used when adding jobs to a named queue
79
+ */
80
+ namedQueues = {};
81
+ groupNames = {};
82
+ workstreamNames = [];
83
+ /**
84
+ * Used when adding jobs to a named transitioanl queue
85
+ */
86
+ namedTransitionalQueues = {};
87
+ _workers = [];
88
+ redisConnections = [];
89
+ connect({ activateWorkers = false, } = {}) {
90
+ if (this.defaultQueue)
91
+ return;
92
+ const psychicWorkersApp = index_js_1.default.getOrFail();
93
+ const defaultBullMQQueueOptions = psychicWorkersApp.backgroundOptions.defaultBullMQQueueOptions || {};
94
+ if (psychicWorkersApp.backgroundOptions.nativeBullMQ) {
95
+ this.nativeBullMQConnect(defaultBullMQQueueOptions, psychicWorkersApp.backgroundOptions, { activateWorkers });
96
+ }
97
+ else {
98
+ this.simpleConnect(defaultBullMQQueueOptions, psychicWorkersApp.backgroundOptions, { activateWorkers });
99
+ }
100
+ }
101
+ get queues() {
102
+ return (0, dream_1.compact)([
103
+ this.defaultQueue,
104
+ ...Object.values(this.namedQueues).map(queue => queue),
105
+ this.defaultTransitionalQueue,
106
+ ...Object.values(this.namedTransitionalQueues).map(queue => queue),
107
+ ]);
108
+ }
109
+ get workers() {
110
+ return [...this._workers];
111
+ }
112
+ async shutdownAndExit() {
113
+ await this.shutdown();
114
+ process.exit();
115
+ }
116
+ async shutdown() {
117
+ await Promise.all(this._workers.map(worker => worker.close()));
118
+ const psychicWorkersApp = index_js_1.default.getOrFail();
119
+ for (const hook of psychicWorkersApp.hooks.workerShutdown) {
120
+ await hook();
121
+ }
122
+ await (0, dream_1.closeAllDbConnections)();
123
+ await this.closeAllRedisConnections();
124
+ }
125
+ async closeAllRedisConnections() {
126
+ for (const queue of this.queues) {
127
+ await queue.close();
128
+ }
129
+ for (const worker of this.workers) {
130
+ await worker.close();
131
+ }
132
+ for (const connection of this.redisConnections) {
133
+ try {
134
+ connection.disconnect();
135
+ }
136
+ catch {
137
+ // noop
138
+ }
139
+ }
140
+ }
141
+ simpleConnect(defaultBullMQQueueOptions, backgroundOptions, { activateWorkers = false, activatingTransitionalWorkstreams = false, }) {
142
+ const defaultQueueConnection = backgroundOptions.defaultQueueConnection;
143
+ const defaultWorkerConnection = backgroundOptions.defaultWorkerConnection;
144
+ if (defaultQueueConnection)
145
+ this.redisConnections.push(defaultQueueConnection);
146
+ if (defaultWorkerConnection)
147
+ this.redisConnections.push(defaultWorkerConnection);
148
+ // transitional queues must have the same names they had prior to making them
149
+ // transitional since the name is what identifies the queues and enables the
150
+ // queues to be worked off
151
+ const formattedQueueName = nameToRedisQueueName(Background.defaultQueueName, defaultQueueConnection);
152
+ ///////////////////////////////
153
+ // create default workstream //
154
+ ///////////////////////////////
155
+ const defaultQueue = new Background.Queue(formattedQueueName, {
156
+ ...defaultBullMQQueueOptions,
157
+ connection: defaultQueueConnection,
158
+ });
159
+ if (activatingTransitionalWorkstreams) {
160
+ this.defaultTransitionalQueue = defaultQueue;
161
+ }
162
+ else {
163
+ this.defaultQueue = defaultQueue;
164
+ }
165
+ ////////////////////////////////////
166
+ // end: create default workstream //
167
+ ////////////////////////////////////
168
+ /////////////////////////////
169
+ // create default workers //
170
+ /////////////////////////////
171
+ if (activateWorkers) {
172
+ if (!defaultWorkerConnection)
173
+ throw new ActivatingBackgroundWorkersWithoutDefaultWorkerConnection();
174
+ const workerCount = backgroundOptions.defaultWorkstream?.workerCount ?? 1;
175
+ for (let i = 0; i < workerCount; i++) {
176
+ this._workers.push(new Background.Worker(formattedQueueName, job => this.doWork(job), {
177
+ connection: defaultWorkerConnection,
178
+ concurrency: backgroundOptions.defaultWorkstream?.concurrency || 1,
179
+ }));
180
+ }
181
+ }
182
+ /////////////////////////////////
183
+ // end: create default workers //
184
+ /////////////////////////////////
185
+ //////////////////////////////
186
+ // create named workstreams //
187
+ //////////////////////////////
188
+ const namedWorkstreams = backgroundOptions.namedWorkstreams || [];
189
+ namedWorkstreams.forEach(namedWorkstream => {
190
+ if (namedWorkstream.queueConnection)
191
+ this.redisConnections.push(namedWorkstream.queueConnection);
192
+ if (namedWorkstream.workerConnection)
193
+ this.redisConnections.push(namedWorkstream.workerConnection);
194
+ const namedWorkstreamQueueConnection = namedWorkstream.queueConnection || defaultQueueConnection;
195
+ const namedWorkstreamWorkerConnection = namedWorkstream.workerConnection || defaultWorkerConnection;
196
+ // transitional queues must have the same names they had prior to making them
197
+ // transitional since the name is what identifies the queues and enables the
198
+ // queues to be worked off
199
+ const namedWorkstreamFormattedQueueName = nameToRedisQueueName(namedWorkstream.name, namedWorkstreamQueueConnection);
200
+ const namedQueue = new Background.Queue(namedWorkstreamFormattedQueueName, {
201
+ ...defaultBullMQQueueOptions,
202
+ connection: namedWorkstreamQueueConnection,
203
+ });
204
+ if (activatingTransitionalWorkstreams) {
205
+ this.namedTransitionalQueues[namedWorkstream.name] = namedQueue;
206
+ }
207
+ else {
208
+ this.namedQueues[namedWorkstream.name] = namedQueue;
209
+ this.workstreamNames.push(namedWorkstream.name);
210
+ }
211
+ //////////////////////////
212
+ // create named workers //
213
+ //////////////////////////
214
+ if (activateWorkers) {
215
+ if (!namedWorkstreamWorkerConnection)
216
+ throw new ActivatingNamedQueueBackgroundWorkersWithoutWorkerConnection(namedWorkstream.name);
217
+ const workerCount = namedWorkstream.workerCount ?? 1;
218
+ for (let i = 0; i < workerCount; i++) {
219
+ this._workers.push(new Background.Worker(namedWorkstreamFormattedQueueName, job => this.doWork(job), {
220
+ group: {
221
+ id: namedWorkstream.name,
222
+ limit: namedWorkstream.rateLimit,
223
+ },
224
+ connection: namedWorkstreamWorkerConnection,
225
+ concurrency: namedWorkstream.concurrency || 1,
226
+ // explicitly typing as WorkerOptions because Psychic can't be aware of BullMQ Pro options
227
+ }));
228
+ }
229
+ }
230
+ ///////////////////////////////
231
+ // end: create named workers //
232
+ ///////////////////////////////
233
+ });
234
+ ///////////////////////////////////
235
+ // end: create named workstreams //
236
+ ///////////////////////////////////
237
+ const transitionalWorkstreams = backgroundOptions
238
+ .transitionalWorkstreams;
239
+ if (transitionalWorkstreams) {
240
+ this.simpleConnect(defaultBullMQQueueOptions, transitionalWorkstreams, {
241
+ activateWorkers,
242
+ activatingTransitionalWorkstreams: true,
243
+ });
244
+ }
245
+ }
246
+ nativeBullMQConnect(defaultBullMQQueueOptions, backgroundOptions, { activateWorkers = false, }) {
247
+ const nativeBullMQ = backgroundOptions.nativeBullMQ;
248
+ const defaultQueueConnection = nativeBullMQ.defaultQueueOptions?.queueConnection || backgroundOptions.defaultQueueConnection;
249
+ const defaultWorkerConnection = nativeBullMQ.defaultQueueOptions?.workerConnection || backgroundOptions.defaultWorkerConnection;
250
+ if (defaultQueueConnection)
251
+ this.redisConnections.push(defaultQueueConnection);
252
+ if (defaultWorkerConnection)
253
+ this.redisConnections.push(defaultWorkerConnection);
254
+ if (!defaultQueueConnection)
255
+ throw new DefaultBullMQNativeOptionsMissingQueueConnectionAndDefaultQueueConnection();
256
+ const formattedQueueName = nameToRedisQueueName(Background.defaultQueueName, defaultQueueConnection);
257
+ //////////////////////////
258
+ // create default queue //
259
+ //////////////////////////
260
+ this.defaultQueue = new Background.Queue(formattedQueueName, {
261
+ ...defaultBullMQQueueOptions,
262
+ ...(nativeBullMQ.defaultQueueOptions || {}),
263
+ connection: defaultQueueConnection,
264
+ });
265
+ ///////////////////////////////
266
+ // end: create default queue //
267
+ ///////////////////////////////
268
+ /////////////////////////////
269
+ // create default workers //
270
+ /////////////////////////////
271
+ if (activateWorkers) {
272
+ if (!defaultWorkerConnection)
273
+ throw new ActivatingBackgroundWorkersWithoutDefaultWorkerConnection();
274
+ const workerCount = nativeBullMQ.defaultWorkerCount ?? 1;
275
+ for (let i = 0; i < workerCount; i++) {
276
+ this._workers.push(new Background.Worker(formattedQueueName, job => this.doWork(job), {
277
+ ...(backgroundOptions.nativeBullMQ.defaultWorkerOptions || {}),
278
+ connection: defaultWorkerConnection,
279
+ }));
280
+ }
281
+ }
282
+ /////////////////////////////////
283
+ // end: create default workers //
284
+ /////////////////////////////////
285
+ /////////////////////////
286
+ // create named queues //
287
+ /////////////////////////
288
+ const namedQueueOptionsMap = nativeBullMQ.namedQueueOptions || {};
289
+ Object.keys(namedQueueOptionsMap).forEach(queueName => {
290
+ const namedQueueOptions = namedQueueOptionsMap[queueName];
291
+ if (namedQueueOptions.queueConnection)
292
+ this.redisConnections.push(namedQueueOptions.queueConnection);
293
+ if (namedQueueOptions.workerConnection)
294
+ this.redisConnections.push(namedQueueOptions.workerConnection);
295
+ const namedQueueConnection = namedQueueOptions.queueConnection || defaultQueueConnection;
296
+ const namedWorkerConnection = namedQueueOptions.workerConnection || defaultWorkerConnection;
297
+ if (!namedQueueConnection)
298
+ throw new NamedBullMQNativeOptionsMissingQueueConnectionAndDefaultQueueConnection(queueName);
299
+ const formattedQueuename = nameToRedisQueueName(queueName, namedQueueConnection);
300
+ this.namedQueues[queueName] = new Background.Queue(formattedQueuename, {
301
+ ...defaultBullMQQueueOptions,
302
+ ...namedQueueOptions,
303
+ connection: namedQueueConnection,
304
+ });
305
+ //////////////////////////
306
+ // create extra workers //
307
+ //////////////////////////
308
+ const extraWorkerOptionsMap = nativeBullMQ.namedQueueWorkers || {};
309
+ const extraWorkerOptions = extraWorkerOptionsMap[queueName];
310
+ const extraWorkerCount = extraWorkerOptions ? (extraWorkerOptions.workerCount ?? 1) : 0;
311
+ this.groupNames[queueName] ||= [];
312
+ if (extraWorkerOptions.group?.id)
313
+ this.groupNames[queueName].push(extraWorkerOptions.group.id);
314
+ if (activateWorkers) {
315
+ if (!namedWorkerConnection)
316
+ throw new ActivatingNamedQueueBackgroundWorkersWithoutWorkerConnection(queueName);
317
+ for (let i = 0; i < extraWorkerCount; i++) {
318
+ this._workers.push(new Background.Worker(formattedQueuename, job => this.doWork(job), {
319
+ ...extraWorkerOptions,
320
+ connection: namedWorkerConnection,
321
+ }));
322
+ }
323
+ }
324
+ ///////////////////////////////
325
+ // end: create extra workers //
326
+ ///////////////////////////////
327
+ });
328
+ //////////////////////////////
329
+ // end: create named queues //
330
+ //////////////////////////////
331
+ }
332
+ work() {
333
+ this.connect({ activateWorkers: true });
334
+ process.on('SIGTERM', () => {
335
+ void this.shutdownAndExit();
336
+ });
337
+ process.on('SIGINT', () => {
338
+ void this.shutdownAndExit();
339
+ });
340
+ }
341
+ async staticMethod(ObjectClass, method, { delaySeconds, globalName, args = [], jobConfig = {}, }) {
342
+ this.connect();
343
+ await this._addToQueue(`BackgroundJobQueueStaticJob`, {
344
+ globalName,
345
+ method,
346
+ args,
347
+ }, {
348
+ delaySeconds,
349
+ jobConfig: jobConfig,
350
+ groupId: this.jobConfigToGroupId(jobConfig),
351
+ priority: this.jobConfigToPriority(jobConfig),
352
+ });
353
+ }
354
+ async scheduledMethod(ObjectClass, pattern, method, { globalName, args = [], jobConfig = {}, }) {
355
+ this.connect();
356
+ // `jobId` is used to determine uniqueness along with name and repeat pattern.
357
+ // Since the name is really a job type and never changes, the `jobId` is the only
358
+ // way to allow multiple jobs with the same cron repeat pattern. Uniqueness will
359
+ // now be enforced by combining class name, method name, and cron repeat pattern.
360
+ //
361
+ // See: https://docs.bullmq.io/guide/jobs/repeatable
362
+ const jobId = `${ObjectClass.name}:${method}`;
363
+ await this.queueInstance(jobConfig).add('BackgroundJobQueueStaticJob', {
364
+ globalName,
365
+ method,
366
+ args,
367
+ }, {
368
+ repeat: {
369
+ pattern,
370
+ },
371
+ jobId,
372
+ group: this.jobConfigToGroup(jobConfig),
373
+ priority: this.mapPriorityWordToPriorityNumber(this.jobConfigToPriority(jobConfig)),
374
+ // explicitly typing as JobsOptions because Psychic can't be aware of BullMQ Pro options
375
+ });
376
+ }
377
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
378
+ queueInstance(values) {
379
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
380
+ const workstreamConfig = values;
381
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
382
+ const queueConfig = values;
383
+ const queueInstance = typeof workstreamConfig.workstream === 'string'
384
+ ? this.namedQueues[workstreamConfig.workstream]
385
+ : typeof queueConfig.queue === 'string'
386
+ ? this.namedQueues[queueConfig.queue]
387
+ : this.defaultQueue;
388
+ if (!queueInstance) {
389
+ if (typeof workstreamConfig.workstream === 'string')
390
+ throw new NoQueueForSpecifiedWorkstream_js_1.default(workstreamConfig.workstream);
391
+ if (typeof queueConfig.queue === 'string')
392
+ throw new NoQueueForSpecifiedQueueName_js_1.default(queueConfig.queue);
393
+ }
394
+ return queueInstance;
395
+ }
396
+ async modelInstanceMethod(modelInstance, method, { delaySeconds, args = [], jobConfig = {}, }) {
397
+ this.connect();
398
+ await this._addToQueue('BackgroundJobQueueModelInstanceJob', {
399
+ id: modelInstance.primaryKeyValue,
400
+ globalName: modelInstance.constructor.globalName,
401
+ method,
402
+ args,
403
+ }, {
404
+ delaySeconds,
405
+ jobConfig: jobConfig,
406
+ groupId: this.jobConfigToGroupId(jobConfig),
407
+ priority: this.jobConfigToPriority(jobConfig),
408
+ });
409
+ }
410
+ // should be private, but public so we can test
411
+ async _addToQueue(jobType, jobData, { delaySeconds, jobConfig, priority, groupId, }) {
412
+ // set this variable out side of the conditional so that
413
+ // mismatches will raise exceptions even in tests
414
+ const queueInstance = this.queueInstance(jobConfig);
415
+ const delay = delaySeconds ? delaySeconds * 1000 : undefined;
416
+ if (EnvInternal_js_1.default.isTest && !EnvInternal_js_1.default.boolean('REALLY_TEST_BACKGROUND_QUEUE')) {
417
+ const queue = new Background.Queue('TestQueue', { connection: {} });
418
+ const job = new bullmq_1.Job(queue, jobType, jobData, {});
419
+ await this.doWork(job);
420
+ //
421
+ }
422
+ else if (groupId && priority) {
423
+ await queueInstance.add(jobType, jobData, {
424
+ delay,
425
+ group: {
426
+ ...this.groupIdToGroupConfig(groupId),
427
+ priority: this.mapPriorityWordToPriorityNumber(priority),
428
+ },
429
+ // explicitly typing as JobsOptions because Psychic can't be aware of BullMQ Pro options
430
+ });
431
+ //
432
+ }
433
+ else {
434
+ await queueInstance.add(jobType, jobData, {
435
+ delay,
436
+ group: this.groupIdToGroupConfig(groupId),
437
+ priority: this.mapPriorityWordToPriorityNumber(priority),
438
+ // explicitly typing as JobsOptions because Psychic can't be aware of BullMQ Pro options
439
+ });
440
+ }
441
+ }
442
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
443
+ jobConfigToPriority(jobConfig) {
444
+ if (!jobConfig)
445
+ return 'default';
446
+ return jobConfig.priority || 'default';
447
+ }
448
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
449
+ jobConfigToGroupId(jobConfig) {
450
+ if (!jobConfig)
451
+ return;
452
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
453
+ const workstreamConfig = jobConfig;
454
+ if (typeof workstreamConfig.workstream === 'string')
455
+ return workstreamConfig.workstream;
456
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
457
+ const queueConfig = jobConfig;
458
+ if (typeof queueConfig.groupId === 'string')
459
+ return queueConfig.groupId;
460
+ return;
461
+ }
462
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
463
+ jobConfigToGroup(jobConfig) {
464
+ return this.groupIdToGroupConfig(this.jobConfigToGroupId(jobConfig));
465
+ }
466
+ groupIdToGroupConfig(groupId) {
467
+ if (!groupId)
468
+ return;
469
+ return { id: groupId };
470
+ }
471
+ mapPriorityWordToPriorityNumber(priority) {
472
+ switch (priority) {
473
+ case 'urgent':
474
+ return 1;
475
+ case 'default':
476
+ return 2;
477
+ case 'not_urgent':
478
+ return 3;
479
+ case 'last':
480
+ return 4;
481
+ default:
482
+ return 2;
483
+ }
484
+ }
485
+ async doWork(job) {
486
+ const jobType = job.name;
487
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
488
+ const { id, method, args, globalName } = job.data;
489
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
490
+ let objectClass;
491
+ let dreamClass;
492
+ switch (jobType) {
493
+ case 'BackgroundJobQueueStaticJob':
494
+ if (globalName) {
495
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
496
+ objectClass = psychic_1.PsychicApplication.lookupClassByGlobalName(globalName);
497
+ }
498
+ if (!objectClass)
499
+ return;
500
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
501
+ await objectClass[method](...args, job);
502
+ break;
503
+ case 'BackgroundJobQueueModelInstanceJob':
504
+ if (globalName) {
505
+ dreamClass = psychic_1.PsychicApplication.lookupClassByGlobalName(globalName);
506
+ }
507
+ if (dreamClass) {
508
+ const modelInstance = await dreamClass.find(id);
509
+ if (!modelInstance)
510
+ return;
511
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
512
+ await modelInstance[method](...args, job);
513
+ }
514
+ break;
515
+ }
516
+ }
517
+ }
518
+ exports.Background = Background;
519
+ const background = new Background();
520
+ exports.default = background;
521
+ async function stopBackgroundWorkers() {
522
+ await background.shutdown();
523
+ }
524
+ function nameToRedisQueueName(queueName, redis) {
525
+ queueName = queueName.replace(/\{|\}/g, '');
526
+ if (redis instanceof ioredis_1.Cluster)
527
+ return `{${queueName}}`;
528
+ return queueName;
529
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class NoQueueForSpecifiedQueueName extends Error {
4
+ queue;
5
+ constructor(queue) {
6
+ super();
7
+ this.queue = queue;
8
+ }
9
+ get message() {
10
+ return `Error enqueueing background job
11
+ No queue matches "${this.queue}"
12
+ `;
13
+ }
14
+ }
15
+ exports.default = NoQueueForSpecifiedQueueName;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class NoQueueForSpecifiedWorkstream extends Error {
4
+ workstream;
5
+ constructor(workstream) {
6
+ super();
7
+ this.workstream = workstream;
8
+ }
9
+ get message() {
10
+ return `Error enqueueing background job
11
+ No queue found for workstream "${this.workstream}"
12
+ `;
13
+ }
14
+ }
15
+ exports.default = NoQueueForSpecifiedWorkstream;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const dream_1 = require("@rvoh/dream");
4
+ const EnvInternal = new dream_1.Env();
5
+ exports.default = EnvInternal;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoQueueForSpecifiedWorkstream = exports.NoQueueForSpecifiedQueueName = exports.PsychicApplicationWorkers = exports.BaseScheduledService = exports.BaseBackgroundedService = exports.BaseBackgroundedModel = exports.stopBackgroundWorkers = exports.Background = exports.background = void 0;
4
+ var index_js_1 = require("./background/index.js");
5
+ Object.defineProperty(exports, "background", { enumerable: true, get: function () { return index_js_1.default; } });
6
+ Object.defineProperty(exports, "Background", { enumerable: true, get: function () { return index_js_1.Background; } });
7
+ Object.defineProperty(exports, "stopBackgroundWorkers", { enumerable: true, get: function () { return index_js_1.stopBackgroundWorkers; } });
8
+ var BaseBackgroundedModel_js_1 = require("./background/BaseBackgroundedModel.js");
9
+ Object.defineProperty(exports, "BaseBackgroundedModel", { enumerable: true, get: function () { return BaseBackgroundedModel_js_1.default; } });
10
+ var BaseBackgroundedService_js_1 = require("./background/BaseBackgroundedService.js");
11
+ Object.defineProperty(exports, "BaseBackgroundedService", { enumerable: true, get: function () { return BaseBackgroundedService_js_1.default; } });
12
+ var BaseScheduledService_js_1 = require("./background/BaseScheduledService.js");
13
+ Object.defineProperty(exports, "BaseScheduledService", { enumerable: true, get: function () { return BaseScheduledService_js_1.default; } });
14
+ var index_js_2 = require("./psychic-application-workers/index.js");
15
+ Object.defineProperty(exports, "PsychicApplicationWorkers", { enumerable: true, get: function () { return index_js_2.default; } });
16
+ var NoQueueForSpecifiedQueueName_js_1 = require("./error/background/NoQueueForSpecifiedQueueName.js");
17
+ Object.defineProperty(exports, "NoQueueForSpecifiedQueueName", { enumerable: true, get: function () { return NoQueueForSpecifiedQueueName_js_1.default; } });
18
+ var NoQueueForSpecifiedWorkstream_js_1 = require("./error/background/NoQueueForSpecifiedWorkstream.js");
19
+ Object.defineProperty(exports, "NoQueueForSpecifiedWorkstream", { enumerable: true, get: function () { return NoQueueForSpecifiedWorkstream_js_1.default; } });
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cachePsychicWorkersApplication = cachePsychicWorkersApplication;
4
+ exports.getCachedPsychicWorkersApplication = getCachedPsychicWorkersApplication;
5
+ exports.getCachedPsychicWorkersApplicationOrFail = getCachedPsychicWorkersApplicationOrFail;
6
+ let _psychicWorkersApp = undefined;
7
+ function cachePsychicWorkersApplication(psychicWorkersApp) {
8
+ _psychicWorkersApp = psychicWorkersApp;
9
+ }
10
+ function getCachedPsychicWorkersApplication() {
11
+ return _psychicWorkersApp;
12
+ }
13
+ function getCachedPsychicWorkersApplicationOrFail() {
14
+ if (!_psychicWorkersApp)
15
+ throw new Error('must call `cachePsychicWorkersApplication` before loading cached psychic application workers');
16
+ return _psychicWorkersApp;
17
+ }