nestworker 2.0.8 → 2.1.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 (34) hide show
  1. package/README.md +388 -117
  2. package/dist/core/worker.interfaces.d.ts +89 -10
  3. package/dist/core/worker.module.d.ts +21 -11
  4. package/dist/core/worker.module.js +38 -10
  5. package/dist/core/worker.module.js.map +1 -1
  6. package/dist/core/worker.pool.d.ts +26 -6
  7. package/dist/core/worker.pool.js +288 -103
  8. package/dist/core/worker.pool.js.map +1 -1
  9. package/dist/core/worker.service.d.ts +28 -74
  10. package/dist/core/worker.service.js +132 -79
  11. package/dist/core/worker.service.js.map +1 -1
  12. package/dist/decorators/worker-task.decorator.d.ts +7 -25
  13. package/dist/decorators/worker-task.decorator.js +5 -26
  14. package/dist/decorators/worker-task.decorator.js.map +1 -1
  15. package/dist/discovery/discovery.service.d.ts +2 -9
  16. package/dist/discovery/discovery.service.js +86 -21
  17. package/dist/discovery/discovery.service.js.map +1 -1
  18. package/dist/example/bench.d.ts +13 -0
  19. package/dist/example/bench.js +85 -0
  20. package/dist/example/bench.js.map +1 -0
  21. package/dist/example/main.js +14 -2
  22. package/dist/example/main.js.map +1 -1
  23. package/dist/health/worker.health.d.ts +46 -0
  24. package/dist/health/worker.health.js +77 -0
  25. package/dist/health/worker.health.js.map +1 -0
  26. package/dist/index.d.ts +6 -1
  27. package/dist/index.js +10 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/metrics/worker.metrics.d.ts +65 -0
  30. package/dist/metrics/worker.metrics.js +122 -0
  31. package/dist/metrics/worker.metrics.js.map +1 -0
  32. package/dist/worker/worker-runtime.js +139 -29
  33. package/dist/worker/worker-runtime.js.map +1 -1
  34. package/package.json +2 -1
@@ -11,51 +11,32 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var WorkerService_1;
14
15
  Object.defineProperty(exports, "__esModule", { value: true });
15
16
  exports.WorkerService = void 0;
16
17
  const common_1 = require("@nestjs/common");
17
18
  const worker_pool_1 = require("./worker.pool");
18
19
  const discovery_service_1 = require("../discovery/discovery.service");
19
20
  const di_serializer_1 = require("../di/di-serializer");
