/** * Workflow Extension — Run Runtime * * 聚合内运行时资源(仅 status==="running" 时存在)。技术资源聚合, * Engine 层类型,持 WorkerHandle / ConcurrencyGate 具体类(D-12 不造 interface)。 * * 职责:封装一次 running-segment 的所有技术资源(worker 线程 + 并发信号量 + * abort controller),统一 release 入口(AC-2:单 release 替代多 boolean flag)。 * * 一次性生命周期(G3-001):runtime 释放后不再复用——AbortController 一次性 * 语义决定 controller 无法跨释放复用,gate 队列也在 worker 重跑脚本 + * callCache replay 时清空无影响,所以整个 RunRuntime 重建。唯一注入路径: * assignRuntime(runWorkflow 创建)与 replaceRuntime(error-recovery 崩溃重试)。 * * 参考:domain-models.md §10、clarification.md G3-001。 */ import { ConcurrencyGate } from "../concurrency-gate.ts"; import { WorkerHandle } from "../worker-handle.ts"; /** * release mode 枚举——调用方表达意图。 * * 一次性生命周期后唯一语义:terminal(终局释放,worker + controller 全释放, * runtime 即被调用方丢弃)。原 "pause" 值已随 pause/resume 生命周期删除(F8) * ——release 后不存在「保留待恢复」的中间形态。 */ export type ReleaseMode = "terminal"; // ── RunRuntime ─────────────────────────────────────────────── export class RunRuntime { /** Worker 线程句柄。 */ readonly worker: WorkerHandle; /** 并发信号量。 */ readonly gate: ConcurrencyGate; /** per-running-segment AbortController(一次性,无法复用——G3-001)。 */ readonly controller: AbortController; /** Run 级墙钟时间预算计时器(spec.budgetTimeMs > 0 时由 lifecycle 调度, * 到期 abortRun time_limited)。release 时清理,避免 abort/replaceRuntime * 后孤儿计时器仍触发(rebuildRuntime 会重排一个全新的计时器,旧的不应残留)。 */ readonly timeBudgetTimer?: ReturnType; /** 防止 release 重复执行(幂等)。 */ private released = false; constructor( worker: WorkerHandle, gate: ConcurrencyGate, controller: AbortController, timeBudgetTimer?: ReturnType, ) { this.worker = worker; this.gate = gate; this.controller = controller; this.timeBudgetTimer = timeBudgetTimer; } /** * 释放所有资源:terminate worker + abort controller。 * * 幂等——重复调用安全(第二次起 no-op,released flag 守卫)。 * 调用后此 RunRuntime 应被调用方丢弃(WorkflowRun.runtime = undefined), * 崩溃重试时由 replaceRuntime 注入新实例(G3-001)。 * * worker.terminate 本身幂等,controller.abort 本身幂等 * (重复 abort 无副作用),但 released flag 让本方法语义更明确: * 「释放过一次的 runtime 不再释放第二次」。 * * @param mode terminal —— 终局释放(唯一值,保留参数为调用方语义显式化) */ release(_mode: ReleaseMode): void { if (this.released) return; this.released = true; // 清理 run 级时间预算计时器——abort/terminate/replaceRuntime 后它不应再触发 // (rebuildRuntime 会重排全新计时器;孤儿触发会把已终态的 run 误转 done)。 if (this.timeBudgetTimer) clearTimeout(this.timeBudgetTimer); // worker.terminate 异步但幂等——不 await(release 是同步签名,调用方 // 不应被底层线程关闭阻塞;worker 收到 terminate 后自行清理)。 void this.worker.terminate(); // controller.abort 触发 listener(kill agent subprocess、中止在飞调用)。 // 一次性语义——已 aborted 的 controller 重复 abort 无副作用。 this.controller.abort(); } /** 是否已 release(测试 + 诊断用)。 */ get isReleased(): boolean { return this.released; } }