import * as plugins from '../plugins.js'; import { CloudlyTaskManager } from './classes.taskmanager.js'; @plugins.smartdata.managed() export class TaskExecution extends plugins.smartdata.SmartDataDbDoc< TaskExecution, plugins.servezoneInterfaces.data.ITaskExecution, CloudlyTaskManager > { // STATIC public static async getTaskExecutionById(executionIdArg: string) { const execution = await this.getInstance({ id: executionIdArg, }); return execution; } public static async getTaskExecutions(filterArg?: { taskName?: string; status?: string; startedAfter?: number; startedBefore?: number; }) { const query: any = {}; if (filterArg?.taskName) { query['data.taskName'] = filterArg.taskName; } if (filterArg?.status) { query['data.status'] = filterArg.status; } if (filterArg?.startedAfter || filterArg?.startedBefore) { query['data.startedAt'] = {}; if (filterArg.startedAfter) { query['data.startedAt'].$gte = filterArg.startedAfter; } if (filterArg.startedBefore) { query['data.startedAt'].$lte = filterArg.startedBefore; } } const executions = await this.getInstances(query); return executions; } public static async createTaskExecution( taskName: string, triggeredBy: 'schedule' | 'manual' | 'system', userId?: string ) { const execution = new TaskExecution(); execution.id = await TaskExecution.getNewId(); execution.data = { taskName, startedAt: Date.now(), status: 'running', triggeredBy, userId, logs: [], }; await execution.save(); return execution; } // INSTANCE @plugins.smartdata.svDb() public id: string; @plugins.smartdata.svDb() public data: plugins.servezoneInterfaces.data.ITaskExecution['data']; /** * Add a log entry to the execution */ public async addLog(message: string, severity: 'info' | 'warning' | 'error' | 'success' = 'info') { this.data.logs.push({ timestamp: Date.now(), message, severity, }); await this.save(); } /** * Set a metric for the execution */ public async setMetric(key: string, value: any) { if (!this.data.metrics) { this.data.metrics = {}; } this.data.metrics[key] = value; await this.save(); } /** * Mark the execution as completed */ public async complete(result?: any) { this.data.completedAt = Date.now(); this.data.duration = this.data.completedAt - this.data.startedAt; this.data.status = 'completed'; if (result !== undefined) { this.data.result = result; } await this.save(); } /** * Mark the execution as failed */ public async fail(error: Error | string) { this.data.completedAt = Date.now(); this.data.duration = this.data.completedAt - this.data.startedAt; this.data.status = 'failed'; if (typeof error === 'string') { this.data.error = { message: error, }; } else { this.data.error = { message: error.message, stack: error.stack, code: (error as any).code, }; } await this.save(); } /** * Cancel the execution */ public async cancel() { this.data.completedAt = Date.now(); this.data.duration = this.data.completedAt - this.data.startedAt; this.data.status = 'cancelled'; await this.save(); } /** * Get running executions */ public static async getRunningExecutions() { return await this.getInstances({ 'data.status': 'running', }); } /** * Clean up old executions */ public static async cleanupOldExecutions(olderThanDays: number = 30) { const cutoffTime = Date.now() - (olderThanDays * 24 * 60 * 60 * 1000); const oldExecutions = await this.getInstances({ 'data.completedAt': { $lt: cutoffTime }, }); for (const execution of oldExecutions) { await execution.delete(); } return oldExecutions.length; } }