20
- /**
21
- * WorkerService
22
- *
23
- * Main entry point for executing worker-thread tasks.
24
- *
25
- * Features:
26
- * - Lazy worker pool initialization
27
- * - Automatic worker discovery
28
- * - Priority queue support
29
- * - Timeout support
30
- * - Worker thread execution
31
- * - NestJS dependency integration
32
- *
33
- * Lifecycle:
34
- * 1. Discovers worker-enabled services
35
- * 2. Serializes metadata for worker runtime
36
- * 3. Creates WorkerPool
37
- * 4. Dispatches tasks to workers
38
- * 5. Handles graceful shutdown
39
- *
40
- * Example:
41
- *
42
- * ```ts
43
- * await workerService.run(
44
- * 'ImageService',
45
- * 'resizeImage',
46
- * [500],
47
- * {
48
- * priority: 'HIGH',
49
- * timeout: 5000,
50
- * },
51
- * );
52
- * ```
53
- */
54
- let WorkerService = class WorkerService {
21
+ // Monotonic ID generator — far cheaper than crypto.randomUUID() and unique
22
+ // per-process which is all we need (jobs never leave this process).
23
+ let __jobIdCounter = 0;
24
+ const __jobIdPrefix = `j${Date.now().toString(36)}-`;
25
+ const nextId = () => __jobIdPrefix + (++__jobIdCounter).toString(36);
26
+ // Hot-path shared frozen sentinels — let v8 elide allocations on the common
27
+ // "no proxies / no ALS context" path.
28
+ const EMPTY_PROXIES = Object.freeze([]);
29
+ const EMPTY_ALS = Object.freeze({});
30
+ const DEFAULT_TASK = Object.freeze({ priority: 'NORMAL' });
31
+ let WorkerService = WorkerService_1 = class WorkerService {
55
32
  discovery;
56
33
  options;
34
+ logger = new common_1.Logger(WorkerService_1.name);
57
35
  pool = null;
58
- taskOptions = new Map();
36
+ taskDefaults = new Map();
37
+ taskProxies = new Map();
38
+ /** Cached array of ALS storages — avoids `?? []` + entries() per call. */
39
+ alsStorages = [];
59
40
  constructor(discovery, options) {
60
41
  this.discovery = discovery;
61
42
  this.options = options;
@@ -66,70 +47,142 @@ let WorkerService = class WorkerService {
66
47
  initPool() {
67
48
  if (this.pool)
68
49
  return;
50
+ this.alsStorages = (this.options.asyncLocalStorages ?? []);
69
51
  const tasks = this.discovery.scan();
52
+ const proxyMap = new Map();
70
53
  for (const task of tasks) {
71
- this.taskOptions.set(`${task.serviceName}.${task.methodName}`, { priority: task.priority, timeout: task.timeout });
54
+ const key = `${task.serviceName}.${task.methodName}`;
55
+ this.taskDefaults.set(key, {
56
+ priority: task.priority,
57
+ timeout: task.timeout,
58
+ retry: task.retry,
59
+ retryDelay: task.retryDelay,
60
+ });
61
+ const descriptors = task.proxyInstances.map((p) => {
62
+ if (!proxyMap.has(p.propertyKey)) {
63
+ proxyMap.set(p.propertyKey, { methodNames: p.methodNames, instance: p.instance });
64
+ }
65
+ return { propertyKey: p.propertyKey, methodNames: p.methodNames };
66
+ });
67
+ this.taskProxies.set(key, descriptors);
72
68
  }
73
69
  const serialized = (0, di_serializer_1.serializeForWorker)(tasks);
74
- this.pool = new worker_pool_1.WorkerPool(serialized, this.options.poolSize);
70
+ const proxyInstances = Array.from(proxyMap.entries()).map(([propertyKey, { methodNames, instance }]) => ({ propertyKey, methodNames, instance }));
71
+ this.pool = new worker_pool_1.WorkerPool(serialized, proxyInstances, this.options.poolSize, this.options.shutdownTimeout);
72
+ // Forward pool events to logger and expose via EventEmitter
73
+ this.pool.on('dead', (event) => {
74
+ this.logger.error(`Dead letter: ${event.serviceName}.${event.methodName} ` +
75
+ `failed after ${event.attempts} attempt(s) — ${event.error.message}`);
76
+ });
77
+ this.pool.on('error', (err) => {
78
+ this.logger.error(`Worker pool error: ${err.message}`, err.stack);
79
+ });
75
80
  }
76
81
  /**
77
- * Executes a worker task.
78
- *
79
- * Parameters:
80
- * - serviceName: target service
81
- * - methodName: target method
82
- * - args: serialized arguments
83
- * - overrides: runtime priority/timeout overrides
84
- *
85
- * Priority:
86
- * - HIGH
87
- * - NORMAL
88
- * - LOW
89
- *
90
- * Timeout:
91
- * Automatically terminates timed-out workers.
82
+ * Run a @WorkerTask method in a worker thread.
92
83
  *
93
- * Example:
94
- *
95
- * ```ts
96
- * await workerService.run(
97
- * 'ImageService',
98
- * 'generateThumbnail',
99
- * [1920, 1080],
100
- * {
101
- * priority: 'HIGH',
102
- * timeout: 3000,
103
- * },
104
- * );
105
- * ```
84
+ * @param serviceName Class name of the @WorkerClass provider
85
+ * @param methodName Method decorated with @WorkerTask
86
+ * @param args structuredClone-compatible arguments
87
+ * @param options Optional priority / timeout / retry / AbortSignal overrides
106
88
  */
107
- run(serviceName, methodName, args = [], overrides = {}) {
89
+ run(serviceName, methodName, args = [], options = {}) {
108
90
  const key = `${serviceName}.${methodName}`;
109
- const defaults = this.taskOptions.get(key) ??
110
- { priority: 'NORMAL' };
91
+ const defaults = this.taskDefaults.get(key) ?? DEFAULT_TASK;
92
+ const proxyServices = this.taskProxies.get(key) ?? EMPTY_PROXIES;
93
+ // Capture ALS context only if any storages are registered. Empty objects
94
+ // still cost allocation + a structuredClone hop across the worker boundary.
95
+ let alsContext;
96
+ const storages = this.alsStorages;
97
+ for (let i = 0, len = storages.length; i < len; i++) {
98
+ const store = storages[i].getStore();
99
+ if (store !== undefined) {
100
+ (alsContext ??= {})[i < 10 ? String.fromCharCode(48 + i) : String(i)] = store;
101
+ }
102
+ }
103
+ // Capture OTEL trace context if available (lazy, cached lookup).
104
+ const traceContext = captureTraceContext();
105
+ // Generate a unique signal ID if an AbortSignal was provided
106
+ const abortSignalId = options.signal ? nextId() : undefined;
111
107
  return this.pool.execute({
108
+ jobId: nextId(),
112
109
  serviceName,
113
110
  methodName,
114
111
  args,
115
- priority: overrides.priority ?? defaults.priority,
116
- timeout: overrides.timeout ?? defaults.timeout,
117
- });
112
+ priority: options.priority ?? defaults.priority,
113
+ timeout: options.timeout ?? defaults.timeout,
114
+ retry: options.retry ?? defaults.retry ?? 0,
115
+ retryDelay: options.retryDelay ?? defaults.retryDelay ?? 0,
116
+ proxyServices,
117
+ alsContext: alsContext ?? EMPTY_ALS,
118
+ traceContext,
119
+ abortSignalId,
120
+ }, options.signal);
121
+ }
122
+ /** Listen for dead-letter events (jobs that exhausted all retry attempts) */
123
+ onDead(listener) {
124
+ this.pool?.on('dead', listener);
125
+ return this;
126
+ }
127
+ /** Listen for task lifecycle events */
128
+ onTaskEnd(listener) {
129
+ this.pool?.on('taskEnd', listener);
130
+ return this;
131
+ }
132
+ onTaskStart(listener) {
133
+ this.pool?.on('taskStart', listener);
134
+ return this;
135
+ }
136
+ onTaskError(listener) {
137
+ this.pool?.on('taskError', listener);
138
+ return this;
139
+ }
140
+ /** Current pool stats — use for health checks and metrics */
141
+ stats() {
142
+ return this.pool?.stats() ?? {
143
+ poolSize: this.options.poolSize ?? 0,
144
+ idle: 0, busy: 0, queued: 0, warmingUp: 0,
145
+ };
118
146
  }
119
- /**
120
- * Gracefully shuts down worker pool.
121
- *
122
- * Called automatically by NestJS
123
- * during application shutdown.
124
- */
125
147
  async onModuleDestroy() {
126
148
  await this.pool?.destroy();
127
149
  }
128
150
  };
129
151
  exports.WorkerService = WorkerService;
130
- exports.WorkerService = WorkerService = __decorate([
152
+ exports.WorkerService = WorkerService = WorkerService_1 = __decorate([
131
153
  (0, common_1.Injectable)(),
132
154
  __param(1, (0, common_1.Inject)('WORKER_OPTIONS')),
133
155
  __metadata("design:paramtypes", [discovery_service_1.WorkerDiscoveryService, Object])
134
156
  ], WorkerService);
157
+ /**
158
+ * Capture the active OpenTelemetry trace context if @opentelemetry/api is
159
+ * available. Returns an empty object otherwise — no hard dependency.
160
+ *
161
+ * The require() lookup is performed at most once and cached, since it shows
162
+ * up on the hot path of every `run()` call.
163
+ */
164
+ const EMPTY_TRACE = Object.freeze({});
165
+ let __otelApi;
166
+ function captureTraceContext() {
167
+ if (__otelApi === undefined) {
168
+ try {
169
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
170
+ __otelApi = require('@opentelemetry/api');
171
+ }
172
+ catch {
173
+ __otelApi = null;
174
+ }
175
+ }
176
+ if (!__otelApi)
177
+ return EMPTY_TRACE;
178
+ const carrier = {};
179
+ __otelApi.propagation.inject(__otelApi.context.active(), carrier);
180
+ // Return the shared empty object when nothing was injected to avoid
181
+ // a per-call structuredClone of an empty object across the worker boundary.
182
+ for (const _k in carrier) {
183
+ void _k;
184
+ return carrier;
185
+ }
186
+ return EMPTY_TRACE;
187
+ }
135
188
  //# sourceMappingURL=worker.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker.service.js","sourceRoot":"","sources":["../../src/core/worker.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmF;AACnF,+CAAyC;AACzC,sEAAsE;AACtE,uDAAuD;AAGvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAa;IAWL;IAEA;IAZX,IAAI,GAAsB,IAAI,CAAC;IACtB,WAAW,GAAG,IAAI,GAAG,EAMnC,CAAC;IAEJ,YACmB,SAAiC,EAEjC,OAA4B;QAF5B,cAAS,GAAT,SAAS,CAAwB;QAEjC,YAAO,GAAP,OAAO,CAAqB;IAE/C,CAAC;IAED,YAAY;QACV,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAEO,QAAQ;QACd,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QAEtB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAEpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,CAAC,GAAG,CAClB,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,EAAE,EACxC,EAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAC,CACjD,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,IAAA,kCAAkB,EAAC,KAAK,CAAC,CAAC;QAE7C,IAAI,CAAC,IAAI,GAAG,IAAI,wBAAU,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,GAAG,CACD,WAAmB,EACnB,UAAkB,EAClB,OAAkB,EAAE,EACpB,YAA2D,EAAE;QAE7D,MAAM,GAAG,GAAG,GAAG,WAAW,IAAI,UAAU,EAAE,CAAC;QAE3C,MAAM,QAAQ,GACZ,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YACzB,EAAC,QAAQ,EAAE,QAAwB,EAAC,CAAC;QAEvC,OAAO,IAAI,CAAC,IAAK,CAAC,OAAO,CAAI;YAC3B,WAAW;YACX,UAAU;YACV,IAAI;YACJ,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;YACjD,OAAO,EAAE,SAAS,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;SAC/C,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAC7B,CAAC;CACF,CAAA;AAnGY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;IAaR,WAAA,IAAA,eAAM,EAAC,gBAAgB,CAAC,CAAA;qCADG,0CAAsB;GAXzC,aAAa,CAmGzB"}
1
+ {"version":3,"file":"worker.service.js","sourceRoot":"","sources":["../../src/core/worker.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAGwB;AACxB,+CAA2C;AAC3C,sEAAwE;AACxE,uDAAyD;AAoBzD,2EAA2E;AAC3E,oEAAoE;AACpE,IAAI,cAAc,GAAG,CAAC,CAAC;AACvB,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC;AACrD,MAAM,MAAM,GAAG,GAAW,EAAE,CAAC,aAAa,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAE7E,4EAA4E;AAC5E,sCAAsC;AACtC,MAAM,aAAa,GAA6B,MAAM,CAAC,MAAM,CAAC,EAAE,CAAwC,CAAC;AACzG,MAAM,SAAS,GAA4B,MAAM,CAAC,MAAM,CAAC,EAAE,CAA4B,CAAC;AACxF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAwB,EAAE,CAExE,CAAC;AAGK,IAAM,aAAa,qBAAnB,MAAM,aAAa;IAaL;IAEA;IAdF,MAAM,GAAG,IAAI,eAAM,CAAC,eAAa,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,GAAsB,IAAI,CAAC;IAEtB,YAAY,GAAG,IAAI,GAAG,EAGpC,CAAC;IACa,WAAW,GAAG,IAAI,GAAG,EAAoC,CAAC;IAC3E,0EAA0E;IAClE,WAAW,GAA2C,EAAE,CAAC;IAEjE,YACmB,SAAiC,EAEjC,OAA4B;QAF5B,cAAS,GAAT,SAAS,CAAwB;QAEjC,YAAO,GAAP,OAAO,CAAqB;IAE/C,CAAC;IAED,YAAY;QACV,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAEO,QAAQ;QACd,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QAEtB,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,EAAE,CAA2C,CAAC;QAErG,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAEpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAGrB,CAAC;QAEJ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE;gBACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC,CAAC;YAEH,MAAM,WAAW,GAA6B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC1E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC;oBACjC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACpF,CAAC;gBACD,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YACpE,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,UAAU,GAAG,IAAA,kCAAkB,EAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CACvD,CAAC,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CACvF,CAAC;QAEF,IAAI,CAAC,IAAI,GAAG,IAAI,wBAAU,CACxB,UAAU,EACV,cAAc,EACd,IAAI,CAAC,OAAO,CAAC,QAAQ,EACrB,IAAI,CAAC,OAAO,CAAC,eAAe,CAC7B,CAAC;QAEF,4DAA4D;QAC5D,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE;YAC9C,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,gBAAgB,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,UAAU,GAAG;gBACxD,gBAAgB,KAAK,CAAC,QAAQ,iBAAiB,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CACrE,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;YACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,GAAG,CACD,WAAmB,EACnB,UAAkB,EAClB,OAAkB,EAAE,EACpB,UAAsB,EAAE;QAExB,MAAM,GAAG,GAAG,GAAG,WAAW,IAAI,UAAU,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC;QAC5D,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC;QAEjE,yEAAyE;QACzE,4EAA4E;QAC5E,IAAI,UAA+C,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YACpD,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YACrC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;YAChF,CAAC;QACH,CAAC;QAED,iEAAiE;QACjE,MAAM,YAAY,GAAG,mBAAmB,EAAE,CAAC;QAE3C,6DAA6D;QAC7D,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAE5D,OAAO,IAAI,CAAC,IAAK,CAAC,OAAO,CACvB;YACE,KAAK,EAAE,MAAM,EAAE;YACf,WAAW;YACX,UAAU;YACV,IAAI;YACJ,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;YAC/C,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;YAC5C,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,IAAI,CAAC;YAC3C,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU,IAAI,CAAC;YAC1D,aAAa;YACb,UAAU,EAAE,UAAU,IAAI,SAAS;YACnC,YAAY;YACZ,aAAa;SACd,EACD,OAAO,CAAC,MAAM,CACf,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,MAAM,CAAC,QAA0C;QAC/C,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uCAAuC;IACvC,SAAS,CAAC,QAAsD;QAC9D,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW,CAAC,QAAkC;QAC5C,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,WAAW,CAAC,QAA0D;QACpE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6DAA6D;IAC7D,KAAK;QACH,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI;YAC3B,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC;YACpC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC;SAC1C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAC7B,CAAC;CACF,CAAA;AApKY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;IAeR,WAAA,IAAA,eAAM,EAAC,gBAAgB,CAAC,CAAA;qCADG,0CAAsB;GAbzC,aAAa,CAoKzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,GAA2B,MAAM,CAAC,MAAM,CAAC,EAAE,CAA2B,CAAC;AACxF,IAAI,SAMS,CAAC;AAEd,SAAS,mBAAmB;IAC1B,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,8DAA8D;YAC9D,SAAS,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,SAAS;QAAE,OAAO,WAAW,CAAC;IACnC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;IAClE,oEAAoE;IACpE,4EAA4E;IAC5E,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,KAAK,EAAE,CAAC;QACR,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -2,36 +2,18 @@ import 'reflect-metadata';
2
2
  export declare const WORKER_CLASS_META = "worker:class";
3
3
  export declare const WORKER_METHOD_META = "worker:method";
4
4
  export declare const WORKER_DEPS_META = "worker:deps";
5
+ export declare const WORKER_PROXY_META = "worker:proxy";
5
6
  export interface WorkerTaskOptions {
6
7
  priority?: 'HIGH' | 'NORMAL' | 'LOW';
7
8
  timeout?: number;
9
+ /** Number of additional attempts after the first failure. Default: 0. */
10
+ retry?: number;
11
+ /** Delay in ms between retry attempts. Supports exponential backoff
12
+ * when set as a function: (attempt) => attempt * 1000 */
13
+ retryDelay?: number | ((attempt: number) => number);
8
14
  }
9
- /**
10
- * @WorkerClass() – marks a provider as a container of worker tasks.
11
- *
12
- * The discovery service scans all NestJS providers for this marker,
13
- * then inspects each method for @WorkerTask().
14
- *
15
- * Declare any injectable deps that your @WorkerTask methods need via
16
- * the `deps` option. These are resolved from the live NestJS container,
17
- * serialised, and reconstructed inside each worker thread.
18
- *
19
- * @example
20
- * @WorkerClass({ deps: [ConfigService] })
21
- * export class ImageService { ... }
22
- */
23
15
  export declare function WorkerClass(options?: {
24
16
  deps?: (abstract new (...a: unknown[]) => unknown)[];
17
+ proxy?: (abstract new (...a: unknown[]) => unknown)[];
25
18
  }): ClassDecorator;
26
- /**
27
- * @WorkerTask() – marks a method to be offloaded to a worker thread.
28
- *
29
- * The method must be pure with respect to thread-crossing:
30
- * its arguments and return value must be structured-clone compatible.
31
- * Any NestJS deps it needs should be declared on @WorkerClass({ deps }).
32
- *
33
- * @example
34
- * @WorkerTask({ priority: 'HIGH', timeout: 5000 })
35
- * resizeImage(value: number): number { ... }
36
- */
37
19
  export declare function WorkerTask(options?: WorkerTaskOptions): MethodDecorator;
@@ -1,45 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WORKER_DEPS_META = exports.WORKER_METHOD_META = exports.WORKER_CLASS_META = void 0;
3
+ exports.WORKER_PROXY_META = exports.WORKER_DEPS_META = exports.WORKER_METHOD_META = exports.WORKER_CLASS_META = void 0;
4
4
  exports.WorkerClass = WorkerClass;
5
5
  exports.WorkerTask = WorkerTask;
6
6
  require("reflect-metadata");
7
7
  exports.WORKER_CLASS_META = 'worker:class';
8
8
  exports.WORKER_METHOD_META = 'worker:method';
9
9
  exports.WORKER_DEPS_META = 'worker:deps';
10
- /**
11
- * @WorkerClass() – marks a provider as a container of worker tasks.
12
- *
13
- * The discovery service scans all NestJS providers for this marker,
14
- * then inspects each method for @WorkerTask().
15
- *
16
- * Declare any injectable deps that your @WorkerTask methods need via
17
- * the `deps` option. These are resolved from the live NestJS container,
18
- * serialised, and reconstructed inside each worker thread.
19
- *
20
- * @example
21
- * @WorkerClass({ deps: [ConfigService] })
22
- * export class ImageService { ... }
23
- */
10
+ exports.WORKER_PROXY_META = 'worker:proxy';
24
11
  function WorkerClass(options = {}) {
25
12
  return (target) => {
26
13
  Reflect.defineMetadata(exports.WORKER_CLASS_META, true, target);
27
14
  if (options.deps?.length) {
28
15
  Reflect.defineMetadata(exports.WORKER_DEPS_META, options.deps, target);
29
16
  }
17
+ if (options.proxy?.length) {
18
+ Reflect.defineMetadata(exports.WORKER_PROXY_META, options.proxy, target);
19
+ }
30
20
  };
31
21
  }
32
- /**
33
- * @WorkerTask() – marks a method to be offloaded to a worker thread.
34
- *
35
- * The method must be pure with respect to thread-crossing:
36
- * its arguments and return value must be structured-clone compatible.
37
- * Any NestJS deps it needs should be declared on @WorkerClass({ deps }).
38
- *
39
- * @example
40
- * @WorkerTask({ priority: 'HIGH', timeout: 5000 })
41
- * resizeImage(value: number): number { ... }
42
- */
43
22
  function WorkerTask(options = {}) {
44
23
  return (target, propertyKey) => {
45
24
  Reflect.defineMetadata(exports.WORKER_METHOD_META, options, target, propertyKey);
@@ -1 +1 @@
1
- {"version":3,"file":"worker-task.decorator.js","sourceRoot":"","sources":["../../src/decorators/worker-task.decorator.ts"],"names":[],"mappings":";;;AAyBA,kCASC;AAaD,gCAIC;AAnDD,4BAA0B;AAEb,QAAA,iBAAiB,GAAG,cAAc,CAAC;AACnC,QAAA,kBAAkB,GAAG,eAAe,CAAC;AACrC,QAAA,gBAAgB,GAAG,aAAa,CAAC;AAO9C;;;;;;;;;;;;;GAaG;AACH,SAAgB,WAAW,CACzB,UAAoE,EAAE;IAEtE,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,OAAO,CAAC,cAAc,CAAC,yBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC,cAAc,CAAC,wBAAgB,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,UAAU,CAAC,UAA6B,EAAE;IACxD,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QAC7B,OAAO,CAAC,cAAc,CAAC,0BAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"worker-task.decorator.js","sourceRoot":"","sources":["../../src/decorators/worker-task.decorator.ts"],"names":[],"mappings":";;;AAiBA,kCAeC;AAED,gCAIC;AAtCD,4BAA0B;AAEb,QAAA,iBAAiB,GAAI,cAAc,CAAC;AACpC,QAAA,kBAAkB,GAAG,eAAe,CAAC;AACrC,QAAA,gBAAgB,GAAK,aAAa,CAAC;AACnC,QAAA,iBAAiB,GAAI,cAAc,CAAC;AAYjD,SAAgB,WAAW,CACzB,UAGI,EAAE;IAEN,OAAO,CAAC,MAAM,EAAE,EAAE;QAChB,OAAO,CAAC,cAAc,CAAC,yBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC,cAAc,CAAC,wBAAgB,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YAC1B,OAAO,CAAC,cAAc,CAAC,yBAAiB,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,UAAU,CAAC,UAA6B,EAAE;IACxD,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QAC7B,OAAO,CAAC,cAAc,CAAC,0BAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC"}
@@ -1,20 +1,13 @@
1
1
  import { ModuleRef, ModulesContainer } from '@nestjs/core';
2
2
  import type { DiscoveredTask } from '../core/worker.interfaces';
3
- /**
4
- * WorkerDiscoveryService
5
- *
6
- * Scans both module.providers AND module.controllers so that
7
- * @WorkerClass() / @WorkerTask() work on NestJS controllers too.
8
- *
9
- * scan() is called lazily by WorkerService on the first run() call,
10
- * guaranteeing all providers and controllers are fully instantiated.
11
- */
12
3
  export declare class WorkerDiscoveryService {
13
4
  private readonly modulesContainer;
14
5
  private readonly moduleRef;
6
+ private readonly logger;
15
7
  private scanned;
16
8
  private discovered;
17
9
  constructor(modulesContainer: ModulesContainer, moduleRef: ModuleRef);
18
10
  scan(): DiscoveredTask[];
19
11
  private inspectWrapper;
12
+ private resolveToken;
20
13
  }
@@ -8,23 +8,16 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var WorkerDiscoveryService_1;
11
12
  Object.defineProperty(exports, "__esModule", { value: true });
12
13
  exports.WorkerDiscoveryService = void 0;
13
14
  const common_1 = require("@nestjs/common");
14
15
  const core_1 = require("@nestjs/core");
15
16
  const worker_task_decorator_1 = require("../decorators/worker-task.decorator");
16
- /**
17
- * WorkerDiscoveryService
18
- *
19
- * Scans both module.providers AND module.controllers so that
20
- * @WorkerClass() / @WorkerTask() work on NestJS controllers too.
21
- *
22
- * scan() is called lazily by WorkerService on the first run() call,
23
- * guaranteeing all providers and controllers are fully instantiated.
24
- */
25
- let WorkerDiscoveryService = class WorkerDiscoveryService {
17
+ let WorkerDiscoveryService = WorkerDiscoveryService_1 = class WorkerDiscoveryService {
26
18
  modulesContainer;
27
19
  moduleRef;
20
+ logger = new common_1.Logger(WorkerDiscoveryService_1.name);
28
21
  scanned = false;
29
22
  discovered = [];
30
23
  constructor(modulesContainer, moduleRef) {
@@ -36,59 +29,131 @@ let WorkerDiscoveryService = class WorkerDiscoveryService {
36
29
  return this.discovered;
37
30
  this.scanned = true;
38
31
  for (const module of this.modulesContainer.values()) {
39
- // Scan providers (services, repositories, etc.)
40
32
  for (const wrapper of module.providers.values()) {
41
33
  this.inspectWrapper(wrapper);
42
34
  }
43
- // Scan controllers — NestJS registers these separately
44
35
  for (const wrapper of module.controllers.values()) {
45
36
  this.inspectWrapper(wrapper);
46
37
  }
47
38
  }
39
+ if (this.discovered.length === 0) {
40
+ this.logger.warn('No @WorkerTask methods found. Ensure at least one class is decorated ' +
41
+ 'with @WorkerClass() and has methods decorated with @WorkerTask().');
42
+ }
48
43
  return this.discovered;
49
44
  }
50
45
  inspectWrapper(wrapper) {
51
46
  const { instance, metatype } = wrapper;
52
47
  if (!instance || !metatype)
53
48
  return;
54
- const isWorkerClass = Reflect.getMetadata(worker_task_decorator_1.WORKER_CLASS_META, metatype);
55
- if (!isWorkerClass)
49
+ if (!Reflect.getMetadata(worker_task_decorator_1.WORKER_CLASS_META, metatype))
56
50
  return;
57
51
  const serviceName = metatype.name;
58
- const proto = Object.getPrototypeOf(instance);
52
+ const proto = metatype.prototype;
53
+ // ── serialised deps ───────────────────────────────────────────────────
59
54
  const depTypes = Reflect.getMetadata(worker_task_decorator_1.WORKER_DEPS_META, metatype) ?? [];
60
- const deps = depTypes.map((token) => {
61
- try {
62
- return this.moduleRef.get(token, { strict: false });
55
+ const deps = depTypes.map((token) => this.resolveToken(token, serviceName, 'deps'));
56
+ // ── proxy services ────────────────────────────────────────────────────
57
+ const proxyTypes = Reflect.getMetadata(worker_task_decorator_1.WORKER_PROXY_META, metatype) ?? [];
58
+ const proxyInstances = proxyTypes.map((token) => {
59
+ const svcInstance = this.resolveToken(token, serviceName, 'proxy');
60
+ const tokenName = token.name ?? 'unknown';
61
+ const propertyKey = findPropertyKey(instance, svcInstance) ?? camelCase(tokenName);
62
+ if (!findPropertyKey(instance, svcInstance)) {
63
+ this.logger.warn(`${serviceName}: could not find property key for proxy "${tokenName}" ` +
64
+ `— falling back to camelCase: "${propertyKey}".`);
63
65
  }
64
- catch {
65
- return undefined;
66
+ const methodNames = [];
67
+ if (svcInstance) {
68
+ let cursor = Object.getPrototypeOf(svcInstance);
69
+ while (cursor && cursor !== Object.prototype) {
70
+ for (const k of Object.getOwnPropertyNames(cursor)) {
71
+ if (k !== 'constructor' && !methodNames.includes(k)) {
72
+ const desc = Object.getOwnPropertyDescriptor(cursor, k);
73
+ if (desc && typeof desc.value === 'function')
74
+ methodNames.push(k);
75
+ }
76
+ }
77
+ cursor = Object.getPrototypeOf(cursor);
78
+ }
66
79
  }
80
+ return { propertyKey, methodNames, instance: svcInstance ?? {} };
67
81
  });
82
+ // ── @WorkerTask methods ───────────────────────────────────────────────
83
+ let tasksFound = 0;
68
84
  for (const methodName of Object.getOwnPropertyNames(proto)) {
69
85
  if (methodName === 'constructor')
70
86
  continue;
71
87
  const options = Reflect.getMetadata(worker_task_decorator_1.WORKER_METHOD_META, proto, methodName);
72
88
  if (!options)
73
89
  continue;
90
+ tasksFound++;
91
+ // Normalise retryDelay: function form → serialised as max of first 3 calls
92
+ // (functions can't cross the thread boundary; we store the numeric value)
93
+ let retryDelay;
94
+ if (typeof options.retryDelay === 'function') {
95
+ // Store delays for attempts 1-3 as a simple average to give workers
96
+ // a representative delay. For production use, pass a number.
97
+ const fn = options.retryDelay;
98
+ retryDelay = Math.round((fn(1) + fn(2) + fn(3)) / 3);
99
+ this.logger.warn(`${serviceName}.${methodName}: retryDelay as a function is not supported ` +
100
+ `across thread boundaries. Computed average: ${retryDelay}ms. ` +
101
+ `Pass a number for precise control.`);
102
+ }
103
+ else {
104
+ retryDelay = options.retryDelay;
105
+ }
74
106
  const fn = instance[methodName].bind(instance);
75
107
  this.discovered.push({
76
108
  serviceName,
77
109
  methodName,
78
110
  priority: options.priority ?? 'NORMAL',
79
111
  timeout: options.timeout,
112
+ retry: options.retry,
113
+ retryDelay,
80
114
  fn,
81
115
  metatype: metatype,
82
116
  instance,
83
117
  deps,
118
+ proxyInstances,
84
119
  });
120
+ this.logger.debug(`Registered task: ${serviceName}.${methodName} ` +
121
+ `[priority=${options.priority ?? 'NORMAL'}` +
122
+ `${options.timeout ? `, timeout=${options.timeout}ms` : ''}` +
123
+ `${options.retry ? `, retry=${options.retry}` : ''}]`);
124
+ }
125
+ if (tasksFound === 0) {
126
+ this.logger.warn(`${serviceName} has @WorkerClass() but no @WorkerTask() methods.`);
127
+ }
128
+ }
129
+ resolveToken(token, ownerName, role) {
130
+ try {
131
+ return this.moduleRef.get(token, { strict: false });
132
+ }
133
+ catch (err) {
134
+ const name = token.name ?? String(token);
135
+ this.logger.error(`${ownerName}: failed to resolve ${role} token "${name}". ` +
136
+ `Original error: ${err.message}`);
137
+ return undefined;
85
138
  }
86
139
  }
87
140
  };
88
141
  exports.WorkerDiscoveryService = WorkerDiscoveryService;
89
- exports.WorkerDiscoveryService = WorkerDiscoveryService = __decorate([
142
+ exports.WorkerDiscoveryService = WorkerDiscoveryService = WorkerDiscoveryService_1 = __decorate([
90
143
  (0, common_1.Injectable)(),
91
144
  __metadata("design:paramtypes", [core_1.ModulesContainer,
92
145
  core_1.ModuleRef])
93
146
  ], WorkerDiscoveryService);
147
+ function findPropertyKey(serviceInstance, depInstance) {
148
+ if (!serviceInstance || !depInstance || typeof serviceInstance !== 'object')
149
+ return undefined;
150
+ for (const key of Object.getOwnPropertyNames(serviceInstance)) {
151
+ if (serviceInstance[key] === depInstance)
152
+ return key;
153
+ }
154
+ return undefined;
155
+ }
156
+ function camelCase(name) {
157
+ return name.charAt(0).toLowerCase() + name.slice(1);
158
+ }
94
159
  //# sourceMappingURL=discovery.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.service.js","sourceRoot":"","sources":["../../src/discovery/discovery.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,uCAA2D;AAE3D,+EAK6C;AAG7C;;;;;;;;GAQG;AAEI,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IAKd;IACA;IALX,OAAO,GAAG,KAAK,CAAC;IAChB,UAAU,GAAqB,EAAE,CAAC;IAE1C,YACmB,gBAAkC,EAClC,SAAoB;QADpB,qBAAgB,GAAhB,gBAAgB,CAAkB;QAClC,cAAS,GAAT,SAAS,CAAW;IACpC,CAAC;IAEJ,IAAI;QACF,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC;YACpD,gDAAgD;YAChD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;gBAChD,IAAI,CAAC,cAAc,CAAC,OAA0B,CAAC,CAAC;YAClD,CAAC;YACD,uDAAuD;YACvD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;gBAClD,IAAI,CAAC,cAAc,CAAC,OAA0B,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAEO,cAAc,CAAC,OAAwB;QAC7C,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QACvC,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ;YAAE,OAAO;QAEnC,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,yCAAiB,EAAE,QAAQ,CAAC,CAAC;QACvE,IAAI,CAAC,aAAa;YAAE,OAAO;QAE3B,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC;QAClC,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,QAAQ,CAA4B,CAAC;QAEzE,MAAM,QAAQ,GACZ,OAAO,CAAC,WAAW,CAAC,wCAAgB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QAExD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAClC,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,IAAI,UAAU,KAAK,aAAa;gBAAE,SAAS;YAC3C,MAAM,OAAO,GAAkC,OAAO,CAAC,WAAW,CAChE,0CAAkB,EAClB,KAAK,EACL,UAAU,CACX,CAAC;YACF,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,EAAE,GACN,QACD,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAE7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBACnB,WAAW;gBACX,UAAU;gBACV,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ;gBACtC,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,EAAE;gBACF,QAAQ,EAAE,QAA+C;gBACzD,QAAQ;gBACR,IAAI;aACL,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAA;AAzEY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,mBAAU,GAAE;qCAM0B,uBAAgB;QACvB,gBAAS;GAN5B,sBAAsB,CAyElC"}
1
+ {"version":3,"file":"discovery.service.js","sourceRoot":"","sources":["../../src/discovery/discovery.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Throughput / latency micro-benchmark.
3
+ *
4
+ * Usage:
5
+ * npx ts-node src/example/bench.ts # default 5000 tasks
6
+ * TASKS=20000 POOL=8 npx ts-node src/example/bench.ts
7
+ *
8
+ * Reports:
9
+ * - cold-start time (until pool is ready for first task)
10
+ * - p50 / p95 / p99 / max round-trip latency
11
+ * - sustained throughput (tasks / second)
12
+ */
13
+ import 'reflect-metadata';