@modern-admin/queue 0.1.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/cron/cron-task.decorator.d.ts +30 -0
- package/dist/cron/cron-task.decorator.d.ts.map +1 -0
- package/dist/cron/cron-task.decorator.js +17 -0
- package/dist/cron/cron-task.decorator.js.map +1 -0
- package/dist/cron/cron.constants.d.ts +5 -0
- package/dist/cron/cron.constants.d.ts.map +1 -0
- package/dist/cron/cron.constants.js +5 -0
- package/dist/cron/cron.constants.js.map +1 -0
- package/dist/cron/cron.module.d.ts +19 -0
- package/dist/cron/cron.module.d.ts.map +1 -0
- package/dist/cron/cron.module.js +43 -0
- package/dist/cron/cron.module.js.map +1 -0
- package/dist/cron/cron.processor.d.ts +13 -0
- package/dist/cron/cron.processor.d.ts.map +1 -0
- package/dist/cron/cron.processor.js +83 -0
- package/dist/cron/cron.processor.js.map +1 -0
- package/dist/cron/cron.service.d.ts +38 -0
- package/dist/cron/cron.service.d.ts.map +1 -0
- package/dist/cron/cron.service.js +175 -0
- package/dist/cron/cron.service.js.map +1 -0
- package/dist/cron/cron.types.d.ts +10 -0
- package/dist/cron/cron.types.d.ts.map +1 -0
- package/dist/cron/cron.types.js +2 -0
- package/dist/cron/cron.types.js.map +1 -0
- package/dist/cron/index.d.ts +7 -0
- package/dist/cron/index.d.ts.map +1 -0
- package/dist/cron/index.js +6 -0
- package/dist/cron/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/queue.module.d.ts +49 -0
- package/dist/queue.module.d.ts.map +1 -0
- package/dist/queue.module.js +93 -0
- package/dist/queue.module.js.map +1 -0
- package/dist/queue.types.d.ts +20 -0
- package/dist/queue.types.d.ts.map +1 -0
- package/dist/queue.types.js +2 -0
- package/dist/queue.types.js.map +1 -0
- package/package.json +54 -0
- package/src/cron/cron-task.decorator.ts +34 -0
- package/src/cron/cron.constants.ts +4 -0
- package/src/cron/cron.module.ts +33 -0
- package/src/cron/cron.processor.ts +86 -0
- package/src/cron/cron.service.ts +178 -0
- package/src/cron/cron.types.ts +13 -0
- package/src/cron/index.ts +11 -0
- package/src/index.ts +19 -0
- package/src/queue.module.ts +94 -0
- package/src/queue.types.ts +16 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { JobsOptions } from 'bullmq';
|
|
2
|
+
export declare const CRON_TASK_META = "MODERN_ADMIN_CRON_TASK_META";
|
|
3
|
+
export interface CronTaskOptions {
|
|
4
|
+
/** Unique task name — used as the BullMQ job scheduler key. */
|
|
5
|
+
name: string;
|
|
6
|
+
/** Cron expression, e.g. `"0 8 * * *"` for every day at 08:00 UTC. */
|
|
7
|
+
cron: string;
|
|
8
|
+
/**
|
|
9
|
+
* When `true`, a distributed Redis lock is acquired before the handler runs.
|
|
10
|
+
* If the previous execution is still active, the new invocation is skipped.
|
|
11
|
+
*/
|
|
12
|
+
skipIfRunning?: boolean;
|
|
13
|
+
/** Extra BullMQ job options (excluding `repeat` which is controlled by `cron`). */
|
|
14
|
+
opts?: Omit<JobsOptions, 'repeat'>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Marks a service method as a BullMQ-backed cron task.
|
|
18
|
+
* The `CronService` discovers all decorated methods automatically on module init.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* @Injectable()
|
|
22
|
+
* export class ReportService {
|
|
23
|
+
* @CronTask({ name: 'daily-report', cron: '0 8 * * *' })
|
|
24
|
+
* async run(job: Job) {
|
|
25
|
+
* // ...
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
export declare const CronTask: (options: CronTaskOptions) => MethodDecorator;
|
|
30
|
+
//# sourceMappingURL=cron-task.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-task.decorator.d.ts","sourceRoot":"","sources":["../../src/cron/cron-task.decorator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAEzC,eAAO,MAAM,cAAc,gCAAgC,CAAA;AAE3D,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,mFAAmF;IACnF,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;CACnC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ,GAAI,SAAS,eAAe,KAAG,eACd,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SetMetadata } from '@nestjs/common';
|
|
2
|
+
export const CRON_TASK_META = 'MODERN_ADMIN_CRON_TASK_META';
|
|
3
|
+
/**
|
|
4
|
+
* Marks a service method as a BullMQ-backed cron task.
|
|
5
|
+
* The `CronService` discovers all decorated methods automatically on module init.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* @Injectable()
|
|
9
|
+
* export class ReportService {
|
|
10
|
+
* @CronTask({ name: 'daily-report', cron: '0 8 * * *' })
|
|
11
|
+
* async run(job: Job) {
|
|
12
|
+
* // ...
|
|
13
|
+
* }
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
export const CronTask = (options) => SetMetadata(CRON_TASK_META, options);
|
|
17
|
+
//# sourceMappingURL=cron-task.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-task.decorator.js","sourceRoot":"","sources":["../../src/cron/cron-task.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAG5C,MAAM,CAAC,MAAM,cAAc,GAAG,6BAA6B,CAAA;AAgB3D;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,OAAwB,EAAmB,EAAE,CACpE,WAAW,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.constants.d.ts","sourceRoot":"","sources":["../../src/cron/cron.constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,YAAY,CAAA;AACnC,eAAO,MAAM,+BAA+B,IAAI,CAAA;AAChD,eAAO,MAAM,gBAAgB,kBAAkB,CAAA;AAC/C,eAAO,MAAM,qBAAqB,MAAM,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.constants.js","sourceRoot":"","sources":["../../src/cron/cron.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAA;AACnC,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAA;AAChD,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAA;AAC/C,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global module that enables BullMQ-backed cron scheduling.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - `CronService` — register tasks imperatively or via `@CronTask` decorator
|
|
6
|
+
* - `CronProcessor` — BullMQ worker that dispatches jobs to their handlers
|
|
7
|
+
*
|
|
8
|
+
* Requires `QueueModule.forRoot()` to be imported in the root module.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // AppModule
|
|
12
|
+
* imports: [
|
|
13
|
+
* QueueModule.forRoot({ connection: { host: 'localhost', port: 6379 } }),
|
|
14
|
+
* CronModule,
|
|
15
|
+
* ]
|
|
16
|
+
*/
|
|
17
|
+
export declare class CronModule {
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=cron.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.module.d.ts","sourceRoot":"","sources":["../../src/cron/cron.module.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;GAeG;AACH,qBASa,UAAU;CAAG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Global, Module } from '@nestjs/common';
|
|
8
|
+
import { DiscoveryModule } from '@nestjs/core';
|
|
9
|
+
import { QueueModule } from '../queue.module.js';
|
|
10
|
+
import { CRON_QUEUE } from './cron.constants.js';
|
|
11
|
+
import { CronService } from './cron.service.js';
|
|
12
|
+
import { CronProcessor } from './cron.processor.js';
|
|
13
|
+
/**
|
|
14
|
+
* Global module that enables BullMQ-backed cron scheduling.
|
|
15
|
+
*
|
|
16
|
+
* Provides:
|
|
17
|
+
* - `CronService` — register tasks imperatively or via `@CronTask` decorator
|
|
18
|
+
* - `CronProcessor` — BullMQ worker that dispatches jobs to their handlers
|
|
19
|
+
*
|
|
20
|
+
* Requires `QueueModule.forRoot()` to be imported in the root module.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // AppModule
|
|
24
|
+
* imports: [
|
|
25
|
+
* QueueModule.forRoot({ connection: { host: 'localhost', port: 6379 } }),
|
|
26
|
+
* CronModule,
|
|
27
|
+
* ]
|
|
28
|
+
*/
|
|
29
|
+
let CronModule = class CronModule {
|
|
30
|
+
};
|
|
31
|
+
CronModule = __decorate([
|
|
32
|
+
Global(),
|
|
33
|
+
Module({
|
|
34
|
+
imports: [
|
|
35
|
+
DiscoveryModule,
|
|
36
|
+
QueueModule.register({ queues: [CRON_QUEUE] }),
|
|
37
|
+
],
|
|
38
|
+
providers: [CronService, CronProcessor],
|
|
39
|
+
exports: [CronService],
|
|
40
|
+
})
|
|
41
|
+
], CronModule);
|
|
42
|
+
export { CronModule };
|
|
43
|
+
//# sourceMappingURL=cron.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.module.js","sourceRoot":"","sources":["../../src/cron/cron.module.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD;;;;;;;;;;;;;;;GAeG;AAUI,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,UAAU;IATtB,MAAM,EAAE;IACR,MAAM,CAAC;QACN,OAAO,EAAE;YACP,eAAe;YACf,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;SAC/C;QACD,SAAS,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC;QACvC,OAAO,EAAE,CAAC,WAAW,CAAC;KACvB,CAAC;GACW,UAAU,CAAG"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { WorkerHost } from '@nestjs/bullmq';
|
|
2
|
+
import type { Job, Queue } from 'bullmq';
|
|
3
|
+
import type { CronService } from './cron.service.js';
|
|
4
|
+
export declare class CronProcessor extends WorkerHost {
|
|
5
|
+
private readonly cronService;
|
|
6
|
+
private readonly cronQueue;
|
|
7
|
+
private readonly logger;
|
|
8
|
+
constructor(cronService: CronService, cronQueue: Queue);
|
|
9
|
+
process(job: Job<unknown, unknown, string>): Promise<unknown>;
|
|
10
|
+
private processWithLock;
|
|
11
|
+
private executeHandler;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=cron.processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.processor.d.ts","sourceRoot":"","sources":["../../src/cron/cron.processor.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAOxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,qBACa,aAAc,SAAQ,UAAU;IAIzC,OAAO,CAAC,QAAQ,CAAC,WAAW;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;gBAGrC,WAAW,EAAE,WAAW,EACC,SAAS,EAAE,KAAK;IAKtD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;YAarD,eAAe;YAmCf,cAAc;CAe7B"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
var CronProcessor_1;
|
|
14
|
+
import { InjectQueue, Processor, WorkerHost } from '@nestjs/bullmq';
|
|
15
|
+
import { Logger } from '@nestjs/common';
|
|
16
|
+
import { CRON_LOCK_PREFIX, CRON_QUEUE, DEFAULT_CRON_LOCK_TTL, DEFAULT_CRON_WORKER_CONCURRENCY, } from './cron.constants.js';
|
|
17
|
+
let CronProcessor = CronProcessor_1 = class CronProcessor extends WorkerHost {
|
|
18
|
+
constructor(cronService, cronQueue) {
|
|
19
|
+
super();
|
|
20
|
+
this.cronService = cronService;
|
|
21
|
+
this.cronQueue = cronQueue;
|
|
22
|
+
this.logger = new Logger(CronProcessor_1.name);
|
|
23
|
+
}
|
|
24
|
+
async process(job) {
|
|
25
|
+
const handler = this.cronService.getHandler(job.name);
|
|
26
|
+
if (!handler) {
|
|
27
|
+
const msg = `No cron handler registered for "${job.name}"`;
|
|
28
|
+
this.logger.error(msg);
|
|
29
|
+
throw new Error(msg);
|
|
30
|
+
}
|
|
31
|
+
return this.cronService.shouldSkipIfRunning(job.name)
|
|
32
|
+
? this.processWithLock(job, handler)
|
|
33
|
+
: this.executeHandler(job, handler);
|
|
34
|
+
}
|
|
35
|
+
async processWithLock(job, handler) {
|
|
36
|
+
const lockKey = `${CRON_LOCK_PREFIX}${job.name}`;
|
|
37
|
+
const client = await this.cronQueue.client;
|
|
38
|
+
// Atomic SET NX EX via the generic `runCommand` escape hatch on
|
|
39
|
+
// bullmq's `IRedisClient`. We can't use `client.set(..., { EX, NX })`
|
|
40
|
+
// because bullmq 5.77+ abstracted the client surface and dropped the
|
|
41
|
+
// `NX` option from `set`'s typed overloads (it now only accepts
|
|
42
|
+
// `{ PX?, EX? }`). `runCommand` is the documented portable way to
|
|
43
|
+
// reach any Redis command across ioredis / node-redis / bun-redis
|
|
44
|
+
// adapters. Returns the raw bulk-string reply ("OK") or nil.
|
|
45
|
+
const acquired = (await client.runCommand('set', [
|
|
46
|
+
lockKey,
|
|
47
|
+
job.id,
|
|
48
|
+
'EX',
|
|
49
|
+
DEFAULT_CRON_LOCK_TTL,
|
|
50
|
+
'NX',
|
|
51
|
+
]));
|
|
52
|
+
if (!acquired) {
|
|
53
|
+
this.logger.warn(`Skipping "${job.name}" (jobId=${job.id}) — previous instance still running`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return await this.executeHandler(job, handler);
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
await client.del(lockKey);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async executeHandler(job, handler) {
|
|
64
|
+
const start = Date.now();
|
|
65
|
+
this.logger.log(`Cron task "${job.name}" started (jobId=${job.id})`);
|
|
66
|
+
try {
|
|
67
|
+
const result = await handler(job);
|
|
68
|
+
this.logger.log(`Cron task "${job.name}" completed in ${Date.now() - start}ms`);
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
this.logger.error(`Cron task "${job.name}" failed after ${Date.now() - start}ms`, err);
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
CronProcessor = CronProcessor_1 = __decorate([
|
|
78
|
+
Processor(CRON_QUEUE, { concurrency: DEFAULT_CRON_WORKER_CONCURRENCY }),
|
|
79
|
+
__param(1, InjectQueue(CRON_QUEUE)),
|
|
80
|
+
__metadata("design:paramtypes", [Function, Function])
|
|
81
|
+
], CronProcessor);
|
|
82
|
+
export { CronProcessor };
|
|
83
|
+
//# sourceMappingURL=cron.processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.processor.js","sourceRoot":"","sources":["../../src/cron/cron.processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type OnModuleDestroy, type OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { DiscoveryService, Reflector } from '@nestjs/core';
|
|
3
|
+
import type { Queue } from 'bullmq';
|
|
4
|
+
import type { CronHandler, CronTaskDefinition } from './cron.types.js';
|
|
5
|
+
export declare class CronService implements OnModuleInit, OnModuleDestroy {
|
|
6
|
+
private readonly cronQueue;
|
|
7
|
+
private readonly discoveryService;
|
|
8
|
+
private readonly reflector;
|
|
9
|
+
private readonly logger;
|
|
10
|
+
private readonly handlers;
|
|
11
|
+
private readonly skipIfRunningSet;
|
|
12
|
+
private readonly definitions;
|
|
13
|
+
private initialized;
|
|
14
|
+
constructor(cronQueue: Queue, discoveryService: DiscoveryService, reflector: Reflector);
|
|
15
|
+
/**
|
|
16
|
+
* Register a cron task imperatively.
|
|
17
|
+
* If called before `onModuleInit`, it is picked up by `syncSchedulers`.
|
|
18
|
+
* If called after `onModuleInit`, the scheduler is upserted in BullMQ immediately.
|
|
19
|
+
*/
|
|
20
|
+
register<TData = unknown, TResult = unknown>(definition: CronTaskDefinition<TData, TResult>): void;
|
|
21
|
+
getHandler<TData = unknown, TResult = unknown>(name: string): CronHandler<TData, TResult> | undefined;
|
|
22
|
+
shouldSkipIfRunning(name: string): boolean;
|
|
23
|
+
onModuleInit(): Promise<void>;
|
|
24
|
+
onModuleDestroy(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Remove specific cron tasks by name — deletes their schedulers and any
|
|
27
|
+
* waiting/delayed jobs from Redis.
|
|
28
|
+
*/
|
|
29
|
+
purgeTasks(names: string[]): Promise<void>;
|
|
30
|
+
private discoverCronTasks;
|
|
31
|
+
/**
|
|
32
|
+
* Synchronise repeatable job schedulers in Redis with the current definitions.
|
|
33
|
+
* Removes stale schedulers no longer defined in code, then upserts all current ones.
|
|
34
|
+
*/
|
|
35
|
+
private syncSchedulers;
|
|
36
|
+
private upsertScheduler;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=cron.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.service.d.ts","sourceRoot":"","sources":["../../src/cron/cron.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE1D,OAAO,KAAK,EAAO,KAAK,EAAE,MAAM,QAAQ,CAAA;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAGtE,qBACa,WAAY,YAAW,YAAY,EAAE,eAAe;IAQpC,OAAO,CAAC,QAAQ,CAAC,SAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAT5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2B;IACvD,OAAO,CAAC,WAAW,CAAQ;gBAGiB,SAAS,EAAE,KAAK,EACzC,gBAAgB,EAAE,gBAAgB,EAClC,SAAS,EAAE,SAAS;IAGvC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EACzC,UAAU,EAAE,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,GAC7C,IAAI;IAaP,UAAU,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAC3C,IAAI,EAAE,MAAM,GACX,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,SAAS;IAI1C,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAW7B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BhD,OAAO,CAAC,iBAAiB;IA6BzB;;;OAGG;YACW,cAAc;YAsBd,eAAe;CAmB9B"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
var CronService_1;
|
|
14
|
+
import { Injectable, Logger, } from '@nestjs/common';
|
|
15
|
+
import { DiscoveryService, Reflector } from '@nestjs/core';
|
|
16
|
+
import { InjectQueue } from '@nestjs/bullmq';
|
|
17
|
+
import { CRON_QUEUE } from './cron.constants.js';
|
|
18
|
+
import { CRON_TASK_META } from './cron-task.decorator.js';
|
|
19
|
+
let CronService = CronService_1 = class CronService {
|
|
20
|
+
constructor(cronQueue, discoveryService, reflector) {
|
|
21
|
+
this.cronQueue = cronQueue;
|
|
22
|
+
this.discoveryService = discoveryService;
|
|
23
|
+
this.reflector = reflector;
|
|
24
|
+
this.logger = new Logger(CronService_1.name);
|
|
25
|
+
this.handlers = new Map();
|
|
26
|
+
this.skipIfRunningSet = new Set();
|
|
27
|
+
this.definitions = [];
|
|
28
|
+
this.initialized = false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Register a cron task imperatively.
|
|
32
|
+
* If called before `onModuleInit`, it is picked up by `syncSchedulers`.
|
|
33
|
+
* If called after `onModuleInit`, the scheduler is upserted in BullMQ immediately.
|
|
34
|
+
*/
|
|
35
|
+
register(definition) {
|
|
36
|
+
if (this.handlers.has(definition.name)) {
|
|
37
|
+
throw new Error(`Cron task "${definition.name}" is already registered`);
|
|
38
|
+
}
|
|
39
|
+
this.handlers.set(definition.name, definition.handler);
|
|
40
|
+
if (definition.skipIfRunning)
|
|
41
|
+
this.skipIfRunningSet.add(definition.name);
|
|
42
|
+
this.definitions.push(definition);
|
|
43
|
+
if (this.initialized) {
|
|
44
|
+
void this.upsertScheduler(definition);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
getHandler(name) {
|
|
48
|
+
return this.handlers.get(name);
|
|
49
|
+
}
|
|
50
|
+
shouldSkipIfRunning(name) {
|
|
51
|
+
return this.skipIfRunningSet.has(name);
|
|
52
|
+
}
|
|
53
|
+
async onModuleInit() {
|
|
54
|
+
this.discoverCronTasks();
|
|
55
|
+
try {
|
|
56
|
+
await this.syncSchedulers();
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
this.logger.error('Failed to sync cron schedulers on init', err);
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
this.initialized = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async onModuleDestroy() {
|
|
66
|
+
await this.cronQueue.close();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Remove specific cron tasks by name — deletes their schedulers and any
|
|
70
|
+
* waiting/delayed jobs from Redis.
|
|
71
|
+
*/
|
|
72
|
+
async purgeTasks(names) {
|
|
73
|
+
const schedulers = await this.cronQueue.getJobSchedulers();
|
|
74
|
+
for (const s of schedulers) {
|
|
75
|
+
if (names.includes(s.name)) {
|
|
76
|
+
try {
|
|
77
|
+
await this.cronQueue.removeJobScheduler(s.key);
|
|
78
|
+
this.logger.log(`Purged scheduler: ${s.name}`);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
this.logger.error(`Failed to purge scheduler ${s.name}`, err);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const jobs = (await this.cronQueue.getJobs(['waiting', 'delayed']));
|
|
86
|
+
for (const j of jobs) {
|
|
87
|
+
if (!j)
|
|
88
|
+
continue;
|
|
89
|
+
if (names.includes(j.name)) {
|
|
90
|
+
try {
|
|
91
|
+
await j.remove();
|
|
92
|
+
this.logger.log(`Purged job: ${j.name} (id=${j.id})`);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
this.logger.error(`Failed to purge job ${j.name}`, err);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
discoverCronTasks() {
|
|
101
|
+
const providers = this.discoveryService.getProviders();
|
|
102
|
+
for (const wrapper of providers) {
|
|
103
|
+
const instance = wrapper.instance;
|
|
104
|
+
if (!instance || typeof instance !== 'object')
|
|
105
|
+
continue;
|
|
106
|
+
const prototype = Object.getPrototypeOf(instance);
|
|
107
|
+
for (const key of Object.getOwnPropertyNames(prototype)) {
|
|
108
|
+
if (key === 'constructor')
|
|
109
|
+
continue;
|
|
110
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
|
|
111
|
+
if (!descriptor || typeof descriptor.value !== 'function')
|
|
112
|
+
continue;
|
|
113
|
+
const meta = this.reflector.get(CRON_TASK_META, descriptor.value);
|
|
114
|
+
if (!meta)
|
|
115
|
+
continue;
|
|
116
|
+
const method = instance[key];
|
|
117
|
+
if (typeof method !== 'function')
|
|
118
|
+
continue;
|
|
119
|
+
this.register({
|
|
120
|
+
name: meta.name,
|
|
121
|
+
cron: meta.cron,
|
|
122
|
+
handler: (job) => method.call(instance, job),
|
|
123
|
+
skipIfRunning: meta.skipIfRunning,
|
|
124
|
+
opts: meta.opts,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Synchronise repeatable job schedulers in Redis with the current definitions.
|
|
131
|
+
* Removes stale schedulers no longer defined in code, then upserts all current ones.
|
|
132
|
+
*/
|
|
133
|
+
async syncSchedulers() {
|
|
134
|
+
const registeredNames = new Set(this.definitions.map((d) => d.name));
|
|
135
|
+
const existing = await this.cronQueue.getJobSchedulers();
|
|
136
|
+
for (const scheduler of existing) {
|
|
137
|
+
if (!registeredNames.has(scheduler.name)) {
|
|
138
|
+
try {
|
|
139
|
+
await this.cronQueue.removeJobScheduler(scheduler.key);
|
|
140
|
+
this.logger.log(`Removed stale cron scheduler: ${scheduler.name} (key=${scheduler.key})`);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
this.logger.error(`Failed to remove stale scheduler ${scheduler.name}`, err);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
for (const def of this.definitions) {
|
|
148
|
+
await this.upsertScheduler(def);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async upsertScheduler(def) {
|
|
152
|
+
try {
|
|
153
|
+
await this.cronQueue.upsertJobScheduler(def.name, { pattern: def.cron }, {
|
|
154
|
+
name: def.name,
|
|
155
|
+
opts: {
|
|
156
|
+
removeOnComplete: { count: 100 },
|
|
157
|
+
removeOnFail: { count: 100 },
|
|
158
|
+
...def.opts,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
this.logger.log(`Cron task scheduled: "${def.name}" [${def.cron}]`);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
this.logger.error(`Failed to schedule cron task "${def.name}"`, err);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
CronService = CronService_1 = __decorate([
|
|
169
|
+
Injectable(),
|
|
170
|
+
__param(0, InjectQueue(CRON_QUEUE)),
|
|
171
|
+
__metadata("design:paramtypes", [Function, DiscoveryService,
|
|
172
|
+
Reflector])
|
|
173
|
+
], CronService);
|
|
174
|
+
export { CronService };
|
|
175
|
+
//# sourceMappingURL=cron.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.service.js","sourceRoot":"","sources":["../../src/cron/cron.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Job, JobsOptions } from 'bullmq';
|
|
2
|
+
export type CronHandler<TData = unknown, TResult = unknown> = (job: Job<TData, TResult, string>) => Promise<TResult> | TResult;
|
|
3
|
+
export interface CronTaskDefinition<TData = unknown, TResult = unknown> {
|
|
4
|
+
name: string;
|
|
5
|
+
cron: string;
|
|
6
|
+
handler: CronHandler<TData, TResult>;
|
|
7
|
+
skipIfRunning?: boolean;
|
|
8
|
+
opts?: Omit<JobsOptions, 'repeat'>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=cron.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.types.d.ts","sourceRoot":"","sources":["../../src/cron/cron.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAE9C,MAAM,MAAM,WAAW,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,CAC5D,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,KAC7B,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;AAE/B,MAAM,WAAW,kBAAkB,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACpC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;CACnC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.types.js","sourceRoot":"","sources":["../../src/cron/cron.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CronModule } from './cron.module.js';
|
|
2
|
+
export { CronService } from './cron.service.js';
|
|
3
|
+
export { CronProcessor } from './cron.processor.js';
|
|
4
|
+
export { CronTask, CRON_TASK_META, type CronTaskOptions } from './cron-task.decorator.js';
|
|
5
|
+
export type { CronHandler, CronTaskDefinition } from './cron.types.js';
|
|
6
|
+
export { CRON_QUEUE, CRON_LOCK_PREFIX, DEFAULT_CRON_WORKER_CONCURRENCY, DEFAULT_CRON_LOCK_TTL, } from './cron.constants.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cron/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACzF,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,+BAA+B,EAC/B,qBAAqB,GACtB,MAAM,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CronModule } from './cron.module.js';
|
|
2
|
+
export { CronService } from './cron.service.js';
|
|
3
|
+
export { CronProcessor } from './cron.processor.js';
|
|
4
|
+
export { CronTask, CRON_TASK_META } from './cron-task.decorator.js';
|
|
5
|
+
export { CRON_QUEUE, CRON_LOCK_PREFIX, DEFAULT_CRON_WORKER_CONCURRENCY, DEFAULT_CRON_LOCK_TTL, } from './cron.constants.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cron/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAwB,MAAM,0BAA0B,CAAA;AAEzF,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,+BAA+B,EAC/B,qBAAqB,GACtB,MAAM,qBAAqB,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { QueueModule } from './queue.module.js';
|
|
2
|
+
export type { QueueModuleOptions, QueueRootOptions } from './queue.types.js';
|
|
3
|
+
export { CronModule, CronService, CronProcessor, CronTask, CRON_TASK_META, CRON_QUEUE, CRON_LOCK_PREFIX, DEFAULT_CRON_WORKER_CONCURRENCY, DEFAULT_CRON_LOCK_TTL, type CronTaskOptions, type CronHandler, type CronTaskDefinition, } from './cron';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAE5E,OAAO,EACL,UAAU,EACV,WAAW,EACX,aAAa,EACb,QAAQ,EACR,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,+BAA+B,EAC/B,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,QAAQ,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// @modern-admin/queue — BullMQ queue + cron scheduling for NestJS.
|
|
2
|
+
export { QueueModule } from './queue.module.js';
|
|
3
|
+
export { CronModule, CronService, CronProcessor, CronTask, CRON_TASK_META, CRON_QUEUE, CRON_LOCK_PREFIX, DEFAULT_CRON_WORKER_CONCURRENCY, DEFAULT_CRON_LOCK_TTL, } from './cron';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAEnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAG/C,OAAO,EACL,UAAU,EACV,WAAW,EACX,aAAa,EACb,QAAQ,EACR,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,+BAA+B,EAC/B,qBAAqB,GAItB,MAAM,QAAQ,CAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type DynamicModule } from '@nestjs/common';
|
|
2
|
+
import type { QueueModuleOptions, QueueRootOptions } from './queue.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* BullMQ integration module for modern-admin NestJS applications.
|
|
5
|
+
*
|
|
6
|
+
* 1. Call `QueueModule.forRoot()` once in the root AppModule to configure the
|
|
7
|
+
* Redis connection globally.
|
|
8
|
+
* 2. Call `QueueModule.register({ queues: [...] })` in any feature module to
|
|
9
|
+
* register named queues and make their injection tokens available.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // AppModule
|
|
13
|
+
* imports: [
|
|
14
|
+
* QueueModule.forRoot({ connection: { host: 'localhost', port: 6379 } }),
|
|
15
|
+
* QueueModule.register({ queues: ['emails', 'exports'] }),
|
|
16
|
+
* CronModule,
|
|
17
|
+
* ]
|
|
18
|
+
*/
|
|
19
|
+
export declare class QueueModule {
|
|
20
|
+
/**
|
|
21
|
+
* Configure the BullMQ Redis connection for the whole application.
|
|
22
|
+
* Must be imported once at the root level before any `register()` call.
|
|
23
|
+
*/
|
|
24
|
+
static forRoot(options: QueueRootOptions): DynamicModule;
|
|
25
|
+
/**
|
|
26
|
+
* Async variant of `forRoot` — useful when the Redis URL comes from a
|
|
27
|
+
* config service or environment variable loaded at runtime.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* QueueModule.forRootAsync({
|
|
31
|
+
* imports: [ConfigModule],
|
|
32
|
+
* inject: [ConfigService],
|
|
33
|
+
* useFactory: (cfg: ConfigService) => ({
|
|
34
|
+
* connection: cfg.get('REDIS_URL'),
|
|
35
|
+
* }),
|
|
36
|
+
* })
|
|
37
|
+
*/
|
|
38
|
+
static forRootAsync(opts: {
|
|
39
|
+
imports?: DynamicModule['imports'];
|
|
40
|
+
inject?: unknown[];
|
|
41
|
+
useFactory: (...args: unknown[]) => QueueRootOptions | Promise<QueueRootOptions>;
|
|
42
|
+
}): DynamicModule;
|
|
43
|
+
/**
|
|
44
|
+
* Register named queues (and optional flow producers) in the current module.
|
|
45
|
+
* Exports the BullMQ tokens so they can be injected via `@InjectQueue(name)`.
|
|
46
|
+
*/
|
|
47
|
+
static register(options: QueueModuleOptions): DynamicModule;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=queue.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.module.d.ts","sourceRoot":"","sources":["../src/queue.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAU,MAAM,gBAAgB,CAAA;AAE3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAE5E;;;;;;;;;;;;;;;GAeG;AACH,qBACa,WAAW;IACtB;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa;IAaxD;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE;QACxB,OAAO,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAA;QAClC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAA;QAClB,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;KACjF,GAAG,aAAa;IAoBjB;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,aAAa;CAa5D"}
|