@fluojs/queue 1.0.0-beta.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAEtE,kGAAkG;AAClG,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAA4B,CAAC;AAC5D,gGAAgG;AAChG,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,4BAA4B,CAAoC,CAAC"}
package/dist/tokens.js ADDED
@@ -0,0 +1,4 @@
1
+ /** Compatibility injection token for the queue facade returned by {@link QueueModule.forRoot}. */
2
+ export const QUEUE = Symbol.for('fluo.queue');
3
+ /** Injection token for normalized module defaults consumed by {@link QueueLifecycleService}. */
4
+ export const QUEUE_OPTIONS = Symbol.for('fluo.queue.options');
@@ -0,0 +1,76 @@
1
+ import type { Token } from '@fluojs/core';
2
+ /** Class constructor used to identify and rehydrate one queue job payload shape. */
3
+ export interface QueueJobType<TJob extends object = object> {
4
+ new (...args: never[]): TJob;
5
+ }
6
+ /** Supported retry backoff strategies forwarded to BullMQ workers. */
7
+ export type QueueBackoffType = 'fixed' | 'exponential';
8
+ /** Retry timing settings applied to one queued job type. */
9
+ export interface QueueBackoffOptions {
10
+ delayMs?: number;
11
+ type?: QueueBackoffType;
12
+ }
13
+ /** Distributed rate-limiter settings applied at the worker level. */
14
+ export interface QueueRateLimiterOptions {
15
+ max: number;
16
+ duration: number;
17
+ }
18
+ /**
19
+ * Per-worker execution settings declared through {@link QueueWorker}.
20
+ *
21
+ * These options affect how BullMQ workers retry jobs, limit concurrency, and
22
+ * derive the queue name used for one job class.
23
+ */
24
+ export interface QueueWorkerOptions {
25
+ attempts?: number;
26
+ backoff?: QueueBackoffOptions;
27
+ concurrency?: number;
28
+ jobName?: string;
29
+ rateLimiter?: QueueRateLimiterOptions;
30
+ }
31
+ /** Module-wide defaults used when individual workers omit execution settings. */
32
+ export interface QueueModuleOptions {
33
+ clientName?: string;
34
+ defaultAttempts?: number;
35
+ defaultBackoff?: QueueBackoffOptions;
36
+ defaultConcurrency?: number;
37
+ defaultDeadLetterMaxEntries?: number | false;
38
+ defaultRateLimiter?: QueueRateLimiterOptions;
39
+ }
40
+ /** Normalized queue options resolved once during module registration. */
41
+ export interface NormalizedQueueModuleOptions {
42
+ clientName?: string;
43
+ defaultAttempts: number;
44
+ defaultBackoff?: QueueBackoffOptions;
45
+ defaultConcurrency: number;
46
+ defaultDeadLetterMaxEntries: number | false;
47
+ defaultRateLimiter?: QueueRateLimiterOptions;
48
+ }
49
+ /** Metadata captured by {@link QueueWorker} during decorator evaluation. */
50
+ export interface QueueWorkerMetadata {
51
+ jobType: QueueJobType;
52
+ options: QueueWorkerOptions;
53
+ }
54
+ /** Discovered runtime descriptor for one registered queue worker. */
55
+ export interface QueueWorkerDescriptor {
56
+ attempts: number;
57
+ backoff?: QueueBackoffOptions;
58
+ concurrency: number;
59
+ jobName: string;
60
+ jobType: QueueJobType;
61
+ moduleName: string;
62
+ rateLimiter?: QueueRateLimiterOptions;
63
+ token: Token;
64
+ workerName: string;
65
+ }
66
+ /** Queue facade exposed to application code and compatibility tokens. */
67
+ export interface Queue {
68
+ /**
69
+ * Enqueues one job instance for the worker registered against its class.
70
+ *
71
+ * @param job Job instance whose constructor identifies the target worker.
72
+ * @returns The BullMQ job id generated for the enqueued payload.
73
+ */
74
+ enqueue<TJob extends object>(job: TJob): Promise<string>;
75
+ }
76
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,oFAAoF;AACpF,MAAM,WAAW,YAAY,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACxD,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;CAC9B;AAED,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,aAAa,CAAC;AAEvD,4DAA4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACvC;AAED,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2BAA2B,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7C,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;CAC9C;AAED,yEAAyE;AACzE,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2BAA2B,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5C,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;CAC9C;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,yEAAyE;AACzE,MAAM,WAAW,KAAK;IACpB;;;;;OAKG;IACH,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1D"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { ApplicationLogger, CompiledModule } from '@fluojs/runtime';
2
+ import type { NormalizedQueueModuleOptions, QueueJobType, QueueWorkerDescriptor } from './types.js';
3
+ export declare function discoverQueueWorkerDescriptors(compiledModules: readonly CompiledModule[], options: NormalizedQueueModuleOptions, logger: ApplicationLogger): Map<QueueJobType, QueueWorkerDescriptor>;
4
+ //# sourceMappingURL=worker-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-discovery.d.ts","sourceRoot":"","sources":["../src/worker-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIzE,OAAO,KAAK,EAAE,4BAA4B,EAAE,YAAY,EAAE,qBAAqB,EAAuB,MAAM,YAAY,CAAC;AAEzH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,OAAO,EAAE,4BAA4B,EACrC,MAAM,EAAE,iBAAiB,GACxB,GAAG,CAAC,YAAY,EAAE,qBAAqB,CAAC,CA4C1C"}
@@ -0,0 +1,42 @@
1
+ import { getQueueWorkerMetadata } from './metadata.js';
2
+ import { collectDiscoveryCandidates, normalizePositiveInteger, normalizeRateLimiter } from './helpers.js';
3
+ export function discoverQueueWorkerDescriptors(compiledModules, options, logger) {
4
+ const descriptorsByJobType = new Map();
5
+ const seenJobNames = new Set();
6
+ for (const candidate of collectDiscoveryCandidates(compiledModules)) {
7
+ const metadata = getQueueWorkerMetadata(candidate.targetType);
8
+ if (!metadata) {
9
+ continue;
10
+ }
11
+ if (candidate.scope !== 'singleton') {
12
+ logger.warn(`${candidate.targetType.name} in module ${candidate.moduleName} declares @QueueWorker() but is registered with ${candidate.scope} scope. Queue workers are registered only for singleton providers.`, 'QueueLifecycleService');
13
+ continue;
14
+ }
15
+ const jobType = metadata.jobType;
16
+ if (descriptorsByJobType.has(jobType)) {
17
+ logger.warn(`Duplicate @QueueWorker() registration for job type ${jobType.name} was ignored in ${candidate.moduleName}.`, 'QueueLifecycleService');
18
+ continue;
19
+ }
20
+ const jobName = metadata.options.jobName ?? jobType.name;
21
+ if (seenJobNames.has(jobName)) {
22
+ logger.warn(`Duplicate queue job name ${jobName} was ignored in ${candidate.moduleName}.`, 'QueueLifecycleService');
23
+ continue;
24
+ }
25
+ seenJobNames.add(jobName);
26
+ descriptorsByJobType.set(jobType, createWorkerDescriptor(candidate.moduleName, candidate.token, candidate.targetType.name, metadata, jobName, options));
27
+ }
28
+ return descriptorsByJobType;
29
+ }
30
+ function createWorkerDescriptor(moduleName, token, workerName, metadata, jobName, options) {
31
+ return {
32
+ attempts: normalizePositiveInteger(metadata.options.attempts, options.defaultAttempts),
33
+ backoff: metadata.options.backoff ?? options.defaultBackoff,
34
+ concurrency: normalizePositiveInteger(metadata.options.concurrency, options.defaultConcurrency),
35
+ jobName,
36
+ jobType: metadata.jobType,
37
+ moduleName,
38
+ rateLimiter: normalizeRateLimiter(metadata.options.rateLimiter ?? options.defaultRateLimiter),
39
+ token,
40
+ workerName
41
+ };
42
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@fluojs/queue",
3
+ "description": "Redis-backed background job processing with worker discovery and DLQ support for Fluo.",
4
+ "keywords": [
5
+ "fluo",
6
+ "queue",
7
+ "jobs",
8
+ "background",
9
+ "worker",
10
+ "redis",
11
+ "dlq"
12
+ ],
13
+ "version": "1.0.0-beta.1",
14
+ "private": false,
15
+ "license": "MIT",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/fluojs/fluo.git",
19
+ "directory": "packages/queue"
20
+ },
21
+ "engines": {
22
+ "node": ">=20.0.0"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "type": "module",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ }
33
+ },
34
+ "main": "./dist/index.js",
35
+ "types": "./dist/index.d.ts",
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "dependencies": {
40
+ "bullmq": "^5.58.0",
41
+ "@fluojs/core": "^1.0.0-beta.1",
42
+ "@fluojs/di": "^1.0.0-beta.1",
43
+ "@fluojs/redis": "^1.0.0-beta.1",
44
+ "@fluojs/runtime": "^1.0.0-beta.1"
45
+ },
46
+ "devDependencies": {
47
+ "vitest": "^3.2.4"
48
+ },
49
+ "scripts": {
50
+ "prebuild": "node ../../tooling/scripts/clean-dist.mjs",
51
+ "build": "pnpm exec babel src --extensions .ts --ignore 'src/**/*.test.ts' --out-dir dist --config-file ../../tooling/babel/babel.config.cjs && pnpm exec tsc -p tsconfig.build.json",
52
+ "typecheck": "pnpm exec tsc -p tsconfig.json --noEmit",
53
+ "test": "pnpm exec vitest run -c vitest.config.ts",
54
+ "test:watch": "pnpm exec vitest -c vitest.config.ts"
55
+ }
56
+ }