nestjs-temporal-core 3.2.0 → 3.2.2

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.
@@ -26,7 +26,6 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
26
26
  this.injectedConnection = injectedConnection;
27
27
  this.worker = null;
28
28
  this.restartCount = 0;
29
- this.maxRestarts = 3;
30
29
  this.isInitialized = false;
31
30
  this.isRunning = false;
32
31
  this.lastError = null;
@@ -40,15 +39,25 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
40
39
  logLevel: options.logLevel,
41
40
  });
42
41
  }
42
+ get maxRestarts() {
43
+ return this.options.worker?.maxRestarts ?? this.options.maxRestarts ?? 3;
44
+ }
45
+ get autoRestartEnabled() {
46
+ const workerAutoRestart = this.options.worker?.autoRestart;
47
+ if (workerAutoRestart !== undefined) {
48
+ return workerAutoRestart;
49
+ }
50
+ return this.options.autoRestart !== false;
51
+ }
43
52
  async onModuleInit() {
44
53
  try {
45
- this.logger.debug('Initializing Temporal worker manager...');
54
+ this.logger.verbose('Initializing Temporal worker manager...');
46
55
  if (this.options.workers && this.options.workers.length > 0) {
47
56
  await this.initializeMultipleWorkers();
48
57
  return;
49
58
  }
50
59
  if (!this.shouldInitializeWorker()) {
51
- this.logger.info('Worker initialization skipped - no worker configuration provided');
60
+ this.logger.info('Worker initialization skipped - no configuration provided');
52
61
  return;
53
62
  }
54
63
  const initResult = await this.initializeWorker();
@@ -60,7 +69,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
60
69
  this.lastError = initResult.error?.message || 'Unknown initialization error';
61
70
  this.logger.error('Failed to initialize worker manager', initResult.error);
62
71
  if (this.options.allowConnectionFailure === true) {
63
- this.logger.warn('Worker initialization failed but connection failures are allowed');
72
+ this.logger.warn('Continuing without worker (connection failures allowed)');
64
73
  return;
65
74
  }
66
75
  throw initResult.error || new Error('Worker initialization failed');
@@ -70,7 +79,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
70
79
  this.lastError = this.extractErrorMessage(error);
71
80
  this.logger.error('Failed to initialize worker manager', error);
72
81
  if (this.options.allowConnectionFailure === true) {
73
- this.logger.warn('Worker initialization failed but connection failures are allowed');
82
+ this.logger.warn('Continuing without worker (connection failures allowed)');
74
83
  return;
75
84
  }
76
85
  throw error;
@@ -153,7 +162,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
153
162
  this.logger.info(`Successfully initialized ${this.workers.size} workers`);
154
163
  }
155
164
  async createWorkerFromDefinition(workerDef) {
156
- this.logger.debug(`Creating worker for task queue: ${workerDef.taskQueue}`);
165
+ this.logger.verbose(`Creating worker for task queue '${workerDef.taskQueue}'`);
157
166
  if (this.workers.has(workerDef.taskQueue)) {
158
167
  throw new Error(`Worker for task queue '${workerDef.taskQueue}' already exists`);
159
168
  }
@@ -194,10 +203,10 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
194
203
  startedAt: null,
195
204
  restartCount: 0,
196
205
  activities,
197
- workflowSource: this.getWorkflowSourceFromDef(workerDef),
206
+ workflowSource: this.getWorkflowSource(workerDef),
198
207
  };
199
208
  this.workers.set(workerDef.taskQueue, workerInstance);
200
- this.logger.info(`Worker created for task queue '${workerDef.taskQueue}' with ${activities.size} activities`);
209
+ this.logger.info(`Created worker '${workerDef.taskQueue}' (${activities.size} activities)`);
201
210
  return workerInstance;
202
211
  }
203
212
  async registerWorker(workerDef) {
@@ -219,7 +228,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
219
228
  };
220
229
  }
