nestjs-temporal-core
Version:
Complete NestJS integration for Temporal.io with auto-discovery, declarative scheduling, enhanced monitoring, and enterprise-ready features
192 lines • 8.49 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var TemporalActivityService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TemporalActivityService = void 0;
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const temporal_metadata_accessor_1 = require("../worker/temporal-metadata.accessor");
const constants_1 = require("../constants");
const logger_1 = require("../utils/logger");
let TemporalActivityService = TemporalActivityService_1 = class TemporalActivityService {
constructor(options, discoveryService, metadataAccessor) {
this.options = options;
this.discoveryService = discoveryService;
this.metadataAccessor = metadataAccessor;
this.discoveredActivities = new Map();
this.activityHandlers = new Map();
this.logger = (0, logger_1.createLogger)(TemporalActivityService_1.name);
}
async onModuleInit() {
await this.discoverActivities();
this.logActivitySummary();
}
async discoverActivities() {
const providers = this.discoveryService.getProviders();
let discoveredCount = 0;
for (const wrapper of providers) {
const { instance, metatype } = wrapper;
const targetClass = instance?.constructor || metatype;
if (!targetClass || !instance)
continue;
if (!this.metadataAccessor.isActivity(targetClass))
continue;
if (this.options.activityClasses?.length) {
if (!this.options.activityClasses.includes(targetClass))
continue;
}
try {
const activityInfo = await this.processActivityClass(instance, targetClass);
if (activityInfo) {
this.discoveredActivities.set(targetClass.name, activityInfo);
discoveredCount++;
}
}
catch (error) {
this.logger.error(`Failed to process activity class ${targetClass.name}:`, error.stack);
}
}
this.logger.log(`Discovered ${discoveredCount} activity classes`);
}
async processActivityClass(instance, targetClass) {
const className = targetClass.name;
this.logger.debug(`Processing activity class: ${className}`);
const validation = this.metadataAccessor.validateActivityClass(targetClass);
if (!validation.isValid) {
this.logger.warn(`Activity class ${className} has validation issues: ${validation.issues.join(', ')}`);
return null;
}
const activityMethods = this.metadataAccessor.extractActivityMethods(instance);
const methodInfos = [];
for (const [activityName, handler] of activityMethods.entries()) {
this.activityHandlers.set(activityName, handler);
const methodName = Object.getOwnPropertyNames(Object.getPrototypeOf(instance)).find((name) => instance[name] === handler);
if (methodName) {
const method = Object.getPrototypeOf(instance)[methodName];
methodInfos.push({
name: activityName,
methodName,
options: this.metadataAccessor.getActivityMethodOptions(method),
});
}
this.logger.debug(`Registered activity: ${className}.${activityName}`);
}
return {
className,
instance,
targetClass: targetClass,
methods: methodInfos,
totalMethods: methodInfos.length,
};
}
getDiscoveredActivities() {
return Array.from(this.discoveredActivities.values());
}
getActivityByClassName(className) {
return this.discoveredActivities.get(className);
}
getActivityHandlers() {
return Object.fromEntries(this.activityHandlers.entries());
}
getActivityHandler(activityName) {
return this.activityHandlers.get(activityName);
}
getActivityNames() {
return Array.from(this.activityHandlers.keys());
}
hasActivity(activityName) {
return this.activityHandlers.has(activityName);
}
getActivityStats() {
const activities = this.getDiscoveredActivities();
const totalMethods = activities.reduce((sum, activity) => sum + activity.totalMethods, 0);
return {
totalClasses: activities.length,
totalMethods,
classNames: activities.map((a) => a.className),
methodNames: this.getActivityNames(),
};
}
validateConfiguration() {
const issues = [];
const warnings = [];
if (this.discoveredActivities.size === 0) {
warnings.push('No activities were discovered. Make sure classes are decorated with @Activity()');
}
const methodNames = this.getActivityNames();
const duplicates = methodNames.filter((name, index) => methodNames.indexOf(name) !== index);
if (duplicates.length > 0) {
issues.push(`Duplicate activity names found: ${duplicates.join(', ')}`);
}
if (this.options.activityClasses?.length) {
const foundClasses = this.getDiscoveredActivities().map((a) => a.targetClass);
const missingClasses = this.options.activityClasses.filter((cls) => !foundClasses.includes(cls));
if (missingClasses.length > 0) {
warnings.push(`Some specified activity classes were not found: ${missingClasses.map((c) => c.name).join(', ')}`);
}
}
return {
isValid: issues.length === 0,
issues,
warnings,
};
}
getHealthStatus() {
const stats = this.getActivityStats();
const validation = this.validateConfiguration();
let status;
if (!validation.isValid) {
status = 'unhealthy';
}
else if (validation.warnings.length > 0 || stats.totalMethods === 0) {
status = 'degraded';
}
else {
status = 'healthy';
}
return {
status,
activities: {
total: stats.totalClasses,
registered: stats.totalMethods,
},
validation,
};
}
logActivitySummary() {
const stats = this.getActivityStats();
const validation = this.validateConfiguration();
this.logger.log(`Activity discovery completed: ${stats.totalClasses} classes, ${stats.totalMethods} methods`);
if (stats.totalClasses > 0) {
this.logger.debug(`Activity classes: ${stats.classNames.join(', ')}`);
}
if (stats.totalMethods > 0) {
this.logger.debug(`Activity methods: ${stats.methodNames.join(', ')}`);
}
if (validation.warnings.length > 0) {
validation.warnings.forEach((warning) => this.logger.warn(warning));
}
if (validation.issues.length > 0) {
validation.issues.forEach((issue) => this.logger.error(issue));
}
}
};
exports.TemporalActivityService = TemporalActivityService;
exports.TemporalActivityService = TemporalActivityService = TemporalActivityService_1 = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, common_1.Inject)(constants_1.ACTIVITY_MODULE_OPTIONS)),
__metadata("design:paramtypes", [Object, core_1.DiscoveryService,
temporal_metadata_accessor_1.TemporalMetadataAccessor])
], TemporalActivityService);
//# sourceMappingURL=temporal-activity.service.js.map