feat(task): add task labels and push-based task events

This commit is contained in:
2026-01-26 00:39:30 +00:00
parent 9a3a3e3eab
commit 6030fb2805
9 changed files with 360 additions and 9 deletions

View File

@@ -2,7 +2,7 @@ import * as plugins from './taskbuffer.plugins.js';
import { BufferRunner } from './taskbuffer.classes.bufferrunner.js';
import { CycleCounter } from './taskbuffer.classes.cyclecounter.js';
import { TaskStep, type ITaskStep } from './taskbuffer.classes.taskstep.js';
import type { ITaskMetadata } from './taskbuffer.interfaces.js';
import type { ITaskMetadata, ITaskEvent, TTaskEventType } from './taskbuffer.interfaces.js';
import { logger } from './taskbuffer.logging.js';
@@ -91,6 +91,7 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
// Reset steps and error state at the beginning of task execution
taskToRun.resetSteps();
taskToRun.lastError = undefined;
taskToRun.emitEvent('started');
done.promise
.then(async () => {
@@ -98,6 +99,7 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
// Complete all steps when task finishes
taskToRun.completeAllSteps();
taskToRun.emitEvent(taskToRun.lastError ? 'failed' : 'completed');
// When the task has finished running, resolve the finished promise
taskToRun.resolveFinished();
@@ -109,6 +111,7 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
})
.catch((err) => {
taskToRun.running = false;
taskToRun.emitEvent('failed', { error: err instanceof Error ? err.message : String(err) });
// Resolve finished so blocking dependants don't hang
taskToRun.resolveFinished();
@@ -218,6 +221,8 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
public catchErrors: boolean = false;
public lastError?: Error;
public errorCount: number = 0;
public labels: Record<string, string> = {};
public readonly eventSubject = new plugins.smartrx.rxjs.Subject<ITaskEvent>();
public get idle() {
return !this.running;
@@ -227,6 +232,38 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
this.lastError = undefined;
}
public setLabel(key: string, value: string): void {
this.labels[key] = value;
}
public getLabel(key: string): string | undefined {
return this.labels[key];
}
public removeLabel(key: string): boolean {
if (key in this.labels) {
delete this.labels[key];
return true;
}
return false;
}
public hasLabel(key: string, value?: string): boolean {
if (value !== undefined) {
return this.labels[key] === value;
}
return key in this.labels;
}
private emitEvent(type: TTaskEventType, extra?: Partial<ITaskEvent>): void {
this.eventSubject.next({
type,
task: this.getMetadata(),
timestamp: Date.now(),
...extra,
});
}
public taskSetup: ITaskSetupFunction<T>;
public setupValue: T;
@@ -247,6 +284,7 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
taskSetup?: ITaskSetupFunction<T>;
steps?: TSteps;
catchErrors?: boolean;
labels?: Record<string, string>;
}) {
this.taskFunction = optionsArg.taskFunction;
this.preTask = optionsArg.preTask;
@@ -257,6 +295,7 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
this.name = optionsArg.name;
this.taskSetup = optionsArg.taskSetup;
this.catchErrors = optionsArg.catchErrors ?? false;
this.labels = optionsArg.labels ? { ...optionsArg.labels } : {};
// Initialize steps if provided
if (optionsArg.steps) {
@@ -309,8 +348,8 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
if (step) {
step.start();
this.currentStepName = stepName as string;
// Emit event for frontend updates (could be enhanced with event emitter)
this.emitEvent('step', { stepName: stepName as string });
if (this.name) {
logger.log('info', `Task ${this.name}: Starting step "${stepName}" - ${step.description}`);
}
@@ -369,6 +408,7 @@ export class Task<T = undefined, TSteps extends ReadonlyArray<{ name: string; de
cronSchedule: this.cronJob?.cronExpression,
lastError: this.lastError?.message,
errorCount: this.errorCount,
labels: { ...this.labels },
};
}