221
230
  catch (error) {
222
- this.logger.error(`Failed to create worker for '${workerDef.taskQueue}'`, error);
231
+ this.logger.error(`Failed to register worker '${workerDef.taskQueue}'`, error);
223
232
  return {
224
233
  success: false,
225
234
  taskQueue: workerDef.taskQueue,
@@ -257,21 +266,18 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
257
266
  return;
258
267
  }
259
268
  try {
260
- this.logger.info(`Starting worker for task queue '${taskQueue}'...`);
269
+ this.logger.verbose(`Starting worker '${taskQueue}'...`);
261
270
  workerInstance.isRunning = true;
262
271
  workerInstance.startedAt = new Date();
263
272
  workerInstance.lastError = null;
264
- workerInstance.worker.run().catch((error) => {
265
- workerInstance.lastError = this.extractErrorMessage(error);
266
- workerInstance.isRunning = false;
267
- this.logger.error(`Worker '${taskQueue}' failed`, error);
268
- });
269
- this.logger.info(`Worker for '${taskQueue}' started successfully`);
273
+ workerInstance.restartCount = 0;
274
+ this.runWorkerWithAutoRestartByTaskQueue(taskQueue);
275
+ this.logger.info(`Worker '${taskQueue}' started (${workerInstance.activities.size} activities, ${workerInstance.workflowSource})`);
270
276
  }
271
277
  catch (error) {
272
278
  workerInstance.lastError = this.extractErrorMessage(error);
273
279
  workerInstance.isRunning = false;
274
- this.logger.error(`Failed to start worker for '${taskQueue}'`, error);
280
+ this.logger.error(`Failed to start worker '${taskQueue}'`, error);
275
281
  throw error;
276
282
  }
277
283
  }
@@ -281,49 +287,91 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
281
287
  throw new Error(`Worker for task queue '${taskQueue}' not found`);
282
288
  }
283
289
  if (!workerInstance.isRunning) {
284
- this.logger.debug(`Worker for '${taskQueue}' is not running`);
290
+ this.logger.verbose(`Worker '${taskQueue}' is not running`);
285
291
  return;
286
292
  }
287
293
  try {
288
- this.logger.info(`Stopping worker for '${taskQueue}'...`);
289
- try {
290
- const workerState = workerInstance.worker.getState();
291
- this.logger.debug(`Worker '${taskQueue}' current state: ${workerState}`);
292
- if (workerState === 'INITIALIZED' ||
293
- workerState === 'RUNNING' ||
294
- workerState === 'FAILED') {
295
- await workerInstance.worker.shutdown();
296
- this.logger.info(`Worker for '${taskQueue}' stopped successfully`);
297
- }
298
- else if (workerState === 'STOPPING' ||
299
- workerState === 'DRAINING' ||
300
- workerState === 'DRAINED') {
301
- this.logger.info(`Worker for '${taskQueue}' is already shutting down (state: ${workerState})`);
302
- }
303
- else if (workerState === 'STOPPED') {
304
- this.logger.debug(`Worker for '${taskQueue}' is already stopped`);
305
- }
306
- }
307
- catch (shutdownError) {
308
- const errorMessage = shutdownError instanceof Error ? shutdownError.message : String(shutdownError);
309
- if (errorMessage.includes('Not running') ||
310
- errorMessage.includes('DRAINING') ||
311
- errorMessage.includes('STOPPING')) {
312
- this.logger.debug(`Worker '${taskQueue}' is already shutting down or stopped`);
313
- }
314
- else {
315
- throw shutdownError;
316
- }
317
- }
294
+ this.logger.verbose(`Stopping worker '${taskQueue}'...`);
295
+ this.safeShutdownWorker(workerInstance.worker, taskQueue, workerInstance.startedAt);
318
296
  workerInstance.isRunning = false;
319
297
  workerInstance.startedAt = null;
320
298
  }
