nestworker 2.1.5 → 2.1.7
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.md +684 -611
- package/dist/core/worker.interfaces.d.ts +38 -3
- package/dist/core/worker.module.js +1 -5
- package/dist/core/worker.module.js.map +1 -1
- package/dist/core/worker.pool.d.ts +52 -15
- package/dist/core/worker.pool.js +399 -223
- package/dist/core/worker.pool.js.map +1 -1
- package/dist/core/worker.service.d.ts +37 -3
- package/dist/core/worker.service.js +93 -18
- package/dist/core/worker.service.js.map +1 -1
- package/dist/decorators/worker-task.decorator.js.map +1 -1
- package/dist/di/di-serializer.js +27 -16
- package/dist/di/di-serializer.js.map +1 -1
- package/dist/di/worker-container.d.ts +24 -5
- package/dist/di/worker-container.js +70 -30
- package/dist/di/worker-container.js.map +1 -1
- package/dist/discovery/discovery.service.js +6 -15
- package/dist/discovery/discovery.service.js.map +1 -1
- package/dist/example/bench.js +10 -2
- package/dist/example/bench.js.map +1 -1
- package/dist/example/image.service.d.ts +8 -0
- package/dist/example/image.service.js +31 -0
- package/dist/example/image.service.js.map +1 -1
- package/dist/example/main.js +26 -9
- package/dist/example/main.js.map +1 -1
- package/dist/health/worker.health.js +4 -3
- package/dist/health/worker.health.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics/worker.metrics.js +6 -2
- package/dist/metrics/worker.metrics.js.map +1 -1
- package/dist/worker/worker-runtime.js +81 -72
- package/dist/worker/worker-runtime.js.map +1 -1
- package/package.json +85 -67
|
@@ -6,8 +6,13 @@ export interface WorkerJob {
|
|
|
6
6
|
methodName: string;
|
|
7
7
|
args: unknown[];
|
|
8
8
|
proxyServices?: ProxyServiceDescriptor[];
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* ALS context snapshot. Index `i` corresponds to the i-th storage in
|
|
11
|
+
* `WorkerModuleOptions.asyncLocalStorages`. Encoded as an array — smaller
|
|
12
|
+
* structuredClone payload than an object, and survives >10 storages
|
|
13
|
+
* (the old string-keyed encoding broke past 9).
|
|
14
|
+
*/
|
|
15
|
+
alsContext?: unknown[];
|
|
11
16
|
/** OTEL trace context — W3C traceparent/tracestate headers */
|
|
12
17
|
traceContext?: Record<string, string>;
|
|
13
18
|
/** AbortSignal is non-transferable; we send the signal ID instead */
|
|
@@ -43,6 +48,13 @@ export interface IpcInvokeRequest {
|
|
|
43
48
|
propertyKey: string;
|
|
44
49
|
methodName: string;
|
|
45
50
|
args: unknown[];
|
|
51
|
+
/**
|
|
52
|
+
* If the originating worker task was invoked with an AbortSignal, the
|
|
53
|
+
* worker forwards its abortSignalId here so the main thread can wire the
|
|
54
|
+
* proxy call to the same signal — preventing proxy methods from running
|
|
55
|
+
* past their parent task's cancellation.
|
|
56
|
+
*/
|
|
57
|
+
abortSignalId?: number;
|
|
46
58
|
}
|
|
47
59
|
export interface IpcInvokeResponse {
|
|
48
60
|
type: 'ipc:result';
|
|
@@ -79,7 +91,8 @@ export interface DiscoveredTask {
|
|
|
79
91
|
priority: TaskPriority;
|
|
80
92
|
timeout?: number;
|
|
81
93
|
retry?: number;
|
|
82
|
-
|
|
94
|
+
/** Number or function — functions are evaluated main-thread per attempt. */
|
|
95
|
+
retryDelay?: number | ((attempt: number) => number);
|
|
83
96
|
fn: (...args: unknown[]) => unknown;
|
|
84
97
|
metatype: new (...args: unknown[]) => unknown;
|
|
85
98
|
instance: unknown;
|
|
@@ -111,11 +124,29 @@ export interface WorkerModuleOptions {
|
|
|
111
124
|
* workers on application shutdown. Defaults to 30_000.
|
|
112
125
|
*/
|
|
113
126
|
shutdownTimeout?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Maximum number of pending tasks allowed in the queue. When the queue is
|
|
129
|
+
* full, `WorkerService.run()` rejects with a `QueueFullError` instead of
|
|
130
|
+
* enqueuing — gives callers a chance to apply backpressure. Defaults to
|
|
131
|
+
* `Infinity` (unbounded, legacy behaviour).
|
|
132
|
+
*/
|
|
133
|
+
maxQueueDepth?: number;
|
|
114
134
|
/**
|
|
115
135
|
* AsyncLocalStorage instances whose current store should be propagated
|
|
116
136
|
* into worker tasks. Pass the same ALS instances you use in your app.
|
|
117
137
|
*/
|
|
118
138
|
asyncLocalStorages?: AsyncLocalStorage<unknown>[];
|
|
139
|
+
/**
|
|
140
|
+
* Optional logger sink. Defaults to `@nestjs/common`'s `Logger`. Pass any
|
|
141
|
+
* object with `error`/`warn`/`debug` methods to integrate pino, winston,
|
|
142
|
+
* bunyan, etc.
|
|
143
|
+
*/
|
|
144
|
+
logger?: WorkerLogger;
|
|
145
|
+
}
|
|
146
|
+
export interface WorkerLogger {
|
|
147
|
+
error(message: string, trace?: string): void;
|
|
148
|
+
warn(message: string): void;
|
|
149
|
+
debug?(message: string): void;
|
|
119
150
|
}
|
|
120
151
|
export interface WorkerModuleAsyncOptions {
|
|
121
152
|
inject?: unknown[];
|
|
@@ -127,4 +158,8 @@ export interface PoolStats {
|
|
|
127
158
|
busy: number;
|
|
128
159
|
queued: number;
|
|
129
160
|
warmingUp: number;
|
|
161
|
+
/** Queue depth as a fraction of `maxQueueDepth` (0..1). 0 when unbounded. */
|
|
162
|
+
saturation: number;
|
|
163
|
+
/** Configured `maxQueueDepth` (Infinity when unbounded). */
|
|
164
|
+
maxQueueDepth: number;
|
|
130
165
|
}
|
|
@@ -55,11 +55,7 @@ let WorkerModule = WorkerModule_1 = class WorkerModule {
|
|
|
55
55
|
module: WorkerModule_1,
|
|
56
56
|
global: true,
|
|
57
57
|
imports: [core_1.DiscoveryModule],
|
|
58
|
-
providers: [
|
|
59
|
-
optionsProvider,
|
|
60
|
-
discovery_service_1.WorkerDiscoveryService,
|
|
61
|
-
worker_service_1.WorkerService,
|
|
62
|
-
],
|
|
58
|
+
providers: [optionsProvider, discovery_service_1.WorkerDiscoveryService, worker_service_1.WorkerService],
|
|
63
59
|
exports: [worker_service_1.WorkerService],
|
|
64
60
|
};
|
|
65
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.module.js","sourceRoot":"","sources":["../../src/core/worker.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAiE;AACjE,uCAA+C;AAC/C,qDAAiD;AACjD,sEAAwE;
|
|
1
|
+
{"version":3,"file":"worker.module.js","sourceRoot":"","sources":["../../src/core/worker.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAiE;AACjE,uCAA+C;AAC/C,qDAAiD;AACjD,sEAAwE;AAOjE,IAAM,YAAY,oBAAlB,MAAM,YAAY;IACvB;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,UAA+B,EAAE;QAC9C,OAAO;YACL,MAAM,EAAE,cAAY;YACpB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,sBAAe,CAAC;YAC1B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE;gBAChD,0CAAsB;gBACtB,8BAAa;aACd;YACD,OAAO,EAAE,CAAC,8BAAa,CAAC;SACzB,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,YAAY,CAAC,YAAsC;QACxD,MAAM,eAAe,GAAa;YAChC,OAAO,EAAE,gBAAgB;YACzB,MAAM,EAAE,CAAC,YAAY,CAAC,MAAM,IAAI,EAAE,CAAY;YAC9C,UAAU,EAAE,YAAY,CAAC,UAAU;SACpC,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,cAAY;YACpB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,sBAAe,CAAC;YAC1B,SAAS,EAAE,CAAC,eAAe,EAAE,0CAAsB,EAAE,8BAAa,CAAC;YACnE,OAAO,EAAE,CAAC,8BAAa,CAAC;SACzB,CAAC;IACJ,CAAC;CACF,CAAA;AAjDY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,YAAY,CAiDxB"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import type { WorkerJob, TaskPriority, ProxyInstance, DeadLetterEvent, SerializedError, PoolStats } from './worker.interfaces';
|
|
3
3
|
import type { SerializedService } from '../di/worker-container';
|
|
4
|
+
export declare class QueueFullError extends Error {
|
|
5
|
+
constructor(depth: number);
|
|
6
|
+
}
|
|
4
7
|
export declare interface WorkerPool {
|
|
5
8
|
on(event: 'dead', listener: (event: DeadLetterEvent) => void): this;
|
|
6
9
|
on(event: 'error', listener: (err: Error, job: WorkerJob) => void): this;
|
|
@@ -26,8 +29,13 @@ export declare class WorkerPool extends EventEmitter {
|
|
|
26
29
|
*/
|
|
27
30
|
private readonly idle;
|
|
28
31
|
private readonly warmingUp;
|
|
29
|
-
private readonly
|
|
30
|
-
private
|
|
32
|
+
private readonly queueHigh;
|
|
33
|
+
private readonly queueNormal;
|
|
34
|
+
private readonly queueLow;
|
|
35
|
+
private queueHighHead;
|
|
36
|
+
private queueNormalHead;
|
|
37
|
+
private queueLowHead;
|
|
38
|
+
private queuedCount;
|
|
31
39
|
private destroyed;
|
|
32
40
|
private activeCount;
|
|
33
41
|
/**
|
|
@@ -39,36 +47,65 @@ export declare class WorkerPool extends EventEmitter {
|
|
|
39
47
|
* coalesced into a single postMessage per worker.
|
|
40
48
|
*/
|
|
41
49
|
private scheduleQueued;
|
|
42
|
-
/** Maps abortSignalId → worker currently running that job */
|
|
43
|
-
private readonly signalWorkerMap;
|
|
44
50
|
private readonly concurrency;
|
|
51
|
+
private readonly maxQueueDepth;
|
|
45
52
|
private readonly proxyMap;
|
|
46
|
-
constructor(services: SerializedService[], proxyInstances: ProxyInstance[], size?: number, shutdownTimeout?: number, concurrency?: number);
|
|
53
|
+
constructor(services: SerializedService[], proxyInstances: ProxyInstance[], size?: number, shutdownTimeout?: number, concurrency?: number, maxQueueDepth?: number);
|
|
47
54
|
execute<T = unknown>(job: WorkerJob, meta: {
|
|
48
55
|
priority: TaskPriority;
|
|
49
56
|
timeout?: number;
|
|
50
57
|
retry?: number;
|
|
51
|
-
retryDelay?: number;
|
|
58
|
+
retryDelay?: number | ((attempt: number) => number);
|
|
52
59
|
}, signal?: AbortSignal): Promise<T>;
|
|
60
|
+
/** Remove the abort listener installed in `execute()` (idempotent). */
|
|
61
|
+
private detachAbort;
|
|
53
62
|
stats(): PoolStats;
|
|
54
63
|
private spawnWorker;
|
|
55
64
|
private handleIpcInvoke;
|
|
65
|
+
/**
|
|
66
|
+
* Look up the original caller's AbortSignal by abortSignalId. Used by
|
|
67
|
+
* `handleIpcInvoke` to forward cancellation into proxy methods.
|
|
68
|
+
* Scan is bounded by `concurrency * poolSize` and only happens on proxy
|
|
69
|
+
* calls from signal-bearing tasks, so we don't bother with a side index.
|
|
70
|
+
*/
|
|
71
|
+
private findSignalById;
|
|
56
72
|
private enqueue;
|
|
57
|
-
private schedule;
|
|
58
73
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* adds a full microtask hop per round-trip, which dominates throughput
|
|
63
|
-
* for short tasks with concurrency=1.
|
|
74
|
+
* Pop the next ready task in priority order (HIGH > NORMAL > LOW). Skips
|
|
75
|
+
* tombstoned entries (aborted-while-queued) and lazily compacts each
|
|
76
|
+
* bucket once its head pointer wastes >1024 slots.
|
|
64
77
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
|
|
78
|
+
* Returns `undefined` when all buckets are empty or contain only
|
|
79
|
+
* tombstones — caller must check.
|
|
80
|
+
*/
|
|
81
|
+
private dequeue;
|
|
82
|
+
private maybeCompact;
|
|
83
|
+
/** True iff at least one bucket has a non-tombstone entry remaining. */
|
|
84
|
+
private hasQueued;
|
|
85
|
+
private schedule;
|
|
86
|
+
/**
|
|
87
|
+
* Synchronous drain used on the COMPLETION path. Initial-burst dispatch
|
|
88
|
+
* still goes through the deferred `schedule()` so synchronous floods of
|
|
89
|
+
* `execute()` calls get coalesced into per-worker batches.
|
|
68
90
|
*/
|
|
69
91
|
private dispatchNow;
|
|
70
92
|
/** Pre-bound for queueMicrotask — avoids closure allocation per schedule. */
|
|
71
93
|
private readonly drain;
|
|
94
|
+
/**
|
|
95
|
+
* Common dispatch loop shared by `dispatchNow` (synchronous, post-result)
|
|
96
|
+
* and `drain` (microtask, post-burst). Pops idle slots and ships jobs as
|
|
97
|
+
* either bare `WorkerJob` (single) or `WorkerJobBatch` envelopes.
|
|
98
|
+
*
|
|
99
|
+
* @param fastSingle When true, take a fast path for "exactly one job to
|
|
100
|
+
* exactly one idle worker" that skips the per-worker Map allocation.
|
|
101
|
+
*/
|
|
102
|
+
private flushDispatch;
|
|
103
|
+
/**
|
|
104
|
+
* Post a single job; on serialization failure synthesise a failure result
|
|
105
|
+
* so the caller's promise rejects instead of hanging on the active map.
|
|
106
|
+
*/
|
|
107
|
+
private safePostJob;
|
|
108
|
+
private safePostBatch;
|
|
72
109
|
private prepareDispatch;
|
|
73
110
|
/** Called from the persistent message listener when a job result arrives. */
|
|
74
111
|
private completeJob;
|