f40ef6b7c0
Align Cloudly with the current typedserver, smartconfig, smartstate, and Docker tooling releases so builds and Docker output stay compatible with the upgraded stack.
166 lines
4.0 KiB
TypeScript
166 lines
4.0 KiB
TypeScript
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.unI()
|
|
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;
|
|
}
|
|
}
|