nestworker 2.0.8 → 2.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.
@@ -11,51 +11,24 @@ 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 __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ var WorkerService_1;
14
18
  Object.defineProperty(exports, "__esModule", { value: true });
15
19
  exports.WorkerService = void 0;
16
20
  const common_1 = require("@nestjs/common");
21
+ const node_crypto_1 = __importDefault(require("node:crypto"));
17
22
  const worker_pool_1 = require("./worker.pool");
18
23
  const discovery_service_1 = require("../discovery/discovery.service");
19
24
  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 {
25
+ let WorkerService = WorkerService_1 = class WorkerService {
55
26
  discovery;
56
27
  options;
28
+ logger = new common_1.Logger(WorkerService_1.name);
57
29
  pool = null;
58
- taskOptions = new Map();
30
+ taskDefaults = new Map();
31
+ taskProxies = new Map();
59
32
  constructor(discovery, options) {
60
33
  this.discovery = discovery;
61
34
  this.options = options;
@@ -67,69 +40,122 @@ let WorkerService = class WorkerService {
67
40
  if (this.pool)
68
41
  return;
69
42
  const tasks = this.discovery.scan();
43
+ const proxyMap = new Map();
70
44
  for (const task of tasks) {
71
- this.taskOptions.set(`${task.serviceName}.${task.methodName}`, { priority: task.priority, timeout: task.timeout });
45
+ const key = `${task.serviceName}.${task.methodName}`;
46
+ this.taskDefaults.set(key, {
47
+ priority: task.priority,
48
+ timeout: task.timeout,
49
+ retry: task.retry,
50
+ retryDelay: task.retryDelay,
51
+ });
52
+ const descriptors = task.proxyInstances.map((p) => {
53
+ if (!proxyMap.has(p.propertyKey)) {
54
+ proxyMap.set(p.propertyKey, { methodNames: p.methodNames, instance: p.instance });
55
+ }
56
+ return { propertyKey: p.propertyKey, methodNames: p.methodNames };
57
+ });
58
+ this.taskProxies.set(key, descriptors);
72
59
  }
73
60
  const serialized = (0, di_serializer_1.serializeForWorker)(tasks);
74
- this.pool = new worker_pool_1.WorkerPool(serialized, this.options.poolSize);
61
+ const proxyInstances = Array.from(proxyMap.entries()).map(([propertyKey, { methodNames, instance }]) => ({ propertyKey, methodNames, instance }));
62
+ this.pool = new worker_pool_1.WorkerPool(serialized, proxyInstances, this.options.poolSize, this.options.shutdownTimeout);
63
+ // Forward pool events to logger and expose via EventEmitter
64
+ this.pool.on('dead', (event) => {
65
+ this.logger.error(`Dead letter: ${event.serviceName}.${event.methodName} ` +
66
+ `failed after ${event.attempts} attempt(s) — ${event.error.message}`);
67
+ });
68
+ this.pool.on('error', (err) => {
69
+ this.logger.error(`Worker pool error: ${err.message}`, err.stack);
70
+ });
75
71
  }
76
72
  /**
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
73
+ * Run a @WorkerTask method in a worker thread.
84
74
  *
85
- * Priority:
86
- * - HIGH
87
- * - NORMAL
88
- * - LOW
89
- *
90
- * Timeout:
91
- * Automatically terminates timed-out workers.
92
- *
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
- * ```
75
+ * @param serviceName Class name of the @WorkerClass provider
76
+ * @param methodName Method decorated with @WorkerTask
77
+ * @param args structuredClone-compatible arguments
78
+ * @param options Optional priority / timeout / retry / AbortSignal overrides
106
79
  */
107
- run(serviceName, methodName, args = [], overrides = {}) {
80
+ run(serviceName, methodName, args = [], options = {}) {
108
81
  const key = `${serviceName}.${methodName}`;
109
- const defaults = this.taskOptions.get(key) ??
110
- { priority: 'NORMAL' };
82
+ const defaults = this.taskDefaults.get(key) ?? { priority: 'NORMAL' };
83
+ const proxyServices = this.taskProxies.get(key) ?? [];
84
+ // Capture ALS context from all registered storages
85
+ const alsContext = {};
86
+ for (const [i, als] of (this.options.asyncLocalStorages ?? []).entries()) {
87
+ const store = als.getStore();
88
+ if (store !== undefined)
89
+ alsContext[String(i)] = store;
90
+ }
91
+ // Capture OTEL trace context if available
92
+ const traceContext = captureTraceContext();
93
+ // Generate a unique signal ID if an AbortSignal was provided
94
+ const abortSignalId = options.signal ? node_crypto_1.default.randomUUID() : undefined;
111
95
  return this.pool.execute({
96
+ jobId: node_crypto_1.default.randomUUID(),
112
97
  serviceName,
113
98
  methodName,
114
99
  args,
115
- priority: overrides.priority ?? defaults.priority,
116
- timeout: overrides.timeout ?? defaults.timeout,
117
- });
100
+ priority: options.priority ?? defaults.priority,
101
+ timeout: options.timeout ?? defaults.timeout,
102
+ retry: options.retry ?? defaults.retry ?? 0,
103
+ retryDelay: options.retryDelay ?? defaults.retryDelay ?? 0,
104
+ proxyServices,
105
+ alsContext,
106
+ traceContext,
107
+ abortSignalId,
108
+ }, options.signal);
109
+ }
110
+ /** Listen for dead-letter events (jobs that exhausted all retry attempts) */
111
+ onDead(listener) {
112
+ this.pool?.on('dead', listener);
113
+ return this;
114
+ }
115
+ /** Listen for task lifecycle events */
116
+ onTaskEnd(listener) {
117
+ this.pool?.on('taskEnd', listener);
118
+ return this;
119
+ }
120
+ onTaskStart(listener) {
121
+ this.pool?.on('taskStart', listener);
122
+ return this;
123
+ }
124
+ onTaskError(listener) {
125
+ this.pool?.on('taskError', listener);
126
+ return this;
127
+ }
128
+ /** Current pool stats — use for health checks and metrics */
129
+ stats() {
130
+ return this.pool?.stats() ?? {
131
+ poolSize: this.options.poolSize ?? 0,
132
+ idle: 0, busy: 0, queued: 0, warmingUp: 0,
133
+ };
118
134
  }
119
- /**
120
- * Gracefully shuts down worker pool.
121
- *
122
- * Called automatically by NestJS
123
- * during application shutdown.
124
- */
125
135
  async onModuleDestroy() {
126
136
  await this.pool?.destroy();
127
137
  }
128
138
  };
129
139
  exports.WorkerService = WorkerService;
130
- exports.WorkerService = WorkerService = __decorate([
140
+ exports.WorkerService = WorkerService = WorkerService_1 = __decorate([
131
141
  (0, common_1.Injectable)(),
132
142
  __param(1, (0, common_1.Inject)('WORKER_OPTIONS')),
133
143
  __metadata("design:paramtypes", [discovery_service_1.WorkerDiscoveryService, Object])
134
144
  ], WorkerService);
145
+ /**
146
+ * Capture the active OpenTelemetry trace context if @opentelemetry/api is
147
+ * available. Returns an empty object otherwise — no hard dependency.
148
+ */
149
+ function captureTraceContext() {
150
+ try {
151
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
152
+ const api = require('@opentelemetry/api');
153
+ const carrier = {};
154
+ api.propagation.inject(api.context.active(), carrier);
155
+ return carrier;
156
+ }
157
+ catch {
158
+ return {};
159
+ }
160
+ }
135
161
  //# 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":"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"}
@@ -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":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,uCAA2D;AAE3D,+EAM6C;AAItC,IAAM,sBAAsB,8BAA5B,MAAM,sBAAsB;IAMd;IACA;IANF,MAAM,GAAG,IAAI,eAAM,CAAC,wBAAsB,CAAC,IAAI,CAAC,CAAC;IAC1D,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,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;gBAChD,IAAI,CAAC,cAAc,CAAC,OAA0B,CAAC,CAAC;YAClD,CAAC;YACD,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,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,uEAAuE;gBACvE,mEAAmE,CACpE,CAAC;QACJ,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;QACnC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,yCAAiB,EAAE,QAAQ,CAAC;YAAE,OAAO;QAE9D,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC;QAClC,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAoC,CAAC;QAE5D,yEAAyE;QACzE,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,CAClC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,CAC9C,CAAC;QAEF,yEAAyE;QACzE,MAAM,UAAU,GACd,OAAO,CAAC,WAAW,CAAC,yCAAiB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEzD,MAAM,cAAc,GAAoB,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CACJ,CAAC;YAE9D,MAAM,SAAS,GAAI,KAA2B,CAAC,IAAI,IAAI,SAAS,CAAC;YACjE,MAAM,WAAW,GAAG,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;YAEnF,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC;gBAC5C,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,GAAG,WAAW,4CAA4C,SAAS,IAAI;oBACvE,iCAAiC,WAAW,IAAI,CACjD,CAAC;YACJ,CAAC;YAED,MAAM,WAAW,GAAa,EAAE,CAAC;YACjC,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,WAAW,CAAkB,CAAC;gBACjE,OAAO,MAAM,IAAI,MAAM,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;oBAC7C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;wBACnD,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;4BACpD,MAAM,IAAI,GAAG,MAAM,CAAC,wBAAwB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;4BACxD,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,UAAU;gCAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;wBACpE,CAAC;oBACH,CAAC;oBACD,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAkB,CAAC;gBAC1D,CAAC;YACH,CAAC;YAED,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,IAAI,EAAE,EAAE,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,yEAAyE;QACzE,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,IAAI,UAAU,KAAK,aAAa;gBAAE,SAAS;YAE3C,MAAM,OAAO,GAAkC,OAAO,CAAC,WAAW,CAChE,0CAAkB,EAAE,KAAK,EAAE,UAAU,CACtC,CAAC;YACF,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,UAAU,EAAE,CAAC;YAEb,2EAA2E;YAC3E,0EAA0E;YAC1E,IAAI,UAA8B,CAAC;YACnC,IAAI,OAAO,OAAO,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;gBAC7C,oEAAoE;gBACpE,6DAA6D;gBAC7D,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;gBAC9B,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACrD,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,GAAG,WAAW,IAAI,UAAU,8CAA8C;oBAC1E,+CAA+C,UAAU,MAAM;oBAC/D,oCAAoC,CACrC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;YAClC,CAAC;YAED,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,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,UAAU;gBACV,EAAE;gBACF,QAAQ,EAAE,QAA+C;gBACzD,QAAQ;gBACR,IAAI;gBACJ,cAAc;aACf,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,oBAAoB,WAAW,IAAI,UAAU,GAAG;gBAChD,aAAa,OAAO,CAAC,QAAQ,IAAI,QAAQ,EAAE;gBAC3C,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC5D,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CACtD,CAAC;QACJ,CAAC;QAED,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,mDAAmD,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAEO,YAAY,CAClB,KAAgD,EAChD,SAAiB,EACjB,IAAsB;QAEtB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,GAAI,KAA2B,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,GAAG,SAAS,uBAAuB,IAAI,WAAW,IAAI,KAAK;gBAC3D,mBAAoB,GAAa,CAAC,OAAO,EAAE,CAC5C,CAAC;YACF,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;CACF,CAAA;AAjKY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,mBAAU,GAAE;qCAO0B,uBAAgB;QACvB,gBAAS;GAP5B,sBAAsB,CAiKlC;AAED,SAAS,eAAe,CACtB,eAAwB,EACxB,WAAoB;IAEpB,IAAI,CAAC,eAAe,IAAI,CAAC,WAAW,IAAI,OAAO,eAAe,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC9F,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,mBAAmB,CAAC,eAAe,CAAC,EAAE,CAAC;QAC9D,IAAK,eAA2C,CAAC,GAAG,CAAC,KAAK,WAAW;YAAE,OAAO,GAAG,CAAC;IACpF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC"}
@@ -17,7 +17,7 @@ let AppModule = class AppModule {
17
17
  };
18
18
  AppModule = __decorate([
19
19
  (0, common_1.Module)({
20
- imports: [worker_module_1.WorkerModule.forRoot({ poolSize: 8 })],
20
+ imports: [worker_module_1.WorkerModule.forRoot({ poolSize: 4, shutdownTimeout: 10000 })],
21
21
  providers: [config_service_1.ConfigService, image_service_1.ImageService],
22
22
  })
23
23
  ], AppModule);
@@ -26,6 +26,18 @@ async function bootstrap() {
26
26
  logger: false,
27
27
  });
28
28
  const workerService = app.get(worker_service_1.WorkerService);
29
+ workerService.onTaskStart((task) => {
30
+ console.log('Task started:', task.jobId, workerService.stats());
31
+ });
32
+ workerService.onTaskEnd(((task, durationMs) => {
33
+ console.log('Task ended:', task.jobId, durationMs);
34
+ }));
35
+ workerService.onTaskError(((task, error) => {
36
+ console.log('Task error:', task.jobId, error);
37
+ }));
38
+ workerService.onDead((task) => {
39
+ console.log('Task dead:', task.jobId);
40
+ });
29
41
  // ── Task 1: sequential ────────────────────────────────────────────────────
30
42
  console.log('▶ resizeImage [priority: HIGH]');
31
43
  console.time('resizeImage');
@@ -35,7 +47,7 @@ async function bootstrap() {
35
47
  // ── Task 2: sequential ────────────────────────────────────────────────────
36
48
  console.log('\n▶ generateThumbnail [priority: LOW override]');
37
49
  console.time('generateThumbnail');
38
- const thumb = await workerService.run('ImageService', 'generateThumbnail', [1920, 1080], { priority: 'LOW' });
50
+ const thumb = await workerService.run('ImageService', 'generateThumbnail', [1920, 1080], { priority: 'LOW', retry: 3, retryDelay: 1000 });
39
51
  console.timeEnd('generateThumbnail');
40
52
  console.log(' result:', thumb);
41
53
  // ── Task 3: concurrent — proves multiple workers run in parallel ───────────
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/example/main.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/example/main.ts"],"names":[],"mappings":"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"}