nestjs-temporal-core 3.0.10 → 3.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/README.md +1755 -693
- package/dist/constants.d.ts +49 -151
- package/dist/constants.js +38 -141
- package/dist/constants.js.map +1 -1
- package/dist/decorators/activity.decorator.js +75 -15
- package/dist/decorators/activity.decorator.js.map +1 -1
- package/dist/decorators/index.d.ts +1 -3
- package/dist/decorators/index.js +4 -13
- package/dist/decorators/index.js.map +1 -1
- package/dist/decorators/workflow.decorator.d.ts +7 -3
- package/dist/decorators/workflow.decorator.js +161 -48
- package/dist/decorators/workflow.decorator.js.map +1 -1
- package/dist/health/temporal-health.controller.d.ts +7 -0
- package/dist/health/temporal-health.controller.js +77 -0
- package/dist/health/temporal-health.controller.js.map +1 -0
- package/dist/health/temporal-health.module.d.ts +2 -0
- package/dist/health/temporal-health.module.js +20 -0
- package/dist/health/temporal-health.module.js.map +1 -0
- package/dist/index.d.ts +10 -20
- package/dist/index.js +15 -30
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +773 -160
- package/dist/interfaces.js +1 -2
- package/dist/interfaces.js.map +1 -1
- package/dist/providers/temporal-connection.factory.d.ts +28 -0
- package/dist/providers/temporal-connection.factory.js +194 -0
- package/dist/providers/temporal-connection.factory.js.map +1 -0
- package/dist/services/temporal-client.service.d.ts +33 -0
- package/dist/services/temporal-client.service.js +285 -0
- package/dist/services/temporal-client.service.js.map +1 -0
- package/dist/services/temporal-discovery.service.d.ts +34 -0
- package/dist/services/temporal-discovery.service.js +348 -0
- package/dist/services/temporal-discovery.service.js.map +1 -0
- package/dist/services/temporal-metadata.service.d.ts +37 -0
- package/dist/services/temporal-metadata.service.js +512 -0
- package/dist/services/temporal-metadata.service.js.map +1 -0
- package/dist/services/temporal-schedule.service.d.ts +35 -0
- package/dist/services/temporal-schedule.service.js +380 -0
- package/dist/services/temporal-schedule.service.js.map +1 -0
- package/dist/services/temporal-worker.service.d.ts +67 -0
- package/dist/services/temporal-worker.service.js +845 -0
- package/dist/services/temporal-worker.service.js.map +1 -0
- package/dist/services/temporal.service.d.ts +92 -0
- package/dist/services/temporal.service.js +621 -0
- package/dist/services/temporal.service.js.map +1 -0
- package/dist/temporal.module.d.ts +6 -9
- package/dist/temporal.module.js +160 -109
- package/dist/temporal.module.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +5 -8
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logger.d.ts +10 -4
- package/dist/utils/logger.js +77 -106
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/metadata.d.ts +1 -3
- package/dist/utils/metadata.js +8 -18
- package/dist/utils/metadata.js.map +1 -1
- package/dist/utils/validation.d.ts +16 -2
- package/dist/utils/validation.js +103 -9
- package/dist/utils/validation.js.map +1 -1
- package/package.json +37 -26
- package/dist/activity/index.d.ts +0 -2
- package/dist/activity/index.js +0 -19
- package/dist/activity/index.js.map +0 -1
- package/dist/activity/temporal-activity.module.d.ts +0 -11
- package/dist/activity/temporal-activity.module.js +0 -52
- package/dist/activity/temporal-activity.module.js.map +0 -1
- package/dist/activity/temporal-activity.service.d.ts +0 -46
- package/dist/activity/temporal-activity.service.js +0 -192
- package/dist/activity/temporal-activity.service.js.map +0 -1
- package/dist/client/index.d.ts +0 -3
- package/dist/client/index.js +0 -20
- package/dist/client/index.js.map +0 -1
- package/dist/client/temporal-client.module.d.ts +0 -18
- package/dist/client/temporal-client.module.js +0 -198
- package/dist/client/temporal-client.module.js.map +0 -1
- package/dist/client/temporal-client.service.d.ts +0 -35
- package/dist/client/temporal-client.service.js +0 -187
- package/dist/client/temporal-client.service.js.map +0 -1
- package/dist/client/temporal-schedule.service.d.ts +0 -41
- package/dist/client/temporal-schedule.service.js +0 -204
- package/dist/client/temporal-schedule.service.js.map +0 -1
- package/dist/decorators/parameter.decorator.d.ts +0 -5
- package/dist/decorators/parameter.decorator.js +0 -57
- package/dist/decorators/parameter.decorator.js.map +0 -1
- package/dist/decorators/scheduling.decorator.d.ts +0 -4
- package/dist/decorators/scheduling.decorator.js +0 -44
- package/dist/decorators/scheduling.decorator.js.map +0 -1
- package/dist/discovery/index.d.ts +0 -2
- package/dist/discovery/index.js +0 -19
- package/dist/discovery/index.js.map +0 -1
- package/dist/discovery/temporal-discovery.service.d.ts +0 -39
- package/dist/discovery/temporal-discovery.service.js +0 -191
- package/dist/discovery/temporal-discovery.service.js.map +0 -1
- package/dist/discovery/temporal-schedule-manager.service.d.ts +0 -41
- package/dist/discovery/temporal-schedule-manager.service.js +0 -238
- package/dist/discovery/temporal-schedule-manager.service.js.map +0 -1
- package/dist/schedules/index.d.ts +0 -2
- package/dist/schedules/index.js +0 -19
- package/dist/schedules/index.js.map +0 -1
- package/dist/schedules/temporal-schedules.module.d.ts +0 -11
- package/dist/schedules/temporal-schedules.module.js +0 -55
- package/dist/schedules/temporal-schedules.module.js.map +0 -1
- package/dist/schedules/temporal-schedules.service.d.ts +0 -52
- package/dist/schedules/temporal-schedules.service.js +0 -221
- package/dist/schedules/temporal-schedules.service.js.map +0 -1
- package/dist/temporal.service.d.ts +0 -77
- package/dist/temporal.service.js +0 -243
- package/dist/temporal.service.js.map +0 -1
- package/dist/worker/index.d.ts +0 -3
- package/dist/worker/index.js +0 -20
- package/dist/worker/index.js.map +0 -1
- package/dist/worker/temporal-metadata.accessor.d.ts +0 -32
- package/dist/worker/temporal-metadata.accessor.js +0 -208
- package/dist/worker/temporal-metadata.accessor.js.map +0 -1
- package/dist/worker/temporal-worker-manager.service.d.ts +0 -49
- package/dist/worker/temporal-worker-manager.service.js +0 -389
- package/dist/worker/temporal-worker-manager.service.js.map +0 -1
- package/dist/worker/temporal-worker.module.d.ts +0 -18
- package/dist/worker/temporal-worker.module.js +0 -156
- package/dist/worker/temporal-worker.module.js.map +0 -1
|
@@ -0,0 +1,845 @@
|
|
|
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
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var TemporalWorkerManagerService_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.TemporalWorkerManagerService = void 0;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const worker_1 = require("@temporalio/worker");
|
|
19
|
+
const constants_1 = require("../constants");
|
|
20
|
+
const temporal_discovery_service_1 = require("./temporal-discovery.service");
|
|
21
|
+
const logger_1 = require("../utils/logger");
|
|
22
|
+
let TemporalWorkerManagerService = TemporalWorkerManagerService_1 = class TemporalWorkerManagerService {
|
|
23
|
+
constructor(discoveryService, options, injectedConnection) {
|
|
24
|
+
this.discoveryService = discoveryService;
|
|
25
|
+
this.options = options;
|
|
26
|
+
this.injectedConnection = injectedConnection;
|
|
27
|
+
this.worker = null;
|
|
28
|
+
this.restartCount = 0;
|
|
29
|
+
this.maxRestarts = 3;
|
|
30
|
+
this.isInitialized = false;
|
|
31
|
+
this.isRunning = false;
|
|
32
|
+
this.lastError = null;
|
|
33
|
+
this.startedAt = null;
|
|
34
|
+
this.activities = new Map();
|
|
35
|
+
this.workers = new Map();
|
|
36
|
+
this.connection = null;
|
|
37
|
+
this.shutdownPromise = null;
|
|
38
|
+
this.logger = (0, logger_1.createLogger)(TemporalWorkerManagerService_1.name, {
|
|
39
|
+
enableLogger: options.enableLogger,
|
|
40
|
+
logLevel: options.logLevel,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async onModuleInit() {
|
|
44
|
+
try {
|
|
45
|
+
this.logger.debug('Initializing Temporal worker manager...');
|
|
46
|
+
if (this.options.workers && this.options.workers.length > 0) {
|
|
47
|
+
await this.initializeMultipleWorkers();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!this.shouldInitializeWorker()) {
|
|
51
|
+
this.logger.info('Worker initialization skipped - no worker configuration provided');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const initResult = await this.initializeWorker();
|
|
55
|
+
this.isInitialized = initResult.success;
|
|
56
|
+
if (initResult.success) {
|
|
57
|
+
this.logger.info('Temporal worker manager initialized successfully');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.lastError = initResult.error?.message || 'Unknown initialization error';
|
|
61
|
+
this.logger.error('Failed to initialize worker manager', initResult.error);
|
|
62
|
+
if (this.options.allowConnectionFailure === true) {
|
|
63
|
+
this.logger.warn('Worker initialization failed but connection failures are allowed');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
throw initResult.error || new Error('Worker initialization failed');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
this.lastError = this.extractErrorMessage(error);
|
|
71
|
+
this.logger.error('Failed to initialize worker manager', error);
|
|
72
|
+
if (this.options.allowConnectionFailure === true) {
|
|
73
|
+
this.logger.warn('Worker initialization failed but connection failures are allowed');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async onApplicationBootstrap() {
|
|
80
|
+
if (this.options.workers && this.options.workers.length > 0) {
|
|
81
|
+
for (const [taskQueue] of this.workers.entries()) {
|
|
82
|
+
const workerDef = this.options.workers.find((w) => w.taskQueue === taskQueue);
|
|
83
|
+
if (workerDef?.autoStart !== false) {
|
|
84
|
+
await this.startWorkerByTaskQueue(taskQueue);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (this.worker && this.options.worker?.autoStart !== false) {
|
|
90
|
+
await this.startWorker();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async onModuleDestroy() {
|
|
94
|
+
await this.shutdownWorker();
|
|
95
|
+
}
|
|
96
|
+
async initializeMultipleWorkers() {
|
|
97
|
+
this.logger.info(`Initializing ${this.options.workers.length} workers...`);
|
|
98
|
+
await this.createConnection();
|
|
99
|
+
if (!this.connection && this.options.allowConnectionFailure !== false) {
|
|
100
|
+
this.logger.warn('Connection failed, skipping worker initialization');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
for (const workerDef of this.options.workers) {
|
|
104
|
+
try {
|
|
105
|
+
await this.createWorkerFromDefinition(workerDef);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
this.logger.error(`Failed to initialize worker for task queue '${workerDef.taskQueue}'`, error);
|
|
109
|
+
if (this.options.allowConnectionFailure !== true) {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
this.logger.info(`Successfully initialized ${this.workers.size} workers`);
|
|
115
|
+
}
|
|
116
|
+
async createWorkerFromDefinition(workerDef) {
|
|
117
|
+
this.logger.debug(`Creating worker for task queue: ${workerDef.taskQueue}`);
|
|
118
|
+
if (this.workers.has(workerDef.taskQueue)) {
|
|
119
|
+
throw new Error(`Worker for task queue '${workerDef.taskQueue}' already exists`);
|
|
120
|
+
}
|
|
121
|
+
const activities = new Map();
|
|
122
|
+
if (workerDef.activityClasses && workerDef.activityClasses.length > 0) {
|
|
123
|
+
await this.loadActivitiesForWorker(activities);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const allActivities = this.discoveryService.getAllActivities();
|
|
127
|
+
for (const [name, handler] of Object.entries(allActivities)) {
|
|
128
|
+
activities.set(name, handler);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const workerConfig = {
|
|
132
|
+
taskQueue: workerDef.taskQueue,
|
|
133
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
134
|
+
connection: this.connection,
|
|
135
|
+
activities: Object.fromEntries(activities),
|
|
136
|
+
};
|
|
137
|
+
if (workerDef.workflowsPath) {
|
|
138
|
+
workerConfig.workflowsPath = workerDef.workflowsPath;
|
|
139
|
+
}
|
|
140
|
+
else if (workerDef.workflowBundle) {
|
|
141
|
+
workerConfig.workflowBundle = workerDef.workflowBundle;
|
|
142
|
+
}
|
|
143
|
+
if (workerDef.workerOptions) {
|
|
144
|
+
Object.assign(workerConfig, workerDef.workerOptions);
|
|
145
|
+
}
|
|
146
|
+
const { Worker } = await Promise.resolve().then(() => require('@temporalio/worker'));
|
|
147
|
+
const worker = await Worker.create(workerConfig);
|
|
148
|
+
const workerInstance = {
|
|
149
|
+
worker,
|
|
150
|
+
taskQueue: workerDef.taskQueue,
|
|
151
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
152
|
+
isRunning: false,
|
|
153
|
+
isInitialized: true,
|
|
154
|
+
lastError: null,
|
|
155
|
+
startedAt: null,
|
|
156
|
+
restartCount: 0,
|
|
157
|
+
activities,
|
|
158
|
+
workflowSource: this.getWorkflowSourceFromDef(workerDef),
|
|
159
|
+
};
|
|
160
|
+
this.workers.set(workerDef.taskQueue, workerInstance);
|
|
161
|
+
this.logger.info(`Worker created for task queue '${workerDef.taskQueue}' with ${activities.size} activities`);
|
|
162
|
+
return workerInstance;
|
|
163
|
+
}
|
|
164
|
+
async registerWorker(workerDef) {
|
|
165
|
+
try {
|
|
166
|
+
if (!workerDef.taskQueue || workerDef.taskQueue.trim().length === 0) {
|
|
167
|
+
throw new Error('Task queue is required');
|
|
168
|
+
}
|
|
169
|
+
if (!this.connection) {
|
|
170
|
+
await this.createConnection();
|
|
171
|
+
}
|
|
172
|
+
const workerInstance = await this.createWorkerFromDefinition(workerDef);
|
|
173
|
+
if (workerDef.autoStart !== false) {
|
|
174
|
+
await this.startWorkerByTaskQueue(workerDef.taskQueue);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
success: true,
|
|
178
|
+
taskQueue: workerDef.taskQueue,
|
|
179
|
+
worker: workerInstance.worker,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
this.logger.error(`Failed to create worker for '${workerDef.taskQueue}'`, error);
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
taskQueue: workerDef.taskQueue,
|
|
187
|
+
error: error instanceof Error ? error : new Error(this.extractErrorMessage(error)),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
getWorker(taskQueue) {
|
|
192
|
+
const workerInstance = this.workers.get(taskQueue);
|
|
193
|
+
return workerInstance ? workerInstance.worker : null;
|
|
194
|
+
}
|
|
195
|
+
getAllWorkers() {
|
|
196
|
+
const workersStatus = new Map();
|
|
197
|
+
for (const [taskQueue, workerInstance] of this.workers.entries()) {
|
|
198
|
+
workersStatus.set(taskQueue, this.getWorkerStatusFromInstance(workerInstance));
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
workers: workersStatus,
|
|
202
|
+
totalWorkers: this.workers.size,
|
|
203
|
+
runningWorkers: Array.from(this.workers.values()).filter((w) => w.isRunning).length,
|
|
204
|
+
healthyWorkers: Array.from(this.workers.values()).filter((w) => w.isInitialized && !w.lastError && w.isRunning).length,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
getWorkerStatusByTaskQueue(taskQueue) {
|
|
208
|
+
const workerInstance = this.workers.get(taskQueue);
|
|
209
|
+
return workerInstance ? this.getWorkerStatusFromInstance(workerInstance) : null;
|
|
210
|
+
}
|
|
211
|
+
async startWorkerByTaskQueue(taskQueue) {
|
|
212
|
+
const workerInstance = this.workers.get(taskQueue);
|
|
213
|
+
if (!workerInstance) {
|
|
214
|
+
throw new Error(`Worker for task queue '${taskQueue}' not found`);
|
|
215
|
+
}
|
|
216
|
+
if (workerInstance.isRunning) {
|
|
217
|
+
this.logger.warn(`Worker for '${taskQueue}' is already running`);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
this.logger.info(`Starting worker for task queue '${taskQueue}'...`);
|
|
222
|
+
workerInstance.isRunning = true;
|
|
223
|
+
workerInstance.startedAt = new Date();
|
|
224
|
+
workerInstance.lastError = null;
|
|
225
|
+
workerInstance.worker.run().catch((error) => {
|
|
226
|
+
workerInstance.lastError = this.extractErrorMessage(error);
|
|
227
|
+
workerInstance.isRunning = false;
|
|
228
|
+
this.logger.error(`Worker '${taskQueue}' failed`, error);
|
|
229
|
+
});
|
|
230
|
+
this.logger.info(`Worker for '${taskQueue}' started successfully`);
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
workerInstance.lastError = this.extractErrorMessage(error);
|
|
234
|
+
workerInstance.isRunning = false;
|
|
235
|
+
this.logger.error(`Failed to start worker for '${taskQueue}'`, error);
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async stopWorkerByTaskQueue(taskQueue) {
|
|
240
|
+
const workerInstance = this.workers.get(taskQueue);
|
|
241
|
+
if (!workerInstance) {
|
|
242
|
+
throw new Error(`Worker for task queue '${taskQueue}' not found`);
|
|
243
|
+
}
|
|
244
|
+
if (!workerInstance.isRunning) {
|
|
245
|
+
this.logger.debug(`Worker for '${taskQueue}' is not running`);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
this.logger.info(`Stopping worker for task queue '${taskQueue}'...`);
|
|
250
|
+
await workerInstance.worker.shutdown();
|
|
251
|
+
workerInstance.isRunning = false;
|
|
252
|
+
workerInstance.startedAt = null;
|
|
253
|
+
this.logger.info(`Worker for '${taskQueue}' stopped successfully`);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
workerInstance.lastError = this.extractErrorMessage(error);
|
|
257
|
+
this.logger.error(`Failed to stop worker for '${taskQueue}'`, error);
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
getConnection() {
|
|
262
|
+
return this.connection;
|
|
263
|
+
}
|
|
264
|
+
getWorkerStatusFromInstance(workerInstance) {
|
|
265
|
+
const uptime = workerInstance.startedAt
|
|
266
|
+
? Date.now() - workerInstance.startedAt.getTime()
|
|
267
|
+
: undefined;
|
|
268
|
+
return {
|
|
269
|
+
isInitialized: workerInstance.isInitialized,
|
|
270
|
+
isRunning: workerInstance.isRunning,
|
|
271
|
+
isHealthy: workerInstance.isInitialized &&
|
|
272
|
+
!workerInstance.lastError &&
|
|
273
|
+
workerInstance.isRunning,
|
|
274
|
+
taskQueue: workerInstance.taskQueue,
|
|
275
|
+
namespace: workerInstance.namespace,
|
|
276
|
+
workflowSource: workerInstance.workflowSource,
|
|
277
|
+
activitiesCount: workerInstance.activities.size,
|
|
278
|
+
lastError: workerInstance.lastError || undefined,
|
|
279
|
+
startedAt: workerInstance.startedAt || undefined,
|
|
280
|
+
uptime,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
async loadActivitiesForWorker(activities) {
|
|
284
|
+
let attempts = 0;
|
|
285
|
+
const maxAttempts = 30;
|
|
286
|
+
while (attempts < maxAttempts) {
|
|
287
|
+
const healthStatus = this.discoveryService.getHealthStatus();
|
|
288
|
+
if (healthStatus.isComplete) {
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
292
|
+
attempts++;
|
|
293
|
+
}
|
|
294
|
+
const allActivities = this.discoveryService.getAllActivities();
|
|
295
|
+
for (const [activityName, handler] of Object.entries(allActivities)) {
|
|
296
|
+
activities.set(activityName, handler);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
getWorkflowSourceFromDef(workerDef) {
|
|
300
|
+
if (workerDef.workflowBundle)
|
|
301
|
+
return 'bundle';
|
|
302
|
+
if (workerDef.workflowsPath)
|
|
303
|
+
return 'filesystem';
|
|
304
|
+
return 'none';
|
|
305
|
+
}
|
|
306
|
+
async startWorker() {
|
|
307
|
+
if (!this.worker) {
|
|
308
|
+
throw new Error('Worker not initialized. Cannot start worker.');
|
|
309
|
+
}
|
|
310
|
+
if (this.isRunning) {
|
|
311
|
+
this.logger.warn('Worker is already running');
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
try {
|
|
315
|
+
this.logger.info('Starting Temporal worker...');
|
|
316
|
+
this.isRunning = true;
|
|
317
|
+
this.startedAt = new Date();
|
|
318
|
+
this.lastError = null;
|
|
319
|
+
this.restartCount = 0;
|
|
320
|
+
await this.runWorkerWithAutoRestart();
|
|
321
|
+
this.logger.info('Temporal worker started successfully');
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
this.lastError = this.extractErrorMessage(error);
|
|
325
|
+
this.logger.error('Failed to start worker', error);
|
|
326
|
+
this.isRunning = false;
|
|
327
|
+
throw error;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async runWorkerWithAutoRestart() {
|
|
331
|
+
if (!this.worker)
|
|
332
|
+
return;
|
|
333
|
+
try {
|
|
334
|
+
await new Promise((resolve, reject) => {
|
|
335
|
+
setImmediate(async () => {
|
|
336
|
+
try {
|
|
337
|
+
this.worker.run().catch((error) => {
|
|
338
|
+
this.lastError = this.extractErrorMessage(error);
|
|
339
|
+
this.logger.error('Worker run failed', error);
|
|
340
|
+
this.isRunning = false;
|
|
341
|
+
if (this.options.autoRestart !== false &&
|
|
342
|
+
this.restartCount < this.maxRestarts) {
|
|
343
|
+
this.restartCount++;
|
|
344
|
+
this.logger.info(`Auto-restart enabled, attempting to restart worker (attempt ${this.restartCount}/${this.maxRestarts}) in 1 second...`);
|
|
345
|
+
setTimeout(async () => {
|
|
346
|
+
try {
|
|
347
|
+
await this.autoRestartWorker();
|
|
348
|
+
}
|
|
349
|
+
catch (restartError) {
|
|
350
|
+
this.logger.error('Auto-restart failed', restartError);
|
|
351
|
+
}
|
|
352
|
+
}, 1000);
|
|
353
|
+
}
|
|
354
|
+
else if (this.restartCount >= this.maxRestarts) {
|
|
355
|
+
this.logger.error(`Max restart attempts (${this.maxRestarts}) exceeded. Stopping auto-restart.`);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
setTimeout(() => resolve(), 500);
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
reject(error);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
throw error;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
async autoRestartWorker() {
|
|
371
|
+
this.logger.info('Auto-restarting Temporal worker...');
|
|
372
|
+
try {
|
|
373
|
+
if (this.worker) {
|
|
374
|
+
await this.worker.shutdown();
|
|
375
|
+
}
|
|
376
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
377
|
+
this.isRunning = true;
|
|
378
|
+
this.startedAt = new Date();
|
|
379
|
+
this.lastError = null;
|
|
380
|
+
this.runWorkerWithAutoRestart();
|
|
381
|
+
this.logger.info('Temporal worker auto-restarted successfully');
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
this.lastError = this.extractErrorMessage(error);
|
|
385
|
+
this.logger.error('Auto-restart failed', error);
|
|
386
|
+
this.isRunning = false;
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
async stopWorker() {
|
|
391
|
+
if (!this.worker || !this.isRunning) {
|
|
392
|
+
this.logger.debug('Worker is not running or not initialized');
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
this.logger.info('Stopping Temporal worker...');
|
|
397
|
+
await this.worker.shutdown();
|
|
398
|
+
this.isRunning = false;
|
|
399
|
+
this.startedAt = null;
|
|
400
|
+
this.logger.info('Temporal worker stopped successfully');
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
this.lastError = this.extractErrorMessage(error);
|
|
404
|
+
this.logger.error('Failed to stop worker gracefully', error);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
async shutdown() {
|
|
408
|
+
await this.shutdownWorker();
|
|
409
|
+
}
|
|
410
|
+
async restartWorker() {
|
|
411
|
+
this.logger.info('Restarting Temporal worker...');
|
|
412
|
+
try {
|
|
413
|
+
await this.stopWorker();
|
|
414
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
415
|
+
await this.startWorker();
|
|
416
|
+
return {
|
|
417
|
+
success: true,
|
|
418
|
+
restartCount: this.restartCount,
|
|
419
|
+
maxRestarts: this.maxRestarts,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
catch (error) {
|
|
423
|
+
this.lastError = this.extractErrorMessage(error);
|
|
424
|
+
this.logger.error('Failed to restart worker', error);
|
|
425
|
+
return {
|
|
426
|
+
success: false,
|
|
427
|
+
error: error instanceof Error ? error : new Error(this.lastError),
|
|
428
|
+
restartCount: this.restartCount,
|
|
429
|
+
maxRestarts: this.maxRestarts,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
getWorkerStatus() {
|
|
434
|
+
const uptime = this.startedAt ? Date.now() - this.startedAt.getTime() : undefined;
|
|
435
|
+
return {
|
|
436
|
+
isInitialized: this.isInitialized,
|
|
437
|
+
isRunning: this.isRunning,
|
|
438
|
+
isHealthy: this.isInitialized && !this.lastError && this.isRunning,
|
|
439
|
+
taskQueue: this.options.taskQueue || 'default',
|
|
440
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
441
|
+
workflowSource: this.getWorkflowSource(),
|
|
442
|
+
activitiesCount: this.activities.size,
|
|
443
|
+
lastError: this.lastError || undefined,
|
|
444
|
+
startedAt: this.startedAt || undefined,
|
|
445
|
+
uptime,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
getRegisteredActivities() {
|
|
449
|
+
const result = {};
|
|
450
|
+
for (const [name, func] of this.activities.entries()) {
|
|
451
|
+
result[name] = func;
|
|
452
|
+
}
|
|
453
|
+
return result;
|
|
454
|
+
}
|
|
455
|
+
async registerActivitiesFromDiscovery() {
|
|
456
|
+
const errors = [];
|
|
457
|
+
let registeredCount = 0;
|
|
458
|
+
try {
|
|
459
|
+
let attempts = 0;
|
|
460
|
+
const maxAttempts = 30;
|
|
461
|
+
while (attempts < maxAttempts) {
|
|
462
|
+
const healthStatus = this.discoveryService.getHealthStatus();
|
|
463
|
+
if (healthStatus.isComplete) {
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
467
|
+
attempts++;
|
|
468
|
+
}
|
|
469
|
+
const allActivities = this.discoveryService.getAllActivities();
|
|
470
|
+
for (const [activityName, handler] of Object.entries(allActivities)) {
|
|
471
|
+
try {
|
|
472
|
+
this.activities.set(activityName, handler);
|
|
473
|
+
registeredCount++;
|
|
474
|
+
this.logger.debug(`Registered activity: ${activityName}`);
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
478
|
+
errors.push({ activityName, error: errorMessage });
|
|
479
|
+
this.logger.warn(`Failed to register activity ${activityName}: ${errorMessage}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
this.logger.info(`Registered ${registeredCount} activities from discovery service`);
|
|
483
|
+
return {
|
|
484
|
+
success: errors.length === 0,
|
|
485
|
+
registeredCount,
|
|
486
|
+
errors,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
491
|
+
this.logger.error('Failed to register activities from discovery', error);
|
|
492
|
+
return {
|
|
493
|
+
success: false,
|
|
494
|
+
registeredCount,
|
|
495
|
+
errors: [{ activityName: 'discovery', error: errorMessage }],
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
isWorkerAvailable() {
|
|
500
|
+
return this.worker !== null;
|
|
501
|
+
}
|
|
502
|
+
isWorkerRunning() {
|
|
503
|
+
return this.isRunning;
|
|
504
|
+
}
|
|
505
|
+
getStatus() {
|
|
506
|
+
return this.getWorkerStatus();
|
|
507
|
+
}
|
|
508
|
+
getHealthStatus() {
|
|
509
|
+
const uptime = this.startedAt ? Date.now() - this.startedAt.getTime() : undefined;
|
|
510
|
+
return {
|
|
511
|
+
isHealthy: this.isInitialized && !this.lastError && this.isRunning,
|
|
512
|
+
isRunning: this.isRunning,
|
|
513
|
+
isInitialized: this.isInitialized,
|
|
514
|
+
lastError: this.lastError || undefined,
|
|
515
|
+
uptime,
|
|
516
|
+
activitiesCount: this.activities.size,
|
|
517
|
+
restartCount: this.restartCount,
|
|
518
|
+
maxRestarts: this.maxRestarts,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
getStats() {
|
|
522
|
+
const uptime = this.startedAt ? Date.now() - this.startedAt.getTime() : undefined;
|
|
523
|
+
return {
|
|
524
|
+
isInitialized: this.isInitialized,
|
|
525
|
+
isRunning: this.isRunning,
|
|
526
|
+
activitiesCount: this.activities.size,
|
|
527
|
+
restartCount: this.restartCount,
|
|
528
|
+
maxRestarts: this.maxRestarts,
|
|
529
|
+
uptime,
|
|
530
|
+
startedAt: this.startedAt || undefined,
|
|
531
|
+
lastError: this.lastError || undefined,
|
|
532
|
+
taskQueue: this.options.taskQueue || 'default',
|
|
533
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
534
|
+
workflowSource: this.getWorkflowSource(),
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
validateConfiguration() {
|
|
538
|
+
if (!this.options.taskQueue) {
|
|
539
|
+
throw new Error('Task queue is required');
|
|
540
|
+
}
|
|
541
|
+
if (!this.options.connection?.address) {
|
|
542
|
+
throw new Error('Connection address is required');
|
|
543
|
+
}
|
|
544
|
+
if (this.options.worker?.workflowsPath && this.options.worker?.workflowBundle) {
|
|
545
|
+
throw new Error('Cannot specify both workflowsPath and workflowBundle');
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
getEnvironmentDefaults() {
|
|
549
|
+
return {
|
|
550
|
+
taskQueue: this.options.taskQueue || 'default',
|
|
551
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
buildWorkerOptions() {
|
|
555
|
+
const baseOptions = this.getEnvironmentDefaults();
|
|
556
|
+
if (this.options.worker?.workflowsPath) {
|
|
557
|
+
Object.assign(baseOptions, { workflowsPath: this.options.worker.workflowsPath });
|
|
558
|
+
}
|
|
559
|
+
else if (this.options.worker?.workflowBundle) {
|
|
560
|
+
Object.assign(baseOptions, { workflowBundle: this.options.worker.workflowBundle });
|
|
561
|
+
}
|
|
562
|
+
const activitiesObj = {};
|
|
563
|
+
for (const [name, func] of this.activities.entries()) {
|
|
564
|
+
activitiesObj[name] = func;
|
|
565
|
+
}
|
|
566
|
+
Object.assign(baseOptions, { activities: activitiesObj });
|
|
567
|
+
if (this.options.worker?.workerOptions) {
|
|
568
|
+
Object.assign(baseOptions, this.options.worker.workerOptions);
|
|
569
|
+
}
|
|
570
|
+
return baseOptions;
|
|
571
|
+
}
|
|
572
|
+
async createConnection() {
|
|
573
|
+
if (this.injectedConnection) {
|
|
574
|
+
this.connection = this.injectedConnection;
|
|
575
|
+
this.logger.debug('Using injected connection');
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (!this.options.connection?.address) {
|
|
579
|
+
throw new Error('Connection address is required');
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
const address = this.options.connection.address;
|
|
583
|
+
const connectOptions = {
|
|
584
|
+
address,
|
|
585
|
+
tls: this.options.connection.tls,
|
|
586
|
+
};
|
|
587
|
+
if (this.options.connection.apiKey) {
|
|
588
|
+
connectOptions.metadata = {
|
|
589
|
+
...(this.options.connection.metadata || {}),
|
|
590
|
+
authorization: `Bearer ${this.options.connection.apiKey}`,
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
this.logger.debug(`Creating NativeConnection to ${address}`);
|
|
594
|
+
this.connection = await worker_1.NativeConnection.connect(connectOptions);
|
|
595
|
+
this.logger.info(`Connection established to ${address}`);
|
|
596
|
+
}
|
|
597
|
+
catch (error) {
|
|
598
|
+
this.logger.error('Failed to create connection', error);
|
|
599
|
+
if (this.options.allowConnectionFailure !== false) {
|
|
600
|
+
this.logger.warn('Worker connection failed - continuing without worker functionality');
|
|
601
|
+
this.connection = null;
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
async createWorker() {
|
|
608
|
+
await this.createConnection();
|
|
609
|
+
if (!this.connection) {
|
|
610
|
+
throw new Error('Connection not established');
|
|
611
|
+
}
|
|
612
|
+
const workerConfig = await this.createWorkerConfig();
|
|
613
|
+
const { Worker } = await Promise.resolve().then(() => require('@temporalio/worker'));
|
|
614
|
+
this.worker = await Worker.create(workerConfig);
|
|
615
|
+
}
|
|
616
|
+
logWorkerConfiguration() {
|
|
617
|
+
this.logger.debug(`Worker configuration: ${JSON.stringify(this.options.worker)}`);
|
|
618
|
+
}
|
|
619
|
+
async runWorkerLoop() {
|
|
620
|
+
if (!this.worker) {
|
|
621
|
+
throw new Error('Temporal worker not initialized');
|
|
622
|
+
}
|
|
623
|
+
try {
|
|
624
|
+
await this.worker.run();
|
|
625
|
+
}
|
|
626
|
+
catch (error) {
|
|
627
|
+
this.logger.error('Worker execution failed', error);
|
|
628
|
+
throw new Error('Execution error');
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
startWorkerInBackground() {
|
|
632
|
+
if (this.worker && !this.isRunning) {
|
|
633
|
+
this.startWorker().catch((error) => {
|
|
634
|
+
this.logger.error('Background worker start failed', error);
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
shouldInitializeWorker() {
|
|
639
|
+
return Boolean(this.options.worker &&
|
|
640
|
+
(this.options.worker.workflowsPath ||
|
|
641
|
+
this.options.worker.workflowBundle ||
|
|
642
|
+
this.options.worker.activityClasses?.length));
|
|
643
|
+
}
|
|
644
|
+
async initializeWorker() {
|
|
645
|
+
if (!this.options.worker) {
|
|
646
|
+
return {
|
|
647
|
+
success: false,
|
|
648
|
+
error: new Error('Worker configuration is required'),
|
|
649
|
+
activitiesCount: 0,
|
|
650
|
+
taskQueue: this.options.taskQueue || 'default',
|
|
651
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
try {
|
|
655
|
+
this.validateConfiguration();
|
|
656
|
+
await this.createConnection();
|
|
657
|
+
if (!this.connection && this.options.allowConnectionFailure !== false) {
|
|
658
|
+
this.logger.info('Worker initialization skipped due to connection failure');
|
|
659
|
+
return {
|
|
660
|
+
success: false,
|
|
661
|
+
error: new Error('No worker connection available'),
|
|
662
|
+
activitiesCount: 0,
|
|
663
|
+
taskQueue: this.options.taskQueue || 'default',
|
|
664
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
await this.loadActivitiesFromDiscovery();
|
|
668
|
+
const workerConfig = await this.createWorkerConfig();
|
|
669
|
+
const { Worker } = await Promise.resolve().then(() => require('@temporalio/worker'));
|
|
670
|
+
this.worker = await Worker.create(workerConfig);
|
|
671
|
+
this.logger.debug(`Worker created - TaskQueue: ${workerConfig.taskQueue}, Activities: ${this.activities.size}, Source: ${this.getWorkflowSource()}`);
|
|
672
|
+
return {
|
|
673
|
+
success: true,
|
|
674
|
+
worker: this.worker,
|
|
675
|
+
activitiesCount: this.activities.size,
|
|
676
|
+
taskQueue: workerConfig.taskQueue,
|
|
677
|
+
namespace: workerConfig.namespace,
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
this.lastError = this.extractErrorMessage(error);
|
|
682
|
+
this.logger.error('Failed to initialize worker', error);
|
|
683
|
+
return {
|
|
684
|
+
success: false,
|
|
685
|
+
error: error instanceof Error ? error : new Error(this.lastError),
|
|
686
|
+
activitiesCount: this.activities.size,
|
|
687
|
+
taskQueue: this.options.taskQueue || 'default',
|
|
688
|
+
namespace: this.options.connection?.namespace || 'default',
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
async loadActivitiesFromDiscovery() {
|
|
693
|
+
const startTime = Date.now();
|
|
694
|
+
const errors = [];
|
|
695
|
+
let discoveredActivities = 0;
|
|
696
|
+
let loadedActivities = 0;
|
|
697
|
+
try {
|
|
698
|
+
let attempts = 0;
|
|
699
|
+
const maxAttempts = 30;
|
|
700
|
+
while (attempts < maxAttempts) {
|
|
701
|
+
const healthStatus = this.discoveryService.getHealthStatus();
|
|
702
|
+
if (healthStatus.isComplete) {
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
706
|
+
attempts++;
|
|
707
|
+
}
|
|
708
|
+
const allActivities = this.discoveryService.getAllActivities();
|
|
709
|
+
discoveredActivities = Object.keys(allActivities).length;
|
|
710
|
+
for (const [activityName, handler] of Object.entries(allActivities)) {
|
|
711
|
+
try {
|
|
712
|
+
this.activities.set(activityName, handler);
|
|
713
|
+
loadedActivities++;
|
|
714
|
+
this.logger.debug(`Loaded activity: ${activityName}`);
|
|
715
|
+
}
|
|
716
|
+
catch (error) {
|
|
717
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
718
|
+
errors.push({ component: activityName, error: errorMessage });
|
|
719
|
+
this.logger.warn(`Failed to load activity ${activityName}: ${errorMessage}`);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
this.logger.info(`Loaded ${loadedActivities} activities from discovery service`);
|
|
723
|
+
return {
|
|
724
|
+
success: errors.length === 0,
|
|
725
|
+
discoveredActivities,
|
|
726
|
+
loadedActivities,
|
|
727
|
+
errors,
|
|
728
|
+
duration: Date.now() - startTime,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
catch (error) {
|
|
732
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
733
|
+
this.logger.error('Failed to load activities from discovery', error);
|
|
734
|
+
return {
|
|
735
|
+
success: false,
|
|
736
|
+
discoveredActivities,
|
|
737
|
+
loadedActivities,
|
|
738
|
+
errors: [{ component: 'discovery', error: errorMessage }],
|
|
739
|
+
duration: Date.now() - startTime,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
async createWorkerConfig() {
|
|
744
|
+
const taskQueue = this.options.taskQueue || 'default';
|
|
745
|
+
const namespace = this.options.connection?.namespace || 'default';
|
|
746
|
+
if (!this.connection) {
|
|
747
|
+
throw new Error('Connection not established');
|
|
748
|
+
}
|
|
749
|
+
const config = {
|
|
750
|
+
taskQueue,
|
|
751
|
+
namespace,
|
|
752
|
+
connection: this.connection,
|
|
753
|
+
activities: Object.fromEntries(this.activities),
|
|
754
|
+
};
|
|
755
|
+
if (this.options.worker?.workflowsPath) {
|
|
756
|
+
config.workflowsPath = this.options.worker.workflowsPath;
|
|
757
|
+
this.logger.debug(`Using workflows from path: ${this.options.worker.workflowsPath}`);
|
|
758
|
+
}
|
|
759
|
+
else if (this.options.worker?.workflowBundle) {
|
|
760
|
+
config.workflowBundle = this.options.worker.workflowBundle;
|
|
761
|
+
this.logger.debug('Using workflow bundle');
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
this.logger.warn('No workflow configuration provided - worker will only handle activities');
|
|
765
|
+
}
|
|
766
|
+
if (this.options.worker?.workerOptions) {
|
|
767
|
+
Object.assign(config, this.options.worker.workerOptions);
|
|
768
|
+
}
|
|
769
|
+
return config;
|
|
770
|
+
}
|
|
771
|
+
async shutdownWorker() {
|
|
772
|
+
if (this.shutdownPromise) {
|
|
773
|
+
return this.shutdownPromise;
|
|
774
|
+
}
|
|
775
|
+
this.shutdownPromise = this.performShutdown();
|
|
776
|
+
return this.shutdownPromise;
|
|
777
|
+
}
|
|
778
|
+
async performShutdown() {
|
|
779
|
+
try {
|
|
780
|
+
this.logger.info('Shutting down Temporal worker manager...');
|
|
781
|
+
if (this.workers.size > 0) {
|
|
782
|
+
this.logger.info(`Shutting down ${this.workers.size} workers...`);
|
|
783
|
+
for (const [taskQueue, workerInstance] of this.workers.entries()) {
|
|
784
|
+
try {
|
|
785
|
+
if (workerInstance.isRunning) {
|
|
786
|
+
this.logger.debug(`Stopping worker for '${taskQueue}'...`);
|
|
787
|
+
await workerInstance.worker.shutdown();
|
|
788
|
+
workerInstance.isRunning = false;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
catch (error) {
|
|
792
|
+
this.logger.warn(`Error shutting down worker '${taskQueue}'`, error);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
this.workers.clear();
|
|
796
|
+
}
|
|
797
|
+
if (this.worker) {
|
|
798
|
+
await this.stopWorker();
|
|
799
|
+
this.worker = null;
|
|
800
|
+
}
|
|
801
|
+
if (this.connection && !this.injectedConnection) {
|
|
802
|
+
try {
|
|
803
|
+
await this.connection.close();
|
|
804
|
+
this.logger.info('Connection closed successfully');
|
|
805
|
+
}
|
|
806
|
+
catch (error) {
|
|
807
|
+
this.logger.warn('Error closing connection', error);
|
|
808
|
+
}
|
|
809
|
+
this.connection = null;
|
|
810
|
+
}
|
|
811
|
+
this.isInitialized = false;
|
|
812
|
+
this.logger.info('Worker manager shutdown completed');
|
|
813
|
+
}
|
|
814
|
+
catch (error) {
|
|
815
|
+
this.logger.error('Error during worker shutdown', error);
|
|
816
|
+
}
|
|
817
|
+
finally {
|
|
818
|
+
this.shutdownPromise = null;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
getWorkflowSource() {
|
|
822
|
+
if (this.options.worker?.workflowBundle)
|
|
823
|
+
return 'bundle';
|
|
824
|
+
if (this.options.worker?.workflowsPath)
|
|
825
|
+
return 'filesystem';
|
|
826
|
+
return 'none';
|
|
827
|
+
}
|
|
828
|
+
extractErrorMessage(error) {
|
|
829
|
+
if (error instanceof Error) {
|
|
830
|
+
return error.message;
|
|
831
|
+
}
|
|
832
|
+
if (typeof error === 'string') {
|
|
833
|
+
return error;
|
|
834
|
+
}
|
|
835
|
+
return 'Unknown error';
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
exports.TemporalWorkerManagerService = TemporalWorkerManagerService;
|
|
839
|
+
exports.TemporalWorkerManagerService = TemporalWorkerManagerService = TemporalWorkerManagerService_1 = __decorate([
|
|
840
|
+
(0, common_1.Injectable)(),
|
|
841
|
+
__param(1, (0, common_1.Inject)(constants_1.TEMPORAL_MODULE_OPTIONS)),
|
|
842
|
+
__param(2, (0, common_1.Inject)(constants_1.TEMPORAL_CONNECTION)),
|
|
843
|
+
__metadata("design:paramtypes", [temporal_discovery_service_1.TemporalDiscoveryService, Object, Object])
|
|
844
|
+
], TemporalWorkerManagerService);
|
|
845
|
+
//# sourceMappingURL=temporal-worker.service.js.map
|