321
299
  catch (error) {
322
300
  workerInstance.lastError = this.extractErrorMessage(error);
323
- this.logger.warn(`Error while stopping worker for '${taskQueue}'`, error);
301
+ this.logger.warn(`Error stopping worker '${taskQueue}'`, error);
302
+ workerInstance.isRunning = false;
303
+ }
304
+ }
305
+ runWorkerWithAutoRestartByTaskQueue(taskQueue) {
306
+ const workerInstance = this.workers.get(taskQueue);
307
+ if (!workerInstance)
308
+ return;
309
+ const workerDef = this.options.workers?.find((w) => w.taskQueue === taskQueue);
310
+ const maxRestarts = workerDef?.maxRestarts ?? this.options.maxRestarts ?? 3;
311
+ workerInstance.worker.run().catch((error) => {
312
+ workerInstance.lastError = this.extractErrorMessage(error);
324
313
  workerInstance.isRunning = false;
314
+ const autoRestartEnabled = workerDef?.autoRestart ?? this.options.autoRestart;
315
+ if (autoRestartEnabled !== false && workerInstance.restartCount < maxRestarts) {
316
+ workerInstance.restartCount++;
317
+ this.logger.warn(`Worker '${taskQueue}' failed, auto-restarting in 1s (attempt ${workerInstance.restartCount}/${maxRestarts})`, error);
318
+ setTimeout(() => {
319
+ this.autoRestartWorkerByTaskQueue(taskQueue).catch((restartError) => {
320
+ this.logger.error(`Auto-restart failed for '${taskQueue}'`, restartError);
321
+ });
322
+ }, 1000);
323
+ }
324
+ else if (workerInstance.restartCount >= maxRestarts) {
325
+ this.logger.error(`Worker '${taskQueue}' failed after ${maxRestarts} restart attempts, giving up`, error);
326
+ }
327
+ else {
328
+ this.logger.error(`Worker '${taskQueue}' run failed`, error);
329
+ }
330
+ });
331
+ }
332
+ async autoRestartWorkerByTaskQueue(taskQueue) {
333
+ this.logger.info(`Auto-restarting worker '${taskQueue}'...`);
334
+ try {
335
+ const workerDef = this.options.workers?.find((w) => w.taskQueue === taskQueue);
336
+ if (!workerDef) {
337
+ throw new Error(`Worker definition for '${taskQueue}' not found`);
338
+ }
339
+ const oldInstance = this.workers.get(taskQueue);
340
+ const restartCount = oldInstance?.restartCount ?? 0;
341
+ await this.cleanupWorkerForRestartByTaskQueue(taskQueue);
342
+ await new Promise((resolve) => setTimeout(resolve, 500));
343
+ this.workers.delete(taskQueue);
344
+ const newInstance = await this.createWorkerFromDefinition(workerDef);
345
+ newInstance.restartCount = restartCount;
346
+ newInstance.isRunning = true;
347
+ newInstance.startedAt = new Date();
348
+ newInstance.lastError = null;
349
+ this.runWorkerWithAutoRestartByTaskQueue(taskQueue);
350
+ this.logger.info(`Worker '${taskQueue}' auto-restarted successfully`);
351
+ }
352
+ catch (error) {
353
+ const workerInstance = this.workers.get(taskQueue);
354
+ if (workerInstance) {
355
+ workerInstance.lastError = this.extractErrorMessage(error);
356
+ workerInstance.isRunning = false;
357
+ }
358
+ this.logger.error(`Auto-restart failed for '${taskQueue}'`, error);
359
+ throw error;
325
360
  }
326
361
  }
362
+ async cleanupWorkerForRestartByTaskQueue(taskQueue) {
363
+ const workerInstance = this.workers.get(taskQueue);
364
+ if (!workerInstance?.worker)
365
+ return;
366
+ try {
367
+ this.safeShutdownWorker(workerInstance.worker, taskQueue);
368
+ }
369
+ catch (error) {
370
+ this.logger.warn(`Error during worker '${taskQueue}' cleanup (continuing with restart)`, error);
371
+ }
372
+ workerInstance.isRunning = false;
373
+ workerInstance.startedAt = null;
374
+ }
327
375
  getConnection() {
328
376
  return this.connection;
329
377
  }
@@ -331,12 +379,11 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
331
379
  const uptime = workerInstance.startedAt
332
380
  ? Date.now() - workerInstance.startedAt.getTime()
333
381
  : undefined;
382
+ const isHealthy = this.calculateWorkerHealth(workerInstance);
334
383
  return {
335
384
  isInitialized: workerInstance.isInitialized,
336
385
  isRunning: workerInstance.isRunning,
337
- isHealthy: workerInstance.isInitialized &&
338
- !workerInstance.lastError &&
339
- workerInstance.isRunning,
386
+ isHealthy,
340
387
  taskQueue: workerInstance.taskQueue,
341
388
  namespace: workerInstance.namespace,
342
389
  workflowSource: workerInstance.workflowSource,
@@ -347,16 +394,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
347
394
  };
