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
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ /**
13
+ * Throughput / latency micro-benchmark.
14
+ *
15
+ * Usage:
16
+ * npx ts-node src/example/bench.ts # default 5000 tasks
17
+ * TASKS=20000 POOL=8 npx ts-node src/example/bench.ts
18
+ *
19
+ * Reports:
20
+ * - cold-start time (until pool is ready for first task)
21
+ * - p50 / p95 / p99 / max round-trip latency
22
+ * - sustained throughput (tasks / second)
23
+ */
24
+ require("reflect-metadata");
25
+ const core_1 = require("@nestjs/core");
26
+ const common_1 = require("@nestjs/common");
27
+ const node_os_1 = __importDefault(require("node:os"));
28
+ const node_perf_hooks_1 = require("node:perf_hooks");
29
+ const worker_module_1 = require("../core/worker.module");
30
+ const worker_service_1 = require("../core/worker.service");
31
+ const config_service_1 = require("./config.service");
32
+ const image_service_1 = require("./image.service");
33
+ const TASKS = Number(process.env.TASKS ?? 5_000);
34
+ const POOL = Number(process.env.POOL ?? node_os_1.default.cpus().length);
35
+ const WARMUP = Number(process.env.WARMUP ?? 200);
36
+ let BenchModule = class BenchModule {
37
+ };
38
+ BenchModule = __decorate([
39
+ (0, common_1.Module)({
40
+ imports: [worker_module_1.WorkerModule.forRoot({ poolSize: POOL, shutdownTimeout: 5_000 })],
41
+ providers: [config_service_1.ConfigService, image_service_1.ImageService],
42
+ })
43
+ ], BenchModule);
44
+ function pct(sorted, p) {
45
+ if (sorted.length === 0)
46
+ return 0;
47
+ const idx = Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length));
48
+ return sorted[idx];
49
+ }
50
+ async function run() {
51
+ console.log(`▶ bench: tasks=${TASKS} pool=${POOL} warmup=${WARMUP}`);
52
+ const t0 = node_perf_hooks_1.performance.now();
53
+ const app = await core_1.NestFactory.createApplicationContext(BenchModule, { logger: false });
54
+ const ws = app.get(worker_service_1.WorkerService);
55
+ // Cold-start: first task forces pool readiness.
56
+ await ws.run('ImageService', 'moduleRequire');
57
+ const cold = node_perf_hooks_1.performance.now() - t0;
58
+ console.log(` cold-start: ${cold.toFixed(1)} ms`);
59
+ // Warm-up — JIT, MessagePort priming, etc.
60
+ await Promise.all(Array.from({ length: WARMUP }, () => ws.run('ImageService', 'moduleRequire')));
61
+ // Measured run — uses the cheapest task (cached require) so we measure
62
+ // pool + IPC overhead rather than CPU work.
63
+ const latencies = new Float64Array(TASKS);
64
+ const start = node_perf_hooks_1.performance.now();
65
+ await Promise.all(Array.from({ length: TASKS }, (_, i) => {
66
+ const t = node_perf_hooks_1.performance.now();
67
+ return ws.run('ImageService', 'moduleRequire').then(() => {
68
+ latencies[i] = node_perf_hooks_1.performance.now() - t;
69
+ });
70
+ }));
71
+ const wall = node_perf_hooks_1.performance.now() - start;
72
+ const sorted = Array.from(latencies).sort((a, b) => a - b);
73
+ console.log(` wall: ${wall.toFixed(1)} ms`);
74
+ console.log(` throughput: ${(TASKS / (wall / 1000)).toFixed(0)} tasks/s`);
75
+ console.log(` p50: ${pct(sorted, 50).toFixed(3)} ms`);
76
+ console.log(` p95: ${pct(sorted, 95).toFixed(3)} ms`);
77
+ console.log(` p99: ${pct(sorted, 99).toFixed(3)} ms`);
78
+ console.log(` max: ${sorted[sorted.length - 1].toFixed(3)} ms`);
79
+ await app.close();
80
+ }
81
+ run().catch((err) => {
82
+ console.error('Bench failed:', err);
83
+ process.exit(1);
84
+ });
85
+ //# sourceMappingURL=bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bench.js","sourceRoot":"","sources":["../../src/example/bench.ts"],"names":[],"mappings":"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"}
@@ -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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"}
@@ -0,0 +1,46 @@
1
+ import { WorkerService } from '../core/worker.service';
2
+ export interface WorkerHealthResult {
3
+ status: 'up' | 'down';
4
+ details: {
5
+ poolSize: number;
6
+ idle: number;
7
+ busy: number;
8
+ queued: number;
9
+ warmingUp: number;
10
+ };
11
+ error?: string;
12
+ }
13
+ /**
14
+ * WorkerHealthIndicator — plugs into NestJS Terminus.
15
+ *
16
+ * @example
17
+ * // health.controller.ts
18
+ * import { HealthCheck, HealthCheckService } from '@nestjs/terminus';
19
+ * import { WorkerHealthIndicator } from 'nestworker';
20
+ *
21
+ * @Controller('health')
22
+ * export class HealthController {
23
+ * constructor(
24
+ * private health: HealthCheckService,
25
+ * private workerHealth: WorkerHealthIndicator,
26
+ * ) {}
27
+ *
28
+ * @Get()
29
+ * @HealthCheck()
30
+ * check() {
31
+ * return this.health.check([
32
+ * () => this.workerHealth.check('workers'),
33
+ * ]);
34
+ * }
35
+ * }
36
+ */
37
+ export declare class WorkerHealthIndicator {
38
+ private readonly workerService;
39
+ constructor(workerService: WorkerService);
40
+ /**
41
+ * Returns a Terminus-compatible health indicator result.
42
+ * Reports 'down' when warmingUp > 0 (pool not fully ready) or when
43
+ * queued jobs exceed the pool size (backpressure signal).
44
+ */
45
+ check(key: string): Record<string, WorkerHealthResult>;
46
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.WorkerHealthIndicator = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const worker_service_1 = require("../core/worker.service");
15
+ /**
16
+ * WorkerHealthIndicator — plugs into NestJS Terminus.
17
+ *
18
+ * @example
19
+ * // health.controller.ts
20
+ * import { HealthCheck, HealthCheckService } from '@nestjs/terminus';
21
+ * import { WorkerHealthIndicator } from 'nestworker';
22
+ *
23
+ * @Controller('health')
24
+ * export class HealthController {
25
+ * constructor(
26
+ * private health: HealthCheckService,
27
+ * private workerHealth: WorkerHealthIndicator,
28
+ * ) {}
29
+ *
30
+ * @Get()
31
+ * @HealthCheck()
32
+ * check() {
33
+ * return this.health.check([
34
+ * () => this.workerHealth.check('workers'),
35
+ * ]);
36
+ * }
37
+ * }
38
+ */
39
+ let WorkerHealthIndicator = class WorkerHealthIndicator {
40
+ workerService;
41
+ constructor(workerService) {
42
+ this.workerService = workerService;
43
+ }
44
+ /**
45
+ * Returns a Terminus-compatible health indicator result.
46
+ * Reports 'down' when warmingUp > 0 (pool not fully ready) or when
47
+ * queued jobs exceed the pool size (backpressure signal).
48
+ */
49
+ check(key) {
50
+ const stats = this.workerService.stats();
51
+ const isDown = stats.warmingUp > 0 ||
52
+ stats.queued > stats.poolSize;
53
+ const result = {
54
+ status: isDown ? 'down' : 'up',
55
+ details: stats,
56
+ ...(isDown && stats.warmingUp > 0
57
+ ? { error: `${stats.warmingUp} worker(s) still warming up` }
58
+ : {}),
59
+ ...(isDown && stats.queued > stats.poolSize
60
+ ? { error: `Queue depth (${stats.queued}) exceeds pool size (${stats.poolSize})` }
61
+ : {}),
62
+ };
63
+ if (isDown) {
64
+ throw Object.assign(new Error(`Worker pool unhealthy`), {
65
+ [key]: result,
66
+ causes: [result.error],
67
+ });
68
+ }
69
+ return { [key]: result };
70
+ }
71
+ };
72
+ exports.WorkerHealthIndicator = WorkerHealthIndicator;
73
+ exports.WorkerHealthIndicator = WorkerHealthIndicator = __decorate([
74
+ (0, common_1.Injectable)(),
75
+ __metadata("design:paramtypes", [worker_service_1.WorkerService])
76
+ ], WorkerHealthIndicator);
77
+ //# sourceMappingURL=worker.health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.health.js","sourceRoot":"","sources":["../../src/health/worker.health.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,2DAAuD;AAcvD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IACH;IAA7B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAE7D;;;;OAIG;IACH,KAAK,CAAC,GAAW;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QACzC,MAAM,MAAM,GACV,KAAK,CAAC,SAAS,GAAG,CAAC;YACnB,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC;QAEhC,MAAM,MAAM,GAAuB;YACjC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;YAC9B,OAAO,EAAE,KAAK;YACd,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,SAAS,GAAG,CAAC;gBAC/B,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,SAAS,6BAA6B,EAAE;gBAC5D,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ;gBACzC,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,KAAK,CAAC,MAAM,wBAAwB,KAAK,CAAC,QAAQ,GAAG,EAAE;gBAClF,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,EAAE;gBACtD,CAAC,GAAG,CAAC,EAAE,MAAM;gBACb,MAAM,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;aACvB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AAlCY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;qCAEiC,8BAAa;GAD9C,qBAAqB,CAkCjC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  export { WorkerModule } from './core/worker.module';
2
2
  export { WorkerService } from './core/worker.service';
3
+ export type { RunOptions } from './core/worker.service';
3
4
  export { WorkerClass, WorkerTask } from './decorators/worker-task.decorator';
4
- export type { WorkerModuleOptions, TaskPriority } from './core/worker.interfaces';
5
5
  export type { WorkerTaskOptions } from './decorators/worker-task.decorator';
6
+ export { WorkerHealthIndicator } from './health/worker.health';
7
+ export type { WorkerHealthResult } from './health/worker.health';
8
+ export { WorkerMetricsService } from './metrics/worker.metrics';
9
+ export type { WorkerMetricsSnapshot } from './metrics/worker.metrics';
10
+ export type { WorkerJob, WorkerModuleOptions, WorkerModuleAsyncOptions, TaskPriority, DeadLetterEvent, PoolStats, SerializedError, } from './core/worker.interfaces';
package/dist/index.js CHANGED
@@ -1,11 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WorkerTask = exports.WorkerClass = exports.WorkerService = exports.WorkerModule = void 0;
3
+ exports.WorkerMetricsService = exports.WorkerHealthIndicator = exports.WorkerTask = exports.WorkerClass = exports.WorkerService = exports.WorkerModule = void 0;
4
+ // Module
4
5
  var worker_module_1 = require("./core/worker.module");
5
6
  Object.defineProperty(exports, "WorkerModule", { enumerable: true, get: function () { return worker_module_1.WorkerModule; } });
7
+ // Services
6
8
  var worker_service_1 = require("./core/worker.service");
7
9
  Object.defineProperty(exports, "WorkerService", { enumerable: true, get: function () { return worker_service_1.WorkerService; } });
10
+ // Decorators
8
11
  var worker_task_decorator_1 = require("./decorators/worker-task.decorator");
9
12
  Object.defineProperty(exports, "WorkerClass", { enumerable: true, get: function () { return worker_task_decorator_1.WorkerClass; } });
10
13
  Object.defineProperty(exports, "WorkerTask", { enumerable: true, get: function () { return worker_task_decorator_1.WorkerTask; } });
14
+ // Health
15
+ var worker_health_1 = require("./health/worker.health");
16
+ Object.defineProperty(exports, "WorkerHealthIndicator", { enumerable: true, get: function () { return worker_health_1.WorkerHealthIndicator; } });
17
+ // Metrics
18
+ var worker_metrics_1 = require("./metrics/worker.metrics");
19
+ Object.defineProperty(exports, "WorkerMetricsService", { enumerable: true, get: function () { return worker_metrics_1.WorkerMetricsService; } });
11
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,sDAAkD;AAA1C,6GAAA,YAAY,OAAA;AACpB,wDAAoD;AAA5C,+GAAA,aAAa,OAAA;AACrB,4EAA2E;AAAnE,oHAAA,WAAW,OAAA;AAAE,mHAAA,UAAU,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,SAAS;AACT,sDAAsD;AAA7C,6GAAA,YAAY,OAAA;AAErB,WAAW;AACX,wDAAuD;AAA9C,+GAAA,aAAa,OAAA;AAGtB,aAAa;AACb,4EAA6E;AAApE,oHAAA,WAAW,OAAA;AAAE,mHAAA,UAAU,OAAA;AAGhC,SAAS;AACT,wDAA+D;AAAtD,sHAAA,qBAAqB,OAAA;AAG9B,UAAU;AACV,2DAAiE;AAAxD,sHAAA,oBAAoB,OAAA"}
@@ -0,0 +1,65 @@
1
+ import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
2
+ import { WorkerService } from '../core/worker.service';
3
+ export interface WorkerMetricsSnapshot {
4
+ /** Total jobs dispatched since startup */
5
+ jobsTotal: number;
6
+ /** Jobs that completed successfully */
7
+ jobsSuccess: number;
8
+ /** Jobs that failed (after all retries) */
9
+ jobsFailed: number;
10
+ /** Jobs that timed out */
11
+ jobsTimeout: number;
12
+ /** Jobs sent to dead letter queue */
13
+ jobsDead: number;
14
+ /** Current queue depth */
15
+ queueDepth: number;
16
+ /** Current idle worker count */
17
+ idleWorkers: number;
18
+ /** Current busy worker count */
19
+ busyWorkers: number;
20
+ /** Per-task duration histogram (p50, p95, p99) in ms */
21
+ durations: Record<string, {
22
+ p50: number;
23
+ p95: number;
24
+ p99: number;
25
+ count: number;
26
+ }>;
27
+ }
28
+ /**
29
+ * WorkerMetricsService — collects runtime metrics from the worker pool.
30
+ *
31
+ * Designed to be framework-agnostic: read the snapshot and push to
32
+ * Prometheus, Datadog, CloudWatch, or any other metrics provider.
33
+ *
34
+ * @example
35
+ * // Prometheus integration
36
+ * @Get('metrics')
37
+ * async metrics() {
38
+ * const snap = this.workerMetrics.snapshot();
39
+ * return [
40
+ * `nestworker_jobs_total ${snap.jobsTotal}`,
41
+ * `nestworker_jobs_success ${snap.jobsSuccess}`,
42
+ * `nestworker_queue_depth ${snap.queueDepth}`,
43
+ * ].join('\n');
44
+ * }
45
+ */
46
+ export declare class WorkerMetricsService implements OnModuleInit, OnModuleDestroy {
47
+ private readonly workerService;
48
+ private jobsTotal;
49
+ private jobsSuccess;
50
+ private jobsFailed;
51
+ private jobsTimeout;
52
+ private jobsDead;
53
+ /** Raw duration samples per task key — capped at 1000 samples */
54
+ private readonly durationSamples;
55
+ /** Interval handle for periodic pool-stats polling */
56
+ private statsInterval?;
57
+ constructor(workerService: WorkerService);
58
+ onModuleInit(): void;
59
+ onModuleDestroy(): void;
60
+ /** Returns a point-in-time snapshot of all metrics */
61
+ snapshot(): WorkerMetricsSnapshot;
62
+ /** Reset all counters (useful in tests) */
63
+ reset(): void;
64
+ private pushDuration;
65
+ }
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.WorkerMetricsService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const worker_service_1 = require("../core/worker.service");
15
+ /**
16
+ * WorkerMetricsService — collects runtime metrics from the worker pool.
17
+ *
18
+ * Designed to be framework-agnostic: read the snapshot and push to
19
+ * Prometheus, Datadog, CloudWatch, or any other metrics provider.
20
+ *
21
+ * @example
22
+ * // Prometheus integration
23
+ * @Get('metrics')
24
+ * async metrics() {
25
+ * const snap = this.workerMetrics.snapshot();
26
+ * return [
27
+ * `nestworker_jobs_total ${snap.jobsTotal}`,
28
+ * `nestworker_jobs_success ${snap.jobsSuccess}`,
29
+ * `nestworker_queue_depth ${snap.queueDepth}`,
30
+ * ].join('\n');
31
+ * }
32
+ */
33
+ let WorkerMetricsService = class WorkerMetricsService {
34
+ workerService;
35
+ jobsTotal = 0;
36
+ jobsSuccess = 0;
37
+ jobsFailed = 0;
38
+ jobsTimeout = 0;
39
+ jobsDead = 0;
40
+ /** Raw duration samples per task key — capped at 1000 samples */
41
+ durationSamples = new Map();
42
+ /** Interval handle for periodic pool-stats polling */
43
+ statsInterval;
44
+ constructor(workerService) {
45
+ this.workerService = workerService;
46
+ }
47
+ onModuleInit() {
48
+ // Task start
49
+ this.workerService.onTaskStart((job) => {
50
+ this.jobsTotal++;
51
+ });
52
+ // Task end: record duration + success
53
+ this.workerService.onTaskEnd((job, durationMs) => {
54
+ const key = `${job.serviceName}.${job.methodName}`;
55
+ this.jobsSuccess++;
56
+ this.pushDuration(key, durationMs);
57
+ });
58
+ // Task error: record failure
59
+ this.workerService.onTaskError((job, error) => {
60
+ this.jobsFailed++;
61
+ if (error.name === 'TimeoutError')
62
+ this.jobsTimeout++;
63
+ });
64
+ // Dead letter: separate counter
65
+ this.workerService.onDead(() => {
66
+ this.jobsDead++;
67
+ });
68
+ }
69
+ onModuleDestroy() {
70
+ if (this.statsInterval)
71
+ clearInterval(this.statsInterval);
72
+ }
73
+ /** Returns a point-in-time snapshot of all metrics */
74
+ snapshot() {
75
+ const stats = this.workerService.stats();
76
+ const durations = {};
77
+ for (const [key, samples] of this.durationSamples) {
78
+ durations[key] = computePercentiles(samples);
79
+ }
80
+ return {
81
+ jobsTotal: this.jobsTotal,
82
+ jobsSuccess: this.jobsSuccess,
83
+ jobsFailed: this.jobsFailed,
84
+ jobsTimeout: this.jobsTimeout,
85
+ jobsDead: this.jobsDead,
86
+ queueDepth: stats.queued,
87
+ idleWorkers: stats.idle,
88
+ busyWorkers: stats.busy,
89
+ durations,
90
+ };
91
+ }
92
+ /** Reset all counters (useful in tests) */
93
+ reset() {
94
+ this.jobsTotal = this.jobsSuccess = this.jobsFailed =
95
+ this.jobsTimeout = this.jobsDead = 0;
96
+ this.durationSamples.clear();
97
+ }
98
+ pushDuration(key, ms) {
99
+ if (!this.durationSamples.has(key))
100
+ this.durationSamples.set(key, []);
101
+ const samples = this.durationSamples.get(key);
102
+ samples.push(ms);
103
+ // Keep memory bounded — reservoir sampling after 1000 entries
104
+ if (samples.length > 1000) {
105
+ const idx = Math.floor(Math.random() * samples.length);
106
+ samples.splice(idx, 1);
107
+ }
108
+ }
109
+ };
110
+ exports.WorkerMetricsService = WorkerMetricsService;
111
+ exports.WorkerMetricsService = WorkerMetricsService = __decorate([
112
+ (0, common_1.Injectable)(),
113
+ __metadata("design:paramtypes", [worker_service_1.WorkerService])
114
+ ], WorkerMetricsService);
115
+ function computePercentiles(samples) {
116
+ if (samples.length === 0)
117
+ return { p50: 0, p95: 0, p99: 0, count: 0 };
118
+ const sorted = [...samples].sort((a, b) => a - b);
119
+ const p = (pct) => sorted[Math.ceil((pct / 100) * sorted.length) - 1] ?? 0;
120
+ return { p50: p(50), p95: p(95), p99: p(99), count: samples.length };
121
+ }
122
+ //# sourceMappingURL=worker.metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.metrics.js","sourceRoot":"","sources":["../../src/metrics/worker.metrics.ts"],"names":[],"mappings":"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"}