@fluojs/queue 1.0.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +171 -8
- package/README.md +171 -8
- package/dist/dead-letter-manager.d.ts +10 -1
- package/dist/dead-letter-manager.d.ts.map +1 -1
- package/dist/dead-letter-manager.js +62 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/metadata.d.ts +6 -6
- package/dist/metadata.js +6 -6
- package/dist/module.d.ts +2 -2
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +100 -14
- package/dist/service.d.ts +50 -6
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +141 -60
- package/dist/tokens.d.ts +63 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +116 -1
- package/dist/types.d.ts +73 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/worker-discovery.d.ts +3 -2
- package/dist/worker-discovery.d.ts.map +1 -1
- package/dist/worker-discovery.js +6 -7
- package/dist/worker-ownership.d.ts +10 -0
- package/dist/worker-ownership.d.ts.map +1 -0
- package/dist/worker-ownership.js +102 -0
- package/package.json +8 -8
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { cloneWithFallback } from '@fluojs/core/internal';
|
|
2
2
|
import { normalizePositiveInteger, withTimeout } from './helpers.js';
|
|
3
3
|
const DEAD_LETTER_DRAIN_TIMEOUT_MS = 5_000;
|
|
4
|
+
const DEFAULT_DEAD_LETTER_INSPECTION_LIMIT = 100;
|
|
5
|
+
const MAX_DEAD_LETTER_INSPECTION_LIMIT = 1_000;
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Describes the queue dead letter job contract.
|
|
@@ -23,6 +25,33 @@ export class QueueDeadLetterManager {
|
|
|
23
25
|
get pendingWriteCount() {
|
|
24
26
|
return this.pendingWrites.size;
|
|
25
27
|
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Reads and parses a bounded dead-letter snapshot without mutating Redis state.
|
|
31
|
+
*
|
|
32
|
+
* @param jobName Queue worker job name whose dead letters should be inspected.
|
|
33
|
+
* @param options Optional inspection limit, capped at `1_000` stored entries.
|
|
34
|
+
* @returns Valid records in newest-first order and the number of malformed entries omitted.
|
|
35
|
+
*/
|
|
36
|
+
async inspect(jobName, options = {}) {
|
|
37
|
+
const requestedLimit = normalizePositiveInteger(options.limit, DEFAULT_DEAD_LETTER_INSPECTION_LIMIT);
|
|
38
|
+
const limit = Math.min(requestedLimit, MAX_DEAD_LETTER_INSPECTION_LIMIT);
|
|
39
|
+
const serializedRecords = await this.getRedisClient().lrange(deadLetterKey(jobName), -limit, -1);
|
|
40
|
+
const records = [];
|
|
41
|
+
let malformedRecordCount = 0;
|
|
42
|
+
for (const serializedRecord of serializedRecords.reverse()) {
|
|
43
|
+
const record = parseDeadLetterRecord(serializedRecord, jobName);
|
|
44
|
+
if (record) {
|
|
45
|
+
records.push(record);
|
|
46
|
+
} else {
|
|
47
|
+
malformedRecordCount += 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
malformedRecordCount,
|
|
52
|
+
records
|
|
53
|
+
};
|
|
54
|
+
}
|
|
26
55
|
trackTerminalFailure(descriptor, job, error) {
|
|
27
56
|
if (!job || !this.isTerminalFailure(job, descriptor.attempts)) {
|
|
28
57
|
return;
|
|
@@ -75,4 +104,37 @@ function deadLetterKey(jobName) {
|
|
|
75
104
|
}
|
|
76
105
|
function isQueuePayload(value) {
|
|
77
106
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
107
|
+
}
|
|
108
|
+
function parseDeadLetterRecord(serializedRecord, expectedJobName) {
|
|
109
|
+
let value;
|
|
110
|
+
try {
|
|
111
|
+
value = JSON.parse(serializedRecord);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (error instanceof SyntaxError) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
if (!isQueuePayload(value) || !Object.hasOwn(value, 'payload')) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
const {
|
|
122
|
+
attemptsMade,
|
|
123
|
+
errorMessage,
|
|
124
|
+
failedAt,
|
|
125
|
+
jobId,
|
|
126
|
+
jobName,
|
|
127
|
+
payload
|
|
128
|
+
} = value;
|
|
129
|
+
if (typeof attemptsMade !== 'number' || !Number.isInteger(attemptsMade) || attemptsMade < 0 || typeof errorMessage !== 'string' || typeof failedAt !== 'string' || typeof jobId !== 'string' || jobName !== expectedJobName) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
attemptsMade,
|
|
134
|
+
errorMessage,
|
|
135
|
+
failedAt,
|
|
136
|
+
jobId,
|
|
137
|
+
jobName,
|
|
138
|
+
payload
|
|
139
|
+
};
|
|
78
140
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ export { QueueWorker } from './decorators.js';
|
|
|
2
2
|
export { QueueModule } from './module.js';
|
|
3
3
|
export { QueueLifecycleService } from './service.js';
|
|
4
4
|
export * from './status.js';
|
|
5
|
-
export { QUEUE } from './tokens.js';
|
|
6
|
-
export type { Queue, QueueBackoffOptions, QueueBackoffType, QueueJobType, QueueModuleOptions, QueueRateLimiterOptions, QueueWorkerOptions, } from './types.js';
|
|
5
|
+
export { getQueueLifecycleServiceToken, getQueueToken, QUEUE } from './tokens.js';
|
|
6
|
+
export type { Queue, QueueBackoffOptions, QueueBackoffType, QueueDeadLetterInspectionOptions, QueueDeadLetterInspectionResult, QueueDeadLetterRecord, QueueEnqueueManyEntry, QueueEnqueueOptions, QueueJobType, QueueModuleOptions, QueueOwnershipEnforcement, QueueRateLimiterOptions, QueueWorkerOptions, } from './types.js';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,6BAA6B,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAClF,YAAY,EACV,KAAK,EACL,mBAAmB,EACnB,gBAAgB,EAChB,gCAAgC,EAChC,+BAA+B,EAC/B,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,4 +2,4 @@ export { QueueWorker } from './decorators.js';
|
|
|
2
2
|
export { QueueModule } from './module.js';
|
|
3
3
|
export { QueueLifecycleService } from './service.js';
|
|
4
4
|
export * from './status.js';
|
|
5
|
-
export { QUEUE } from './tokens.js';
|
|
5
|
+
export { getQueueLifecycleServiceToken, getQueueToken, QUEUE } from './tokens.js';
|
package/dist/metadata.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { QueueWorkerMetadata } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Stores queue worker metadata for a decorated worker class.
|
|
4
4
|
*
|
|
5
|
-
* @param target
|
|
6
|
-
* @param metadata
|
|
5
|
+
* @param target Decorated worker class that owns the metadata.
|
|
6
|
+
* @param metadata Job type and worker options to store for the class.
|
|
7
7
|
*/
|
|
8
8
|
export declare function defineQueueWorkerMetadata(target: Function, metadata: QueueWorkerMetadata): void;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Reads queue worker metadata for a decorated worker class.
|
|
11
11
|
*
|
|
12
|
-
* @param target
|
|
13
|
-
* @returns
|
|
12
|
+
* @param target Worker class whose metadata should be read.
|
|
13
|
+
* @returns A cloned metadata snapshot, or `undefined` when the class has no queue worker metadata.
|
|
14
14
|
*/
|
|
15
15
|
export declare function getQueueWorkerMetadata(target: Function): QueueWorkerMetadata | undefined;
|
|
16
16
|
/**
|
package/dist/metadata.js
CHANGED
|
@@ -15,20 +15,20 @@ function getStandardQueueWorkerMetadata(target) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Stores queue worker metadata for a decorated worker class.
|
|
19
19
|
*
|
|
20
|
-
* @param target
|
|
21
|
-
* @param metadata
|
|
20
|
+
* @param target Decorated worker class that owns the metadata.
|
|
21
|
+
* @param metadata Job type and worker options to store for the class.
|
|
22
22
|
*/
|
|
23
23
|
export function defineQueueWorkerMetadata(target, metadata) {
|
|
24
24
|
queueWorkerMetadataStore.set(target, cloneQueueWorkerMetadata(metadata));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Reads queue worker metadata for a decorated worker class.
|
|
29
29
|
*
|
|
30
|
-
* @param target
|
|
31
|
-
* @returns
|
|
30
|
+
* @param target Worker class whose metadata should be read.
|
|
31
|
+
* @returns A cloned metadata snapshot, or `undefined` when the class has no queue worker metadata.
|
|
32
32
|
*/
|
|
33
33
|
export function getQueueWorkerMetadata(target) {
|
|
34
34
|
const stored = queueWorkerMetadataStore.get(target);
|
package/dist/module.d.ts
CHANGED
|
@@ -5,10 +5,10 @@ import type { QueueModuleOptions } from './types.js';
|
|
|
5
5
|
*/
|
|
6
6
|
export declare class QueueModule {
|
|
7
7
|
/**
|
|
8
|
-
* Registers queue providers
|
|
8
|
+
* Registers queue providers using canonical `forRoot(...)` semantics.
|
|
9
9
|
*
|
|
10
10
|
* @param options Queue runtime defaults used by discovered workers and enqueued jobs.
|
|
11
|
-
* @returns A module definition that exports `
|
|
11
|
+
* @returns A module definition that exports default queue tokens when `scope` is omitted, or scoped queue tokens when `scope` is set.
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```ts
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6D,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAsB7G,OAAO,KAAK,EAKV,kBAAkB,EACnB,MAAM,YAAY,CAAC;AA6MpB;;GAEG;AACH,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,kBAAuB,GAAG,UAAU;CAa7D"}
|
package/dist/module.js
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
|
+
import { getRedisClientToken } from '@fluojs/redis';
|
|
1
2
|
import { defineModule } from '@fluojs/runtime';
|
|
3
|
+
import { APPLICATION_LOGGER, BOOTSTRAP_READY_SIGNAL, COMPILED_MODULES, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
|
|
2
4
|
import { normalizePositiveInteger, normalizePositiveIntegerOrFalse, normalizeRateLimiter } from './helpers.js';
|
|
3
5
|
import { QueueLifecycleService } from './service.js';
|
|
4
|
-
import { QUEUE,
|
|
6
|
+
import { getQueueLifecycleServiceToken, getQueueModuleContextToken, getQueueOptionsToken, getQueueRedisClientToken as getQueueScopedRedisClientToken, getQueueToken, normalizeQueueScope, QUEUE, QUEUE_MODULE_CONTEXT_MARKER } from './tokens.js';
|
|
7
|
+
import { assertUniqueQueueWorkerOwnership } from './worker-ownership.js';
|
|
8
|
+
function hasQueueRedisClient(value) {
|
|
9
|
+
if (typeof value !== 'object' || value === null) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const client = value;
|
|
13
|
+
return typeof client.duplicate === 'function' && typeof client.lrange === 'function' && typeof client.rpush === 'function' && typeof client.ltrim === 'function';
|
|
14
|
+
}
|
|
5
15
|
function normalizeQueueModuleOptions(options = {}) {
|
|
6
16
|
const defaultRateLimiter = normalizeRateLimiter(options.defaultRateLimiter);
|
|
17
|
+
const scope = normalizeQueueScope(options.scope);
|
|
18
|
+
const ownershipNamespace = options.ownershipNamespace?.trim();
|
|
19
|
+
if (options.ownershipNamespace !== undefined && !ownershipNamespace) {
|
|
20
|
+
throw new Error('Queue ownership namespace must be a non-empty string when provided.');
|
|
21
|
+
}
|
|
7
22
|
return {
|
|
8
23
|
clientName: options.clientName,
|
|
24
|
+
...(scope ? {
|
|
25
|
+
scope
|
|
26
|
+
} : {}),
|
|
27
|
+
...(ownershipNamespace ? {
|
|
28
|
+
ownershipNamespace
|
|
29
|
+
} : {}),
|
|
30
|
+
ownershipEnforcement: options.ownershipEnforcement ?? 'warn',
|
|
9
31
|
defaultAttempts: normalizePositiveInteger(options.defaultAttempts, 1),
|
|
10
32
|
defaultBackoff: options.defaultBackoff ? {
|
|
11
33
|
delayMs: options.defaultBackoff.delayMs,
|
|
@@ -18,17 +40,79 @@ function normalizeQueueModuleOptions(options = {}) {
|
|
|
18
40
|
workerShutdownTimeoutMs: normalizePositiveInteger(options.workerShutdownTimeoutMs, 30_000)
|
|
19
41
|
};
|
|
20
42
|
}
|
|
21
|
-
function
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
43
|
+
function getQueueProviderTokens(scope) {
|
|
44
|
+
return {
|
|
45
|
+
lifecycleServiceToken: getQueueLifecycleServiceToken(scope),
|
|
46
|
+
moduleContextToken: getQueueModuleContextToken(scope),
|
|
47
|
+
optionsToken: getQueueOptionsToken(scope),
|
|
48
|
+
queueRedisClientToken: getQueueScopedRedisClientToken(scope),
|
|
49
|
+
queueToken: getQueueToken(scope)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function moduleCanAccessQueueRegistration(compiledModule, moduleType) {
|
|
53
|
+
return compiledModule.type === moduleType || (compiledModule.definition.imports ?? []).includes(moduleType);
|
|
54
|
+
}
|
|
55
|
+
function canAccessRedisClient(compiledModules, moduleContext, redisToken) {
|
|
56
|
+
return compiledModules.some(compiledModule => moduleCanAccessQueueRegistration(compiledModule, moduleContext.moduleType) && compiledModule.accessibleTokens.has(redisToken));
|
|
57
|
+
}
|
|
58
|
+
function formatQueueScope(scope) {
|
|
59
|
+
return scope ?? 'default';
|
|
60
|
+
}
|
|
61
|
+
function createQueueProviders(normalizedOptions, moduleType, tokens) {
|
|
62
|
+
const providers = [{
|
|
63
|
+
provide: tokens.optionsToken,
|
|
64
|
+
useValue: normalizedOptions
|
|
65
|
+
}, {
|
|
66
|
+
provide: tokens.moduleContextToken,
|
|
67
|
+
useValue: {
|
|
68
|
+
[QUEUE_MODULE_CONTEXT_MARKER]: true,
|
|
69
|
+
moduleType,
|
|
70
|
+
options: normalizedOptions,
|
|
71
|
+
registrationTokens: [QueueLifecycleService, QUEUE, tokens.lifecycleServiceToken, tokens.queueToken],
|
|
72
|
+
scope: formatQueueScope(normalizedOptions.scope)
|
|
73
|
+
}
|
|
74
|
+
}, {
|
|
75
|
+
inject: [tokens.optionsToken, RUNTIME_CONTAINER, COMPILED_MODULES, tokens.moduleContextToken],
|
|
76
|
+
provide: tokens.queueRedisClientToken,
|
|
77
|
+
useFactory: async (...deps) => {
|
|
78
|
+
const [resolvedOptions, runtimeContainer, compiledModules, moduleContext] = deps;
|
|
79
|
+
const redisToken = getRedisClientToken(resolvedOptions.clientName);
|
|
80
|
+
if (!canAccessRedisClient(compiledModules, moduleContext, redisToken)) {
|
|
81
|
+
throw new Error(`@fluojs/queue cannot access Redis client token ${String(redisToken)} from queue scope "${moduleContext.scope}". Import and export the matching RedisModule.forRoot(...) registration through the same module graph.`);
|
|
82
|
+
}
|
|
83
|
+
if (!runtimeContainer.has(redisToken)) {
|
|
84
|
+
throw new Error('@fluojs/queue requires a registered Redis client with duplicate(), lrange(), rpush(), and ltrim() methods.');
|
|
85
|
+
}
|
|
86
|
+
const redisClient = await runtimeContainer.resolve(redisToken);
|
|
87
|
+
if (!hasQueueRedisClient(redisClient)) {
|
|
88
|
+
throw new Error('@fluojs/queue requires a Redis client with duplicate(), lrange(), rpush(), and ltrim() methods.');
|
|
89
|
+
}
|
|
90
|
+
return redisClient;
|
|
91
|
+
}
|
|
92
|
+
}, {
|
|
93
|
+
inject: [tokens.optionsToken, tokens.queueRedisClientToken, RUNTIME_CONTAINER, COMPILED_MODULES, APPLICATION_LOGGER, BOOTSTRAP_READY_SIGNAL, tokens.moduleContextToken],
|
|
94
|
+
provide: tokens.lifecycleServiceToken,
|
|
95
|
+
useFactory: (...deps) => {
|
|
96
|
+
const typedDeps = deps;
|
|
97
|
+
assertUniqueQueueWorkerOwnership(typedDeps[3], typedDeps[4], typedDeps[6].moduleType);
|
|
98
|
+
return new QueueLifecycleService(...typedDeps);
|
|
99
|
+
}
|
|
100
|
+
}, {
|
|
101
|
+
inject: [tokens.lifecycleServiceToken],
|
|
102
|
+
provide: tokens.queueToken,
|
|
28
103
|
useFactory: service => ({
|
|
29
|
-
enqueue: job => service.enqueue(job)
|
|
104
|
+
enqueue: (job, options) => service.enqueue(job, options),
|
|
105
|
+
enqueueMany: entries => service.enqueueMany(entries),
|
|
106
|
+
inspectDeadLetters: (jobName, options) => service.inspectDeadLetters(jobName, options)
|
|
30
107
|
})
|
|
31
108
|
}];
|
|
109
|
+
if (normalizedOptions.scope === undefined) {
|
|
110
|
+
providers.push({
|
|
111
|
+
provide: QueueLifecycleService,
|
|
112
|
+
useExisting: tokens.lifecycleServiceToken
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return providers;
|
|
32
116
|
}
|
|
33
117
|
|
|
34
118
|
/**
|
|
@@ -36,10 +120,10 @@ function createQueueProviders(options = {}) {
|
|
|
36
120
|
*/
|
|
37
121
|
export class QueueModule {
|
|
38
122
|
/**
|
|
39
|
-
* Registers queue providers
|
|
123
|
+
* Registers queue providers using canonical `forRoot(...)` semantics.
|
|
40
124
|
*
|
|
41
125
|
* @param options Queue runtime defaults used by discovered workers and enqueued jobs.
|
|
42
|
-
* @returns A module definition that exports `
|
|
126
|
+
* @returns A module definition that exports default queue tokens when `scope` is omitted, or scoped queue tokens when `scope` is set.
|
|
43
127
|
*
|
|
44
128
|
* @example
|
|
45
129
|
* ```ts
|
|
@@ -57,11 +141,13 @@ export class QueueModule {
|
|
|
57
141
|
* ```
|
|
58
142
|
*/
|
|
59
143
|
static forRoot(options = {}) {
|
|
144
|
+
const normalizedOptions = normalizeQueueModuleOptions(options);
|
|
145
|
+
const tokens = getQueueProviderTokens(normalizedOptions.scope);
|
|
60
146
|
class QueueModuleDefinition {}
|
|
61
147
|
return defineModule(QueueModuleDefinition, {
|
|
62
|
-
exports: [QueueLifecycleService, QUEUE],
|
|
63
|
-
global:
|
|
64
|
-
providers: createQueueProviders(
|
|
148
|
+
exports: normalizedOptions.scope === undefined ? [QueueLifecycleService, tokens.lifecycleServiceToken, QUEUE] : [tokens.lifecycleServiceToken, tokens.queueToken],
|
|
149
|
+
global: normalizedOptions.global,
|
|
150
|
+
providers: createQueueProviders(normalizedOptions, QueueModuleDefinition, tokens)
|
|
65
151
|
});
|
|
66
152
|
}
|
|
67
153
|
}
|
package/dist/service.d.ts
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import type { Container } from '@fluojs/di';
|
|
2
2
|
import type { ApplicationLogger, CompiledModule, OnApplicationBootstrap, OnApplicationShutdown, OnModuleDestroy } from '@fluojs/runtime';
|
|
3
|
-
import {
|
|
3
|
+
import type { BootstrapReadySignal } from '@fluojs/runtime/internal';
|
|
4
|
+
import { type ConnectionOptions } from 'bullmq';
|
|
5
|
+
import { type QueueRedisDeadLetterClient } from './dead-letter-manager.js';
|
|
4
6
|
import { type QueuePlatformStatusSnapshot } from './status.js';
|
|
5
|
-
import type {
|
|
7
|
+
import type { QueueModuleContext } from './tokens.js';
|
|
8
|
+
import type { NormalizedQueueModuleOptions, Queue, QueueDeadLetterInspectionOptions, QueueDeadLetterInspectionResult, QueueEnqueueManyEntry, QueueEnqueueOptions } from './types.js';
|
|
9
|
+
type QueueOwnedConnection = ConnectionOptions & {
|
|
10
|
+
connect(): Promise<unknown>;
|
|
11
|
+
disconnect(): void;
|
|
12
|
+
quit(): Promise<unknown>;
|
|
13
|
+
maxRetriesPerRequest?: number | null;
|
|
14
|
+
status?: string;
|
|
15
|
+
};
|
|
16
|
+
interface QueueBullMqConnectionOptions {
|
|
17
|
+
maxRetriesPerRequest: null;
|
|
18
|
+
}
|
|
19
|
+
interface QueueRedisClient extends QueueRedisDeadLetterClient {
|
|
20
|
+
duplicate(options?: QueueBullMqConnectionOptions): QueueOwnedConnection;
|
|
21
|
+
}
|
|
6
22
|
/**
|
|
7
23
|
* Lifecycle-managed queue runtime for worker discovery and job dispatch.
|
|
8
24
|
*
|
|
@@ -11,10 +27,12 @@ import type { NormalizedQueueModuleOptions, Queue } from './types.js';
|
|
|
11
27
|
*/
|
|
12
28
|
export declare class QueueLifecycleService implements Queue, OnApplicationBootstrap, OnApplicationShutdown, OnModuleDestroy {
|
|
13
29
|
private readonly options;
|
|
30
|
+
private readonly redisClient;
|
|
14
31
|
private readonly runtimeContainer;
|
|
15
32
|
private readonly compiledModules;
|
|
16
33
|
private readonly logger;
|
|
17
34
|
private readonly bootstrapReadySignal;
|
|
35
|
+
private readonly moduleContext;
|
|
18
36
|
private readonly descriptorsByJobType;
|
|
19
37
|
private readonly queuesByJobName;
|
|
20
38
|
private readonly workersByJobName;
|
|
@@ -24,12 +42,12 @@ export declare class QueueLifecycleService implements Queue, OnApplicationBootst
|
|
|
24
42
|
private readonly runningWorkerJobNames;
|
|
25
43
|
private readonly failedWorkerJobNames;
|
|
26
44
|
private readonly workerStartFailures;
|
|
45
|
+
private readonly compiledModulesByType;
|
|
27
46
|
private lifecycleState;
|
|
28
|
-
private redisClient;
|
|
29
47
|
private startPromise;
|
|
30
48
|
private shutdownPromise;
|
|
31
49
|
private startupFailureRollbackPromise;
|
|
32
|
-
constructor(options: NormalizedQueueModuleOptions, runtimeContainer: Container, compiledModules: readonly CompiledModule[], logger: ApplicationLogger, bootstrapReadySignal?: BootstrapReadySignal);
|
|
50
|
+
constructor(options: NormalizedQueueModuleOptions, redisClient: QueueRedisClient, runtimeContainer: Container, compiledModules: readonly CompiledModule[], logger: ApplicationLogger, bootstrapReadySignal?: BootstrapReadySignal, moduleContext?: QueueModuleContext);
|
|
33
51
|
onApplicationBootstrap(): Promise<void>;
|
|
34
52
|
onApplicationShutdown(): Promise<void>;
|
|
35
53
|
onModuleDestroy(): Promise<void>;
|
|
@@ -37,20 +55,45 @@ export declare class QueueLifecycleService implements Queue, OnApplicationBootst
|
|
|
37
55
|
* Enqueues one job instance using the worker metadata registered for its class.
|
|
38
56
|
*
|
|
39
57
|
* @param job Job instance whose constructor matches a discovered `@QueueWorker()` provider.
|
|
40
|
-
* @
|
|
58
|
+
* @param options Optional producer controls, including a caller-owned deduplication key.
|
|
59
|
+
* @returns The backing BullMQ job id, or an empty string when BullMQ does not provide one.
|
|
41
60
|
*
|
|
42
61
|
* @throws {Error} When no worker is registered for the job type or the queue is not initialized.
|
|
43
62
|
*/
|
|
44
|
-
enqueue<TJob extends object>(job: TJob): Promise<string>;
|
|
63
|
+
enqueue<TJob extends object>(job: TJob, options?: QueueEnqueueOptions): Promise<string>;
|
|
64
|
+
/**
|
|
65
|
+
* Atomically enqueues ordered jobs that resolve to one registered worker queue.
|
|
66
|
+
*
|
|
67
|
+
* @param entries Ordered job instances and per-job producer controls.
|
|
68
|
+
* @returns Backing BullMQ job ids aligned with the input order.
|
|
69
|
+
* @throws {Error} When any entry has no registered worker, targets another queue, or the queue is unavailable.
|
|
70
|
+
*/
|
|
71
|
+
enqueueMany<TJob extends object>(entries: readonly QueueEnqueueManyEntry<TJob>[]): Promise<readonly string[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Reads a bounded snapshot of dead-letter records for one queue job name.
|
|
74
|
+
*
|
|
75
|
+
* Inspection reads Redis without starting workers or lifecycle-gating the read. The backing Redis client must
|
|
76
|
+
* remain reachable; `RedisModule` owns that shared client's shutdown.
|
|
77
|
+
*
|
|
78
|
+
* @param jobName Queue worker job name whose dead letters should be inspected.
|
|
79
|
+
* @param options Optional bounded inspection settings.
|
|
80
|
+
* @returns Valid records in newest-first order plus the malformed count for the inspected window.
|
|
81
|
+
* @throws The backing Redis read error when that client is unavailable or already shut down.
|
|
82
|
+
*/
|
|
83
|
+
inspectDeadLetters(jobName: string, options?: QueueDeadLetterInspectionOptions): Promise<QueueDeadLetterInspectionResult>;
|
|
45
84
|
/**
|
|
46
85
|
* Creates a platform status snapshot for health checks and diagnostics.
|
|
47
86
|
*
|
|
48
87
|
* @returns A structured snapshot describing lifecycle state, discovered workers, and pending dead-letter writes.
|
|
49
88
|
*/
|
|
50
89
|
createPlatformStatusSnapshot(): QueuePlatformStatusSnapshot;
|
|
90
|
+
private resolveEnqueueTarget;
|
|
91
|
+
private createBullMqJobOptions;
|
|
51
92
|
private ensureStarted;
|
|
52
93
|
private startLifecycle;
|
|
53
94
|
private shouldDiscoverWorkersInModule;
|
|
95
|
+
private canReachQueueRegistration;
|
|
96
|
+
private exportsQueueRegistration;
|
|
54
97
|
private handleStartupFailure;
|
|
55
98
|
private resolveRedisClient;
|
|
56
99
|
private getRedisClient;
|
|
@@ -81,4 +124,5 @@ export declare class QueueLifecycleService implements Queue, OnApplicationBootst
|
|
|
81
124
|
private tryCloseQueue;
|
|
82
125
|
private tryCloseOwnedConnection;
|
|
83
126
|
}
|
|
127
|
+
export {};
|
|
84
128
|
//# sourceMappingURL=service.d.ts.map
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|