348
395
  }
349
396
  async loadActivitiesForWorker(activities, activityClasses) {
350
- let attempts = 0;
351
- const maxAttempts = 30;
352
- while (attempts < maxAttempts) {
353
- const healthStatus = this.discoveryService.getHealthStatus();
354
- if (healthStatus.isComplete) {
355
- break;
356
- }
357
- await new Promise((resolve) => setTimeout(resolve, 100));
358
- attempts++;
359
- }
397
+ await this.waitForDiscoveryCompletion();
360
398
  if (!activityClasses || activityClasses.length === 0) {
361
399
  const allActivities = this.discoveryService.getAllActivities();
362
400
  for (const [activityName, handler] of Object.entries(allActivities)) {
@@ -381,13 +419,6 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
381
419
  }
382
420
  }
383
421
  }
384
- getWorkflowSourceFromDef(workerDef) {
385
- if (workerDef.workflowBundle)
386
- return 'bundle';
387
- if (workerDef.workflowsPath)
388
- return 'filesystem';
389
- return 'none';
390
- }
391
422
  async startWorker() {
392
423
  if (!this.worker) {
393
424
  throw new Error('Worker not initialized. Cannot start worker.');
@@ -421,12 +452,10 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
421
452
  try {
422
453
  this.worker.run().catch((error) => {
423
454
  this.lastError = this.extractErrorMessage(error);
424
- this.logger.error('Worker run failed', error);
425
455
  this.isRunning = false;
426
- if (this.options.autoRestart !== false &&
427
- this.restartCount < this.maxRestarts) {
456
+ if (this.autoRestartEnabled && this.restartCount < this.maxRestarts) {
428
457
  this.restartCount++;
429
- this.logger.info(`Auto-restart enabled, attempting to restart worker (attempt ${this.restartCount}/${this.maxRestarts}) in 1 second...`);
458
+ this.logger.warn(`Worker failed, auto-restarting in 1s (attempt ${this.restartCount}/${this.maxRestarts})`, error);
430
459
  setTimeout(async () => {
431
460
  try {
432
461
  await this.autoRestartWorker();
@@ -437,7 +466,10 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
437
466
  }, 1000);
438
467
  }
439
468
  else if (this.restartCount >= this.maxRestarts) {
440
- this.logger.error(`Max restart attempts (${this.maxRestarts}) exceeded. Stopping auto-restart.`);
469
+ this.logger.error(`Worker failed after ${this.maxRestarts} restart attempts, giving up`, error);
470
+ }
471
+ else {
472
+ this.logger.error('Worker run failed', error);
441
473
  }
442
474
  });
443
475
  setTimeout(() => resolve(), 500);
@@ -455,14 +487,17 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
455
487
  async autoRestartWorker() {
456
488
  this.logger.info('Auto-restarting Temporal worker...');
457
489
  try {
458
- if (this.worker) {
459
- await this.worker.shutdown();
460
- }
490
+ await this.cleanupWorkerForRestart();
461
491
  await new Promise((resolve) => setTimeout(resolve, 500));
492
+ const initResult = await this.initializeWorker();
493
+ if (!initResult.success) {
494
+ throw initResult.error || new Error('Failed to reinitialize worker');
495
+ }
496
+ this.isInitialized = true;
462
497
  this.isRunning = true;
463
498
  this.startedAt = new Date();
464
499
  this.lastError = null;
465
- this.runWorkerWithAutoRestart();
500
+ await this.runWorkerWithAutoRestart();
466
501
  this.logger.info('Temporal worker auto-restarted successfully');
467
502
  }
468
503
  catch (error) {
@@ -472,29 +507,29 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
472
507
  throw error;
473
508
  }
474
509
  }
510
+ async cleanupWorkerForRestart() {
511
+ if (!this.worker) {
512
+ return;
513
+ }
514
+ try {
515
+ this.safeShutdownWorker(this.worker, 'legacy');
516
+ }
517
+ catch (error) {
518
+ this.logger.warn('Error during worker cleanup (continuing with restart)', error);
519
+ }
520
+ this.worker = null;
521
+ this.isRunning = false;
522
+ this.startedAt = null;
523
+ }
475
524
  async stopWorker() {
476
525
  if (!this.worker || !this.isRunning) {
477
526
  this.logger.debug('Worker is not running or not initialized');
478
527
  return;
479
528
  }
480
529
  try {
481
- this.logger.info('Stopping Temporal worker...');
482
- const workerState = this.worker.getState();
483
- this.logger.debug(`Worker current state: ${workerState}`);
484
- if (workerState === 'INITIALIZED' ||
485
- workerState === 'RUNNING' ||
486
- workerState === 'FAILED') {
487
- await this.worker.shutdown();
488
- this.logger.info('Temporal worker stopped successfully');
489
- }
490
- else if (workerState === 'STOPPING' ||
491
- workerState === 'DRAINING' ||
492
- workerState === 'DRAINED') {
493
- this.logger.info(`Worker is already shutting down (state: ${workerState})`);
494
- }
495
- else if (workerState === 'STOPPED') {
496
- this.logger.debug('Worker is already stopped');
497
- }
530
+ this.logger.verbose('Stopping Temporal worker...');
531
+ const taskQueue = this.options.taskQueue || 'default';
532
+ this.safeShutdownWorker(this.worker, taskQueue, this.startedAt);
498
533
  this.isRunning = false;
499
534
  this.startedAt = null;
500
535
  }
@@ -532,10 +567,11 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
532
567
  }
533
568
  getWorkerStatus() {
534
569
  const uptime = this.startedAt ? Date.now() - this.startedAt.getTime() : undefined;
570
+ const isHealthy = this.calculateWorkerHealth();
535
571
  return {
536
572
  isInitialized: this.isInitialized,
537
573
  isRunning: this.isRunning,
538
- isHealthy: this.isInitialized && !this.lastError && this.isRunning,
574
+ isHealthy,
539
575
  taskQueue: this.options.taskQueue || 'default',
540
576
  namespace: this.options.connection?.namespace || 'default',
541
577
  workflowSource: this.getWorkflowSource(),
@@ -556,27 +592,18 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
556
592
  const errors = [];
557
593
  let registeredCount = 0;
558
594
  try {
559
- let attempts = 0;
560
- const maxAttempts = 30;
561
- while (attempts < maxAttempts) {
562
- const healthStatus = this.discoveryService.getHealthStatus();
563
- if (healthStatus.isComplete) {
564
- break;
565
- }
566
- await new Promise((resolve) => setTimeout(resolve, 100));
567
- attempts++;
568
- }
595
+ await this.waitForDiscoveryCompletion();
569
596
  const allActivities = this.discoveryService.getAllActivities();
570
597
  for (const [activityName, handler] of Object.entries(allActivities)) {
571
598
  try {
572
599
  this.activities.set(activityName, handler);
573
600
  registeredCount++;
574
- this.logger.debug(`Registered activity: ${activityName}`);
601
+ this.logger.verbose(`Registered activity: ${activityName}`);
575
602
  }
576
603
  catch (error) {
577
604
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
578
605
  errors.push({ activityName, error: errorMessage });
579
- this.logger.warn(`Failed to register activity ${activityName}: ${errorMessage}`);
606
+ this.logger.warn(`Failed to register activity '${activityName}': ${errorMessage}`);
580
607
  }
581
608
  }
582
609
  this.logger.info(`Registered ${registeredCount} activities from discovery service`);
@@ -602,13 +629,11 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
602
629
  isWorkerRunning() {
603
630
  return this.isRunning;
604
631
  }
605
- getStatus() {
606
- return this.getWorkerStatus();
607
- }
608
632
  getHealthStatus() {
609
633
  const uptime = this.startedAt ? Date.now() - this.startedAt.getTime() : undefined;
634
+ const isHealthy = this.calculateWorkerHealth();
610
635
  return {
611
- isHealthy: this.isInitialized && !this.lastError && this.isRunning,
636
+ isHealthy,
612
637
  isRunning: this.isRunning,
613
638
  isInitialized: this.isInitialized,
614
639
  lastError: this.lastError || undefined,
@@ -645,30 +670,6 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
645
670
  throw new Error('Cannot specify both workflowsPath and workflowBundle');
646
671
  }
647
672
  }
648
- getEnvironmentDefaults() {
649
- return {
650
- taskQueue: this.options.taskQueue || 'default',
651
- namespace: this.options.connection?.namespace || 'default',
652
- };
653
- }
654
- buildWorkerOptions() {
655
- const baseOptions = this.getEnvironmentDefaults();
656
- if (this.options.worker?.workflowsPath) {
657
- Object.assign(baseOptions, { workflowsPath: this.options.worker.workflowsPath });
658
- }
659
- else if (this.options.worker?.workflowBundle) {
660
- Object.assign(baseOptions, { workflowBundle: this.options.worker.workflowBundle });
661
- }
662
- const activitiesObj = {};
663
- for (const [name, func] of this.activities.entries()) {
664
- activitiesObj[name] = func;
665
- }
666
- Object.assign(baseOptions, { activities: activitiesObj });
667
- if (this.options.worker?.workerOptions) {
668
- Object.assign(baseOptions, this.options.worker.workerOptions);
669
- }
670
- return baseOptions;
671
- }
672
673
  async createConnection() {
673
674
  if (this.injectedConnection) {
674
675
  this.connection = this.injectedConnection;
@@ -690,51 +691,21 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
690
691
  authorization: `Bearer ${this.options.connection.apiKey}`,
691
692
  };
692
693
  }
693
- this.logger.debug(`Creating NativeConnection to ${address}`);
694
+ this.logger.verbose(`Connecting to Temporal server at ${address}...`);
694
695
  this.connection = await worker_1.NativeConnection.connect(connectOptions);
695
- this.logger.info(`Connection established to ${address}`);
696
+ const ns = this.options.connection?.namespace || 'default';
697
+ this.logger.info(`Connected to ${address} (namespace: ${ns})`);
696
698
  }
697
699
  catch (error) {
698
700
  this.logger.error('Failed to create connection', error);
699
701
  if (this.options.allowConnectionFailure !== false) {
700
- this.logger.warn('Worker connection failed - continuing without worker functionality');
702
+ this.logger.warn('Connection failed, continuing without worker');
701
703
  this.connection = null;
702
704
  return;
703
705
  }
704
706
  throw error;
705
707
  }
706
708
  }
707
- async createWorker() {
708
- await this.createConnection();
709
- if (!this.connection) {
710
- throw new Error('Connection not established');
711
- }
712
- const workerConfig = await this.createWorkerConfig();
713
- const { Worker } = await Promise.resolve().then(() => require('@temporalio/worker'));
714
- this.worker = await Worker.create(workerConfig);
715
- }
716
- logWorkerConfiguration() {
717
- this.logger.debug(`Worker configuration: ${JSON.stringify(this.options.worker)}`);
718
- }
719
- async runWorkerLoop() {
720
- if (!this.worker) {
721
- throw new Error('Temporal worker not initialized');
722
- }
723
- try {
724
- await this.worker.run();
725
- }
726
- catch (error) {
727
- this.logger.error('Worker execution failed', error);
728
- throw new Error('Execution error');
729
- }
730
- }
731
- startWorkerInBackground() {
732
- if (this.worker && !this.isRunning) {
733
- this.startWorker().catch((error) => {
734
- this.logger.error('Background worker start failed', error);
735
- });
736
- }
737
- }
738
709
  shouldInitializeWorker() {
739
710
  return Boolean(this.options.worker &&
740
711
  (this.options.worker.workflowsPath ||
@@ -768,7 +739,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
768
739
  const workerConfig = await this.createWorkerConfig();
769
740
  const { Worker } = await Promise.resolve().then(() => require('@temporalio/worker'));
770
741
  this.worker = await Worker.create(workerConfig);
771
- this.logger.debug(`Worker created - TaskQueue: ${workerConfig.taskQueue}, Activities: ${this.activities.size}, Source: ${this.getWorkflowSource()}`);
742
+ this.logger.verbose(`Worker created: queue='${workerConfig.taskQueue}', activities=${this.activities.size}, workflows=${this.getWorkflowSource()}`);
772
743
  return {
773
744
  success: true,
774
745
  worker: this.worker,
@@ -795,31 +766,23 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
795
766
  let discoveredActivities = 0;
796
767
  let loadedActivities = 0;
797
768
  try {
798
- let attempts = 0;
799
- const maxAttempts = 30;
800
- while (attempts < maxAttempts) {
801
- const healthStatus = this.discoveryService.getHealthStatus();
802
- if (healthStatus.isComplete) {
803
- break;
804
- }
805
- await new Promise((resolve) => setTimeout(resolve, 100));
806
- attempts++;
807
- }
769
+ await this.waitForDiscoveryCompletion();
808
770
  const allActivities = this.discoveryService.getAllActivities();
809
771
  discoveredActivities = Object.keys(allActivities).length;
810
772
  for (const [activityName, handler] of Object.entries(allActivities)) {
811
773
  try {
812
774
  this.activities.set(activityName, handler);
813
775
  loadedActivities++;
814
- this.logger.debug(`Loaded activity: ${activityName}`);
776
+ this.logger.verbose(`Loaded activity: ${activityName}`);
815
777
  }
816
778
  catch (error) {
817
779
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
818
- errors.push({ component: activityName, error: errorMessage });
819
- this.logger.warn(`Failed to load activity ${activityName}: ${errorMessage}`);
780
+ errors.push({ name: activityName, error: errorMessage });
781
+ this.logger.warn(`Failed to load activity '${activityName}': ${errorMessage}`);
820
782
  }
821
783
  }
822
- this.logger.info(`Loaded ${loadedActivities} activities from discovery service`);
784
+ const duration = Date.now() - startTime;
785
+ this.logger.info(`Loaded ${loadedActivities} ${loadedActivities === 1 ? 'activity' : 'activities'} from discovery in ${duration}ms`);
823
786
  return {
824
787
  success: errors.length === 0,
825
788
  discoveredActivities,
@@ -835,7 +798,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
835
798
  success: false,
836
799
  discoveredActivities,
837
800
  loadedActivities,
838
- errors: [{ component: 'discovery', error: errorMessage }],
801
+ errors: [{ name: 'discovery', error: errorMessage }],
839
802
  duration: Date.now() - startTime,
840
803
  };
841
804
  }
@@ -854,14 +817,14 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
854
817
  };
855
818
  if (this.options.worker?.workflowsPath) {
856
819
  config.workflowsPath = this.options.worker.workflowsPath;
857
- this.logger.debug(`Using workflows from path: ${this.options.worker.workflowsPath}`);
820
+ this.logger.verbose(`Using workflows from: ${this.options.worker.workflowsPath}`);
858
821
  }
859
822
  else if (this.options.worker?.workflowBundle) {
860
823
  config.workflowBundle = this.options.worker.workflowBundle;
861
- this.logger.debug('Using workflow bundle');
824
+ this.logger.verbose('Using workflow bundle');
862
825
  }
863
826
  else {
864
- this.logger.warn('No workflow configuration provided - worker will only handle activities');
827
+ this.logger.warn('No workflow configuration - worker will only handle activities');
865
828
  }
866
829
  if (this.options.worker?.workerOptions) {
867
830
  Object.assign(config, this.options.worker.workerOptions);
@@ -886,38 +849,7 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
886
849
  try {
887
850
  if (workerInstance.isRunning && workerInstance.worker) {
888
851
  this.logger.debug(`Stopping worker for '${taskQueue}'...`);
889
- try {
890
- const workerState = workerInstance.worker.getState();
891
- if (workerState === 'INITIALIZED' ||
892
- workerState === 'RUNNING' ||
893
- workerState === 'FAILED') {
894
- await workerInstance.worker.shutdown();
895
- this.logger.debug(`Worker '${taskQueue}' shut down successfully`);
896
- }
897
- else if (workerState === 'STOPPING' ||
898
- workerState === 'DRAINING' ||
899
- workerState === 'DRAINED') {
900
- this.logger.debug(`Worker '${taskQueue}' is already shutting down (state: ${workerState})`);
901
- }
902
- else if (workerState === 'STOPPED') {
903
- this.logger.debug(`Worker '${taskQueue}' is already stopped`);
904
- }
905
- }
906
- catch (shutdownError) {
907
- const errorMessage = shutdownError instanceof Error
908
- ? shutdownError.message
909
- : String(shutdownError);
910
- if (errorMessage.includes('Not running') ||
911
- errorMessage.includes('DRAINING') ||
912
- errorMessage.includes('STOPPING')) {
913
- this.logger.debug(`Worker '${taskQueue}' is already shutting down or stopped`);
914
- }
915
- else {
916
- this.logger.warn(`Unexpected error shutting down worker '${taskQueue}': ${errorMessage}`, shutdownError instanceof Error
917
- ? shutdownError.stack
918
- : undefined);
919
- }
920
- }
852
+ this.safeShutdownWorker(workerInstance.worker, taskQueue);
921
853
  workerInstance.isRunning = false;
922
854
  }
923
855
  }
@@ -955,13 +887,95 @@ let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class Tempor
955
887
  this.shutdownPromise = null;
956
888
  }
957
889
  }
958
- getWorkflowSource() {
959
- if (this.options.worker?.workflowBundle)
890
+ getWorkflowSource(config) {
891
+ const source = config ?? this.options.worker;
892
+ if (source?.workflowBundle)
960
893
  return 'bundle';
961
- if (this.options.worker?.workflowsPath)
894
+ if (source?.workflowsPath)
962
895
  return 'filesystem';
963
896
  return 'none';
964
897
  }
898
+ getNativeState() {
899
+ if (!this.worker) {
900
+ return null;
901
+ }
902
+ try {
903
+ return this.worker.getState();
904
+ }
905
+ catch {
906
+ return null;
907
+ }
908
+ }
909
+ calculateWorkerHealth(workerInstance = null) {
910
+ if (workerInstance) {
911
+ let nativeState = null;
912
+ try {
913
+ nativeState = workerInstance.worker?.getState() ?? null;
914
+ }
915
+ catch {
916
+ nativeState = null;
917
+ }
918
+ return (workerInstance.isInitialized &&
919
+ !workerInstance.lastError &&
920
+ workerInstance.isRunning &&
921
+ nativeState === 'RUNNING');
922
+ }
923
+ const nativeState = this.getNativeState();
924
+ return this.isInitialized && !this.lastError && this.isRunning && nativeState === 'RUNNING';
925
+ }
926
+ async waitForDiscoveryCompletion(maxWaitMs = 3000) {
927
+ const pollInterval = 100;
928
+ const maxAttempts = Math.ceil(maxWaitMs / pollInterval);
929
+ let attempts = 0;
930
+ while (attempts < maxAttempts) {
931
+ const healthStatus = this.discoveryService.getHealthStatus();
932
+ if (healthStatus.isComplete) {
933
+ return true;
934
+ }
935
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
936
+ attempts++;
937
+ }
938
+ return false;
939
+ }
940
+ safeShutdownWorker(worker, identifier, startedAt) {
941
+ try {
942
+ const workerState = worker.getState();
943
+ if (workerState === 'INITIALIZED' ||
944
+ workerState === 'RUNNING' ||
945
+ workerState === 'FAILED') {
946
+ worker.shutdown();
947
+ if (startedAt) {
948
+ const uptime = Math.round((Date.now() - startedAt.getTime()) / 1000);
949
+ this.logger.info(`Worker '${identifier}' stopped (uptime: ${uptime}s)`);
950
+ }
951
+ else {
952
+ this.logger.verbose(`Worker '${identifier}' shut down`);
953
+ }
954
+ return true;
955
+ }
956
+ if (workerState === 'STOPPING' ||
957
+ workerState === 'DRAINING' ||
958
+ workerState === 'DRAINED') {
959
+ this.logger.verbose(`Worker '${identifier}' already shutting down (${workerState})`);
960
+ return false;
961
+ }
962
+ if (workerState === 'STOPPED') {
963
+ this.logger.verbose(`Worker '${identifier}' already stopped`);
964
+ return false;
965
+ }
966
+ return false;
967
+ }
968
+ catch (error) {
969
+ const msg = error instanceof Error ? error.message : String(error);
970
+ if (msg.includes('Not running') ||
971
+ msg.includes('DRAINING') ||
972
+ msg.includes('STOPPING')) {
973
+ this.logger.verbose(`Worker '${identifier}' already shutting down`);
974
+ return false;
975
+ }
976
+ throw error;
977
+ }
978
+ }
965
979
  extractErrorMessage(error) {
966
980
  if (error instanceof Error) {
967
981
  return error.message;