- Added CloudlyTaskManager class for managing tasks, including registration, execution, scheduling, and cancellation. - Created predefined tasks: DNS Sync, Certificate Renewal, Cleanup, Health Check, Resource Report, Database Maintenance, Security Scan, and Docker Cleanup. - Introduced ITaskExecution interface for tracking task execution details and outcomes. - Developed API request interfaces for task management operations (getTasks, getTaskExecutions, triggerTask, cancelTask). - Implemented CloudlyViewTasks web component for displaying tasks and their execution history, including filtering and detailed views.
165 lines
4.0 KiB
TypeScript
165 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.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;
|
|
}
|
|
} |