Files
v10/dist/dev/core/tasks/task.d.ts
T

115 lines
4.6 KiB
TypeScript

//#region src/core/tasks/task.d.ts
/** Recursively marks all properties as readonly. */
type DeepReadonly<T> = T extends (infer U)[] ? ReadonlyArray<DeepReadonly<U>> : T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]>; } : T;
type TaskStatus = 'pending' | 'running' | 'done' | 'error';
/**
* Configuration for a Task.
*/
interface TaskConfig {
/**
* Identifier for this task.
* - string: used as-is
* - () => string: called once at construction time
* - undefined: a unique ID is generated via generateId()
*/
id?: string | (() => string);
/**
* Optional external AbortSignal to compose with the task's internal one.
* The task's work is aborted when either the internal controller (via abort())
* or this external signal fires — whichever comes first.
*/
signal?: AbortSignal;
}
/**
* Minimal contract for a schedulable unit of async work.
*/
interface TaskLike<TValue = void, TError = unknown> {
readonly id: string;
readonly status: TaskStatus;
readonly value: DeepReadonly<TValue> | undefined;
readonly error: DeepReadonly<TError> | undefined;
run(): Promise<TValue>;
abort(): void;
}
/**
* Generic reusable task that wraps an async run function.
*
* Owns its own AbortController so it can always be aborted independently.
* Optionally composes an external AbortSignal so that a parent's cancellation
* propagates into the task's work without requiring the caller to track the
* task separately.
*
* Ordering guarantee: `value` is written before `status` transitions to `'done'`;
* `error` is written before `status` transitions to `'error'`. Any reader
* observing `status === 'done'` is guaranteed `value` is already present.
*/
declare class Task<TValue = void, TError = unknown> implements TaskLike<TValue, TError> {
#private;
readonly id: string;
constructor(runFn: (signal: AbortSignal) => Promise<TValue>, config?: TaskConfig);
get status(): TaskStatus;
get value(): DeepReadonly<TValue> | undefined;
get error(): DeepReadonly<TError> | undefined;
run(): Promise<TValue>;
abort(): void;
}
/**
* Runs tasks concurrently, deduplicated by task id.
*
* If a task with a given id is already in flight, subsequent schedule() calls
* for that id are silently ignored until the first completes. Tasks are stored
* so abortAll() can cancel any in-flight work (e.g. on engine cleanup).
*/
declare class ConcurrentRunner {
#private;
schedule<TValue = void, TError = unknown>(task: TaskLike<TValue, TError>): Promise<TValue>;
/**
* Registers a callback to fire when all currently in-flight tasks settle.
* If the runner is already idle, the callback is never called. If abortAll()
* is called before the batch settles, the callback is superseded and silently
* dropped — no stale callbacks, no generation token required by the caller.
*/
whenSettled(callback: () => void): void;
abortAll(): void;
destroy(): void;
}
/**
* Runs tasks one at a time in submission order.
*
* Each schedule() call returns a Promise that resolves or rejects with the
* task's result when it is eventually executed. Tasks wait in queue until the
* prior task completes.
*
* Serialization is achieved by chaining each task's run() onto the tail of a
* shared promise chain — no explicit queue or drain loop needed.
*
* abortAll() aborts all pending (not yet started) tasks and the currently
* in-flight task. Pending tasks still run briefly but receive an aborted
* signal and are expected to exit early.
*/
declare class SerialRunner {
#private;
schedule<TValue = void, TError = unknown>(task: TaskLike<TValue, TError>): Promise<TValue>;
/**
* A promise that resolves when all currently-scheduled tasks have settled.
* Use the reference as a generation token: capture it after scheduling a
* batch, then check identity in the resolution callback to detect whether
* a subsequent abortAll() + new batch has superseded this one.
*/
get settled(): Promise<void>;
/**
* Registers a callback to fire when all currently-pending tasks settle.
* If the runner is already idle (no pending or running tasks), the callback
* is never called. If new tasks are scheduled before the current batch
* settles, the callback is superseded and silently dropped — no stale
* callbacks, no generation token required by the caller.
*/
whenSettled(callback: () => void): void;
/** Aborts and clears queued tasks without touching the in-flight task. */
abortPending(): void;
abortAll(): void;
destroy(): void;
}
//#endregion
export { ConcurrentRunner, DeepReadonly, SerialRunner, Task, TaskConfig, TaskLike, TaskStatus };
//# sourceMappingURL=task.d.ts.map