///
import type WebSocket from 'ws';
import EventEmitter from 'events';
import { JobDefinition, Operation, OperationType } from '@nosana/sdk';
import { NodeRepository } from '../../repository/NodeRepository.js';
import { Provider } from '../../provider/Provider.js';
import { Flow } from '@nosana/sdk';
import { StatsBuffer } from './loggers/StatsBuffer.js';
export type TaskManagerOps = Array>;
export type ExecutionContext = {
group: string;
ops: string[];
};
export type DependencyContext = {
dependencies: string[];
dependents: string[];
};
export declare const StopReasons: {
readonly COMPLETED: "completed";
readonly EXPIRED: "expired";
readonly STOPPED: "stopped";
readonly QUIT: "quit";
readonly UNKNOWN: "unknown";
readonly RESTART: "restart";
};
export type StopReason = (typeof StopReasons)[keyof typeof StopReasons];
export declare const Statuses: {
readonly SUCCESS: "success";
readonly STOPPED: "stopped";
readonly FAILED: "failed";
};
export declare const OperationProgressStatuses: {
readonly FINISHED: "finished";
readonly STOPPED: "stopped";
readonly FAILED: "failed";
readonly RUNNING: "running";
readonly RESTARTING: "restarting";
readonly STOPPING: "stopping";
readonly STARTING: "starting";
readonly WAITING: "waiting";
readonly PENDING: "pending";
readonly INIT: "init";
};
export type LogType = 'container' | 'info' | 'error';
export interface TaskStat {
opId: string;
timestamp: number;
cpu: {
cpu_percent: number;
};
memory: {
memory_usage: number;
memory_limit: number;
memory_percent: number;
};
disk: {
read: number;
write: number;
};
network: {
received: number;
sent: number;
};
}
export interface TaskLog {
opId: string;
group: string;
type: LogType;
timestamp: number;
message: any;
}
export type OperationData = {
host?: string;
container_ip?: string;
endpoint?: {
[key: string]: string;
};
deployment_endpoint?: string;
results?: Record;
};
type InterpolateFn = (value: T) => T;
type InterpolateOpFn = (op: Operation) => Operation;
export type GlobalDataStore = Record;
export type GlobalStore = {
job: string;
host: string;
project: string;
frps_address: string;
version: string;
variables?: Record;
};
export type Status = (typeof Statuses)[keyof typeof Statuses];
export default class TaskManager {
protected provider: Provider;
protected repository: NodeRepository;
protected job: string;
protected project: string;
protected definition?: JobDefinition | undefined;
/**
* All operations defined in the Job Definition (JD).
*/
protected operations: TaskManagerOps | undefined;
/**
* The ordered execution plan built from the job definition.
* Each item represents a group of ops that run together horizontally.
*/
protected executionPlan: ExecutionContext[];
/**
* this creates a map to assign the dependency
*/
protected dependecyMap: Map;
/**
* A map for fast lookup of operations by their ID.
* Useful during validation and execution.
*/
protected opMap: Map>;
/**
* Global data store.
*
* This allows operations to reference data produced by others using literals like:
* "%%global.frps_address%%"
* "%%global.project%%"
*
* Supported keys:
* - frps_address: The current FRPS address.
* - project: The project public key of the jobs project.
*/
protected globalStore: GlobalStore;
/**
* Global data store for all operations in a job definition.
*
* This allows operations to reference data produced by others using literals like:
* "%%ops.nginx-1.results.someKey%%"
* "%%ops.nginx-1.host%%"
*
* Supported keys:
* - result: Stores the output of an operation so it can be accessed later, even if it was unknown at the start of the job.
* - host: Stores the reachable host/URL of the operation. Since Docker container names are dynamic,
* this ensures other operations can communicate with it without needing to know the name in advance.
*/
protected globalOpStore: GlobalDataStore;
/**
* Main controller to allow global cancellation of the entire task flow.
* All per-op controllers should eventually be tied to this as their parent,
* or fallback to this if no specific controller is assigned yet.
*/
protected mainAbortController: AbortController;
/**
* Stores one AbortController per op.
* Used to signal cancellation to all ops in a group or individually if needed.
*/
protected abortControllerMap: Map;
/**
* Keeps track of the currently running group.
* Useful for coordinating group-level logic or logging.
*/
protected currentGroup: string | undefined;
/**
* keeps track of all promises of the current running group
*/
protected currentGroupOperationsPromises: Map>;
/**
* this is to create concurrency control on the operations
*/
protected lockedOperations: Map;
/**
* this is used to track the operations statuses
*/
protected operationStatus: Map;
/**
* this is to track event emitter to emit events
*/
protected operationsEventEmitters: Map;
/**
* save log buffer for streaming logs
*/
protected opLogBuffers: Map;
/**
* save stat buffer for streaming container stats
*/
protected opStatBuffers: Map;
/**
* this list of ws sub to the task managers events
*/
protected subscribers: Set;
/**
* stores filters
*/
protected logMatchers: Map boolean>;
/**
* ws subscribers for stats streaming
*/
protected statSubscribers: Set;
/**
* stores stat filters
*/
protected statMatchers: Map boolean>;
protected TOTAL_LOGS_COUNT: number;
/**
* Lifecycle status of the task manager.
* Can be 'init', 'running', 'stopped', or 'done'.
*/
protected status: string;
private currentRunningStartPromise?;
/**
* Event emitter for task- and op-level lifecycle events.
*/
protected events: EventEmitter;
constructor(provider: Provider, repository: NodeRepository, job: string, project: string, definition?: JobDefinition | undefined);
runTaskManagerOperation: (flow: Flow, op: Operation, dependent: string[]) => Promise;
restartTaskManagerOperation: (group: string, opId: string) => Promise;
stopTaskManagerOperation: (group: string, opId: string) => Promise;
stopTaskManagerGroupOperations: (group: string) => Promise;
restartTaskManagerGroupOperations: (group: string) => Promise;
stopAllTaskManagerOperations: (reason: StopReason) => void;
createOperationMap: () => Map>;
createExecutionPlan: () => ExecutionContext[];
createDependencyMap: () => Map;
validateExecutionPlan: () => void;
getOperationsStatus: () => Record;
getOperationStatus: (id: string) => Record;
getCurrentGroup: () => string | undefined;
getCurrentGroupStatus: () => Record;
getGroupStatus: (group: string) => Record;
addlog: (log: TaskLog) => void;
getLogsByOp: (opid: string) => TaskLog[];
getLogsByGroup: (group: string) => TaskLog[];
getAllLogs: () => TaskLog[];
subscribe: (ws: WebSocket, matcher: (log: TaskLog) => boolean) => void;
unsubscribe: (ws: WebSocket) => void;
addStat: (stat: TaskStat) => void;
getStatsByOp: (opId: string) => TaskStat[];
getAllStats: () => TaskStat[];
queryStats: (start?: number, end?: number, intervalMs?: number) => TaskStat[];
getLatestStatPerOp: (since: number) => TaskStat[];
subscribeStats: (ws: WebSocket, matcher: (stat: TaskStat) => boolean) => void;
unsubscribeStats: (ws: WebSocket) => void;
setResult: (opId: string, key: string, value: any) => void;
setResults: (opId: string, values: Record) => void;
setHost: (opId: string, host: string) => void;
setContainerIp: (opId: string, ip: string) => void;
setDefaults: (flowId: string, project: string, jobDefinition: JobDefinition) => void;
rehydrateEndpointsForOperation: (flowId: string, project: string, jobDefinition: JobDefinition, opId: string) => void;
getByPath: (opId: string, path: string) => any;
resolveLiteralsInString: (input: string) => string;
interpolate: InterpolateFn;
interpolateOperation: InterpolateOpFn;
transformCollections: InterpolateOpFn;
/**
* Returns the unified event emitter for this task manager.
*/
getEventsEmitter(): EventEmitter;
/**
* Registers an op-level emitter and relays its relevant events to the
* task-level unified emitter. Also tracks the emitter in operationsEventEmitters.
*/
protected registerAndRelayOpEmitter(opId: string, emitter: EventEmitter): void;
/**
* Prepares the TaskManager for execution by performing all necessary setup steps.
*
* This method performs two key operations:
*
* `build()`:
* - Generates a map of all operations for fast lookup.
* - Creates the execution plan based on operation groups and dependencies.
* - Validates the structure of the plan to catch any misconfigurations early.
*
* `init()`:
* - Initializes the task's persistent flow state in the repository.
* - Skips initialization if the flow already exists (resumable/restartable design).
*
* Call this once before `start()` to ensure the task manager is fully ready.
*/
bootstrap(): void;
/**
* Starts the execution of the job by processing each group in the execution plan.
* Tracks the full lifecycle including flow state updates and dynamic operations.
*
* Execution Lifecycle:
* - If already started, returns the tracked lifecycle promise.
* - Sets status to 'running' and updates the repository with start time.
* - Iterates through execution groups and runs each op concurrently.
* - Uses a dynamic while-loop to ensure all ops (including restarts) finish before advancing.
* - After all groups finish, sets the final flow status: 'failed' if any op
* failed, 'success' otherwise (including stopped/expired jobs).
* - On any uncaught failure, marks the flow as 'failed' with end time.
*/
start(): Promise;
/**
* Gracefully stops the task manager and all its operations.
*
* This method:
* - Immediately aborts all running operations by triggering the main abort controller.
* - Waits for the current `start()` flow to finish, including database updates.
* - Ensures `stop()` logic runs only once per job to prevent race conditions.
*
* Important:
* - `stopAllTaskManagerOperations()` is synchronous and triggers cancellation.
* - The actual cleanup and final state update (e.g., setting `endTime`) is handled
* by the `start()` method’s final logic.
*/
stop(reason: StopReason): Promise;
protected setUpOperationFunc(flow: Flow, id: string, dependent: string[]): Promise;
protected trackGroupOperationPromise(opId: string, promise: Promise): Promise;
protected getStatus(reason: StopReason, type: 'ops' | 'flow'): Status;
protected getOpStateIndex(opId: string): number;
private build;
private init;
}
export {};