Repository navigation
fix(runtime): supervise optional cache flush after effect drain - #6468
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=xhigh
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewed head: ee05c5e98b15ce7b90445150fb46bfc35d338835。当前共用作者账号以 COMMENTED 发布独立评审。
动机
执行连续 CLI 工作的维护者,需要已完成业务的后台运行进程正常退出,让后来命令可以恢复或启动下一实例。 旧版在业务 journal 已经写入后,最终缓存写盘阻塞仍会让进程和定位文件一直留下;当前版先排空已接纳业务,再有界监督可选缓存并只清理原进程的定位文件。 相同隔离真实进程反例中,旧版阻塞缓存六秒后仍存活,当前版保留完整业务写入并退出;缓存关闭和正常缓存的业务结果保持。 本轮验收缓存退休故障的有界修复,不认证原生 Windows、最小 Node、完整 hosted CI、原间歇故障根因或持续运行尾延迟。
改动思路
同步缓存调用可阻塞主线程的计时器,因此同进程 worker 承担独立监督;排空与定位文件锁仍复用原 owner,不另建业务或授权状态。 本 PR 交付业务已结算之后的缓存失败退出,保留 handler、receipt、替代定位文件与缓存关闭路径;平台及持续资格仍由现有运行验证工作承接。
最强反对理由是强制退出可能先于业务落盘,或者同步写盘晚返回时把正在清理的 worker 杀掉。把 timeout 放主线程不能解决阻塞本身;一律关闭缓存则丢失健康缓存收益。当前选择仅在已结算进程内增加短命监督线程,并在同一现有模块提取一次定位文件清理。业务 drain、并发锁和精确身份判断仍为不变量;缓存只是可丢弃的 provider IO。未增加 Python 决策、通用框架、用户确认或新配置入口。
具体改动
完整6路径 +273/-32:缓存 owner 新增监督和共享清理,server 删除旧内联清理并在排空后调用;三项测试/故障诊断覆盖实际缓存、写入和退出,指南新增20行中英说明。未改 frontend/Lark/CLI 操作入口、权限、数据 provider 或业务 receipt。预加载的原私有目录、禁用和 coverage 判断保持;新 worker 自身禁用缓存。
关键代码讲解
locatorRetirement:26 在 flush 前加载原 IO owner,两条路径共用原 mutation lock;读取 token、PID、fingerprint 全部匹配才删除,替代实例的定位文件保留。superviseCache:57 先读好清理依赖并报告 ready,收到 flush 信号后才启动一秒计时;只有 CAS 从 FLUSHING 成功改成 RETIRING 的线程取得清理权。retireRuntime:71 在缓存关闭时直接普通清理;正常 flush 完成则终止监督并原样清理。启动不可用、抛错或超时才进入已结算进程的强制退出。若同步调用晚返回且 worker 已取得清理权,主线程等待它,不会把持锁线程终止。
依据变更前 docs/development/testing-and-quality.md,固定版本 3c681f1132fe719e01f75e5a41bfd854dfa9e346:Isolate the managed Effect process as well as the data 的隔离/先 settle 后 stop、Local Validation Environment 的源码解释器来源、Risk-Based Review 的真实边界与失败限定均 implemented。新增指南不是独立验收依据。原 server close 的 pendingRequests 等待位于 retireRuntime 之前,断开客户端不减少已接纳 handler 的寿命。
对主干的风险
我以同一私有脚本分别运行固定 base/current 的真实 Node 服务:业务写入被真实文件锁挡住,客户端超时,随后请求 shutdown;0.6秒后两端仍活着、journal尚不存在。释放锁后四组 journal 都逐字段精确匹配。正常及缓存关闭两端均退出;blocked-cache 的 base 在六秒后仍活着且 locator 保留,当前全部消失;throwing-cache 的 base 虽退出但留旧 locator,当前完成清理。只向可选 flush 调用注入故障,业务 IO、结果运输和锁保持真实,结束时仅清理自有隔离 PID。
当前 source 集成90pass/0skip;缓存 TS16pass/0skip,固定base原9pass。实际缓存字节、同路径编辑/腐败、禁用/coverage、worker不可用、阻塞/抛错及晚返回/替代 locator 均覆盖。晚返回反例持锁超过监督期限后发布替代定位文件,原进程等锁释放才退出,替代内容保持。普通 noneditable wheel 的相同90用例也通过;包内两个 TS owner、IO和Python运输四个blob与head完全一致。第一次构建因本地旧frontend bundle过期失败,按正常build重建并验证后重试成功,失败记录保留;没有把重建当作 UI 改动或正式安装升级。
TypeScript全源码compiler通过;advisory先于full语义检查,原生canary4direct+11selected/executed全过,0失败/skip/timeout/manualhold,六条公开路径扫描干净。单独的content_digest消费者检查在base/head均17tests、16pass/1fail,缺同一个direction_authority pin;完整归一化断言签名相同,oracle、consumer和digest owner三个blob相同,属既有不相关失败,#6431仍负责。没有声称full TS suite全绿,也未查询/轮询/等待/启动 hosted CI。
强制退出可能丢失可选缓存;一秒是flush额度,另有一秒startup额度,不涵盖定位锁、存储及OS调度。作者公布的73–79ms对11–21ms退出开销只是其描述样本,本轮未独立计时,也不据此认定native Windows、Node22最小版、长期尾延迟或原间歇故障根因。这些资格不由故障注入或一个通过批次替代。
我的整体评价
APPROVE,当前限定路径无阻塞finding。long_horizon/user_experience在已完成业务后退出与后续实例恢复上改善,原业务结果和替代定位文件所有权有真实正反例;未新增用户操作步骤。future-facing pass已在既有typed owner删除两条路径的重复清理,局部原子状态/worker tag属于local_only,无新共享协议。保持这个有界边界即可,不需扩大框架或关闭整个运行资格计划。本COMMENTED结论不授merge或bypass权限;closeout/readiness分别回读,原生平台、完整hosted与持续资格仍明确未验证。
English verdict: APPROVE - ee05c5e; immutable-base/head real servers preserve the disconnected admitted journal while blocked-cache retirement changes from a live process/stale locator to clean owned retirement. Current source90, ordinary installed-wheel90 and cache16 pass, including late-fence replacement and disabled parity. The identical baseline digest-consumer failure is retained; native Windows/minimum Node/full hosted CI and sustained latency are not independently qualified. No merge authority is granted.
Goal And Delivered Outcome
A settled Effect runtime can remain alive indefinitely when Node's synchronous compilation-cache flush blocks. A disposable real-server test reproduces this after the accepted journal write completes. This proposal supervises optional cache persistence after all admitted handlers drain, then retires only the locator owned by that runtime. Base:
mainat3c681f1132fe719e01f75e5a41bfd854dfa9e346.Author Declaration
docs/development/testing-and-quality.mdat the stated base, managed Effect-process isolation.retireRuntime; real journal/result and negative IO casesScope And Continuation
effect_runtime_compile_cache.tsowns supervision and shared locator cleanup; the server calls it only after drain. Python transport and authority providers are unchanged. The worker shares the runtime PID and has its own cache disabled. An atomic ownership transition prevents the main thread from terminating a worker that has started fenced cleanup when a slow flush finally returns.Default behavior changes for cache-enabled retirement: allow one second for cache persistence, with a separate one-second worker-startup allowance. Successful flush retains the normal exit path. Failed/stalled persistence or unavailable supervision cleans the owned locator and forcefully exits the already settled process, bypassing Node's automatic exit flush. Optional cache entries may be lost. Locator lock/storage waits and OS scheduling are outside this allowance. Cache-disabled retirement uses ordinary cleanup without supervision. See Node v24.21 cache semantics.
Cost disclosure: matched, sequential macOS/Node 24 samples after local builds/tests completed observed warm shutdown at 11–21 ms on the immutable base and 73–79 ms on this head (four samples per arm). Cold samples were 23 ms and 81 ms. This adds retirement startup cost for liveness; these descriptive samples qualify neither Windows nor tail latency.
The bounded related refactor extracts the existing locator cleanup once, within its existing owner, for both paths. Local atomic states and the worker mode tag are internal synchronization vocabulary, not a new persisted/caller protocol or capability.
This is a completed source proposal. Natural Windows lifecycle and minimum Node execution now pass within the scopes below. Exact-head independent source review is now recorded as APPROVE below; complete hosted CI and release qualification remain open. Existing full-CI work in #6458 and #6463 is not closed by this proposal. No manual hosted workflow, runner-capacity change, merge or installed-product upgrade was performed.
Validation
ee05c5e98b15ce7b90445150fb46bfc35d338835.tests/control_plane/test_effect_runtime_integration.py: all 90 cases; drain, disconnect/shutdown, replacement/fence, restart, receipt and permission/error cases.tests/control_plane_ts/effect_runtime_compile_cache.test.ts: 16 cases, including real cache bytes and late-flush/locator-lock race.doctor --restart-runtime --installation-only, read backstopped, and remove their own locator. Module provenance verified.npm run typecheck:control-plane, configured mypy, repository Ruff, diff advisory before full semantic smoke, six-path public scan and DCO.npm run test:control-plane: 4685 passed, 39 skipped, onecontent_digest_single_ownerconsumer-pin failure fordirection_authority.ts. Identical targeted command fails on immutable base and head with identical fixture bytes. Existing #6431 owns that repair; this failure is retained.test_extension_cli_keeps_legacy_machine_state_without_a_global_registryfailure (extension revision history is invalid), matching existing #6463. Subsequent steps are skipped; the whole job remains failed.direction_authority.tsconsumer-pin failure; #6431 remains its existing repair. No baseline exemption.stopped, Node 22.22.3 and SQLite authority qualification. Module provenance verified. The separate minimum-Node CI also passes typecheck and its 18 admission/lease cases; those 18 are not the cache suite.873e8fee87c04561ce58e0bbbd565da220a49f4d; it is absent from this original CI checkout. The timeout's cause is not independently established here.Natural CI provenance: actual merge checkout
b426f6d0ee3be9a55be4142f2da3054450f0f1a2has the stated author head and base as its two parents; every changed runtime/test source blob equals the author head. Latestmainnow contains the browser-fixture repair above, with no intervening runtime-owner source changes. No new source commit, manual rerun or merge was made merely to reproduce known upstream failures. One passing Windows lifecycle batch does not establish the original intermittent cause or sustained qualification.Earlier local failures were corrected and retained in local validation records: new fixture parameter omitted at a direct call, test-environment typing, and stale frontend bundle during wheel construction. The ordinary frontend build and wheel were rebuilt and verified; no UI source change is included.
Frontend / Visual Evidence
Boundary Checklist
Independent source review and remaining platform gap
The published exact-head independent review concludes APPROVE for
ee05c5e98b15ce7b90445150fb46bfc35d338835. It uses aCOMMENTEDreview because the agents share the author account. The reviewer independently exercises immutable-base/current real processes with an admitted journal write, client disconnect, shutdown, a blocked or throwing optional flush, and replacement-locator fencing; current source, ordinary wheel and cache tests pass within the reported scope. The review explicitly does not qualify native Windows, minimum Node, complete hosted CI, sustained latency or the original intermittent cause. The earlier author-side Node 22 and natural Windows subset evidence above remains separate.A later natural Windows job for #6474 again reports 199 passed, 19 skipped, 1 failed at the original decode-change retirement case. Its five runtime/diagnostic/test source files match its unmodified main base; it does not include this proposal's retirement implementation. The replacement locator remains after the two-second wait, with
flush_enterand no observed replacementflush_donein the bounded diagnostic. This keeps the original platform/root-cause gap concrete; it is neither a failing test of this proposal nor proof of the complete cause. No additional hosted run was started to obtain it.独立评审已对本精确提交给出 APPROVE,并用真实进程正反例验证业务排空、缓存故障退出与替代实例保护。此结论限定于源码修复;原生 Windows、原间歇故障根因、完整 CI 和持续资格仍未关闭。后续主干代码的 Windows 再现不包含本修复,不能据此认定本提案回归或已解决该平台问题。未新增源码提交、CI rerun、安装或合并。