Repository navigation
feat(runtime): unify background service lifecycle, health and recovery - #7816
Conversation
Share cadence, step backoff and wakeup handling across native observation, manager pumps and Lark private delivery. Preserve live pools, futures, cursors and provider-owned authorization and health callbacks during step recovery. Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
…iguration Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
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; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机 / Motivation
需要在同一 Core 进程持续观测原生账号、回收执行结果及投递私有消息的用户。
旧版只在整个 target 外重试;scanner 出错时先退出 pool 并等待进行中的写入,后续扫描无法及时恢复。现在在原有资源作用域内重试单步,继续保留原任务。
旧 scanner 的独立反例失败;修订后四个写入仍阻塞时已恢复扫描,一个 pool 和四个原请求保持不变。manager 只回传一次且保留 probe backoff,原生心跳沿真实 tick 恢复。
本次不增加通用守护进程、调度器、授权或配置仓库,不把线程存活当作 provider 健康,也不声称已经完成本机安装。
当前精确 head 的远端 CI、合并资格与安装后的实际服务/额度读回仍待完成;历史 CI 失败保留,不以新的本地通过自动抹除。
本次独立审查 #7816 的完整九文件 diff,不继承 #7783 的 APPROVE。原先只用线程包装不足以说明共享价值;现在用原版失败、当前恢复和资源身份来判断,不以删行数量作为完成标准。
改动思路 / Approach
复用既有 HostedWorker,让循环、下一次观测等待和错误退避在同一个驱动中执行;租约、pool、future、cursor、journal 与 provider 健康判断继续留在原 owner。Python 只负责线程 IO,没有增加第二个 TS 决策 owner。
本 PR 只交付三个现有 owner 的四条 reconciliation loop 及其可验证恢复。独立原生 wheel 保留不依赖 Core 的小型进程驱动,并与 Core 共用同一单步/健康回调;不将不同 provider 的业务健康强制合成一种状态。
共享的是单步执行、动态观测间隔、显式错误等待与协作停止;provider 自己持有资源作用域。正常 scan 的 wakeup 可以提前,但错误等待使用 stop Event,避免新 hint 造成忙重试。实际健康仍由 provider 的进度与回读证明,原生心跳围绕真实 tick 写入;没有新增一个线程存在就绿色的状态。
具体改动 / Changes
新增驱动方法在原类内使用,四条生产循环直接调用。manager 保留同一个 probe pump,发现与初始化只运行一次;Lark 闭包保留原 pending、fairness、deadline 和四个 Future;原生 Core/独立入口使用同一单步与健康回调。两种原生 host 的小型边界是明确支持的独立安装契约,未复制账号 writer、授权或 journal。
关键代码讲解
HostedWorker.repeat在当前 scope 内执行 step,检查有限正间隔,异常后只按显式 retry 等待。正常 target 完成和无 retry 的失败都终止;任意模型请求不会因此自动获得重放权,四个实际调用者仍用自己的 admission/journal。_reconcile_private在线程池内部调用 repeat,迭代异常不会退出 pool;新反例证明四个写入尚未释放时已恢复扫描,并保持一个 pool、四个原身份、无额外 backlog。close 继续协作 drain。run_executions保留一个 QueuedSourcePump 和 next_probe;step 恢复不会重建它或重复启动时的 provenance discovery。真实原结果回传仍只发生一次。Watcher._observe在已获得的 observer lock 内选择 Core 驱动;独立 wheel/旧 host 运行同一 callbacks。checking/retrying/waiting 来自实际 tick/异常,status 读取不刷新心跳。
规范基准 docs/reference/extensions.md#runtime-responsibilities,spec_revision=789694fa42972db17acd47aa2604b1907060028d,按修改前的契约逐项核对:
- A normal return is terminal:implemented;HostedWorker._run,由 normal completion and failure-without-retry cases 验证。
- retry is off unless that owner explicitly enables it:implemented;HostedWorker.repeat,由 no-retry terminal, explicit backoff and hint isolation cases 验证。
- A live thread does not establish provider health:implemented;Watcher._observe_once/_observe_failed,由 hosted/standalone tick failure, real lock/heartbeat and overdue recovery 验证。
- Keep authorization, election locks, receipts, cursors/backoff:implemented;native lease / QueuedSourcePump / Lark scanner closure,由 five strict native pairs, manager pump retention and live-pool recovery 验证。
- Never use host restart to replay a model request:implemented;four existing reconciliation callers,由 original result once, private no-resend/four-inflight/stop regressions 验证。
- standalone native account wheel:implemented;Watcher standalone fallback,由 fresh installed-wheel contract and standalone/shared observation cases 验证。
对主干的风险 / Risks
最大的反例是“简单 failed-once target 能恢复,真实 target 却先等待四个已接纳写入 drain”,原线程测试会漏掉它。该反例先在精确旧源码复现失败;旧 scanner 与 merged baseline 字节相同。当前生产 start/close 路径通过,修复不终止写入、不重发请求,也不丢弃 cursor 或 journal。
PASS:主干集成后 478 项完整 owner/health/manager/Lark/wakeup/ingress 检查;17 项 Python3.11 检查;33 项聚焦检查;五组原生公开入口的完整 base/head 对照保留所有 API/健康/范围字段,只归一化操作 UUID;独立 installed-wheel 与真实 HTTP/TS/store 打包原生页面。随后提交只澄清 target 与 step 的文档含义,执行源码/测试未改;Ruff、diff、双语 RFC、公开边界及 11 项 premerge 全通过。
旧反例和历史远端失败都保留,不把本地通过称为原平台 CI 通过。当前 head 的 CI 仍是合并门。测试使用实际线程、pool、文件锁、临时 store 与 TS,native/OpenAI/Lark IO 为合成;未发送真实消息、登记账号、调用模型或改变活动 Goal。TypeScript 继续持有领域决策,本次没有新建 Python 规则 owner。
我的整体评价 / Verdict
APPROVE 当前精确 head;无剩余源代码阻塞项。long_horizon 为 preserved:原工作的身份、scope、backoff 和不重放语义保留,修复的是实际后台恢复链;没有 benchmark 效果提升声明。user_experience 为 preserved:沿原页面/会话完成激活、错误恢复和回读,不新增配置或审批。
复用既有 HostedWorker,让循环、下一次观测等待和错误退避在同一个驱动中执行;租约、pool、future、cursor、journal 与 provider 健康判断继续留在原 owner。Python 只负责线程 IO,没有增加第二个 TS 决策 owner。
本 PR 只交付三个现有 owner 的四条 reconciliation loop 及其可验证恢复。独立原生 wheel 保留不依赖 Core 的小型进程驱动,并与 Core 共用同一单步/健康回调;不将不同 provider 的业务健康强制合成一种状态。
未验证范围:远端全部 CI 与本机 Core/App/addon 的实际采用、额度与服务持久回读;这些仍需按已授权顺序完成。新 source 不需要一套全局 provider 健康枚举:不同 provider 的业务可用性应继续由自己的真实证据判断。
English verdict: APPROVE — head 77c95fe. Four real reconciliation loops now share cadence and step recovery inside their existing live scopes; the old scanner failure is reproduced and the correction preserves one pool, four original requests, probe state and native heartbeat. 478 integrated checks pass. Exact-head CI and installed acceptance remain separate gates.
…rogress health Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
…iguration Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
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; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机 / Motivation
需要确认自动观察、结果回传和消息投递是否持续运行,并在中断后恢复的 LoopX 用户。
原来启用设置和后台健康分散在各模块;观察器停止后可能需要用户打开状态页才能恢复。现在由同一宿主核对现有启用状态,停止的已授权观察器会自动恢复,App 可直接读回四项任务的进度。
真实 HTTP 验证了无状态轮询的 15 秒观察器恢复、外部持锁者健康、HTTP 主循环恢复宿主线程,以及失败读回时显示历史记录;策略文件和请求防重放边界保持不变。
范围是现有三个 owner 的四条后台循环及公共健康入口;不增加独立守护进程、授权或配置仓库,不承诺全部业务请求成功,也不把心跳当作成功额度样本。
当前 head 的远端 CI、最终合并资格以及升级后的实际 App、服务和额度读回仍待完成。
审查依据为 docs/reference/extensions.md,固定基线 b000bf35d50b06b671799ad81c49ab7a3ae15a24。本次读取原有 Runtime Responsibilities 的授权、事务、防重放和独立 wheel 边界,再检查新增公共宿主,不以本 PR 改写后的说明反向证明它满足原契约。前端同时按现有 task-first delivery 与 design/populated-page 要求验收。
- A normal return is terminal:implemented;HostedWorker._run,由当前 owner、HTTP、真实进程和负例验证覆盖。
- retry is off unless that owner explicitly enables it:implemented;HostedWorker.repeat,由当前 owner、HTTP、真实进程和负例验证覆盖。
- A live thread does not establish provider health:implemented;Watcher._observe_once/_observe_failed,由当前 owner、HTTP、真实进程和负例验证覆盖。
- Keep authorization, election locks, receipts, cursors/backoff:implemented;native lease / QueuedSourcePump / Lark scanner closure,由当前 owner、HTTP、真实进程和负例验证覆盖。
- Never use host restart to replay a model request:implemented;four existing reconciliation callers,由当前 owner、HTTP、真实进程和负例验证覆盖。
- standalone native account wheel:implemented;Watcher standalone fallback,由当前 owner、HTTP、真实进程和负例验证覆盖。
改动思路 / Approach
现有 HostedWorker 适合线程与进度 IO,新增注册宿主复用它和已有 HTTP 进程循环;TypeScript 统一健康投影,provider 保留事务与授权。
四条真实生产循环共用注册、进度、监督、关闭、HTTP 和 App 读回;专用 profile listeners、原生独立进程入口和 OS 进程监督保留各自 owner。
| 触发 | 实际判断与结果 |
|---|---|
| 已启用的观察器停止 | 宿主重读现有 policy,再由原 owner 创建观察器;不改策略与槽位 |
| 宿主线程意外退出 | 已有 HTTP 主循环恢复其线程;正常完成的一次性工作仍不可重放 |
| 线程仍活着但没有及时进度 | TypeScript 显示 overdue;不杀线程、不重放在途请求 |
| 其他进程持有原生观察锁 | 使用 provider 的持锁健康证据,本地 contender 不构造替代成功 |
| 读取失败或功能关闭 | 显示 unavailable/历史记录或 disabled,恢复仍走原授权 |
上表是源代码分支说明,执行证据见验证矩阵。Python 仅持有进程 IO 与实际回调事实;公共状态分类由 runtime/background_services.ts 唯一负责。BACKGROUND_STATES / background_services_v1 是新的诊断投影词汇,不属于 Goal 状态、队列、peer 生命周期或授权模型。语义 advisory 的一个 const-array 候选已人工确认归属,未据工具输出推断全量语义无风险。
具体改动 / Changes
HostedWorker.repeat / snapshot
repeat 在现有资源作用域内执行单步,按原定间隔或返回的下一次检查时间等待;错误等待只接受 stop,不被普通 wakeup 跳过。开始、成功、失败与 checkpoint 只记录实际执行事实;snapshot 是被动读取。三类 owner 的四条循环直接调用它,一次性 target 的正常返回仍为终态。provider 的错误回调与显式退避保留,宿主没有模型重放入口。
BackgroundServices.reconcile / supervise / recheck / close
注册表只持有现有 owner 回调,不保存第二份启用设置。reconcile 串行核对原意图并隔离错误,supervise 只让已经启动过的宿主保持线程存活,recheck 恢复宿主后再核对 children;关闭先设 stop。快照另用短锁,因此卡住的恢复回调不挡住自己的健康读回。公共 HTTP 和真实 Chat 入口都消费同一组注册信息。
projectBackgroundServices / projectBackgroundTask
这个 TypeScript 模块严格解码布尔、时间与失败次数,再区分 checking、healthy、retrying、overdue、stopped 和缺证据状态。线程仍在运行但超过诊断 deadline 时也会逾期;缺失或未来时间不能构成成功。外部原生观察器的 canonical probe 优先于本地被动 contender。结果由 effect runtime 返回公共 HTTP,前端共用类型并校验 JSON,不另算资格或额度。
BackgroundServicesServerMixin / register_chat_background_services
服务 mixin 接入原有 HTTP 进程循环,轻量恢复宿主线程;三项注册把 native、manager 双 pump、Lark scanner 交给同一生命周期。Native 回调仍重读保存的 policy;新页面 GET 不触发恢复,POST 只接受 recheck 并受原 loopback guard 保护。直接构造 server 的旧 embedder 仍可按既有 owner 属性关闭。没有新队列、配置镜像或 API key owner。
BackgroundServicesSettings
本机设置新增一个入口,按四个实际任务展示状态、最近进度和下次检查;成功/失败记录及原账号、连接设置入口在 disclosure 内。请求失败后保留旧值并明确标为历史,不继续显示当前健康。显式重新检查只调用公共宿主;用户无需重填配置。中文/英文 390px 与桌面整页、展开项和恢复路径已实看,窄屏 select 有完整可访问名称并保持可读。
原生观察仍持原 elected lock,并共用 tick/error 心跳回调;manager 保留同一个 QueuedSourcePump、cursor 和 probe deadline,step 失败不重跑启动发现;Lark 保留原 executor、最多四个 future、公平与 journal。公共 recheck 没有 enable 参数;旧账号与连接编辑器仍独立负责激活。HTTP Origin/Host 拒绝路径未放宽。
验证结果(PASS 与历史失败、远端等待分开):
- PASS Actual lifecycle/HTTP/CORS and observer invariants:
pytest common host/observer/common HTTP/CORS suites。102 passed at final implementation; automatic 15s observer and HTTP-pump host recovery, fresh intent, external election and stopped shutdown covered. - PASS Original manager/Lark/host loops and receipts:
pytest manager roundtrip/execution + Lark runtime + host/common/native suites。240 passed before final adapter changes; current adapter deltas additionally covered by the 102 runtime/HTTP checks. - PASS Latest main native-account compatibility:
pytest native account/observer/common HTTP/worker suites。115 passed after main integration; latest lifecycle changed paths separately covered by current HTTP suite. - PASS Supported minimum Python runtime:
Python3.11 host and common HTTP tests。26 host/native observations passed; later 10 final host/common HTTP cases also passed; overlapping tests not summed. - PASS Malformed, missing, stale and external provider facts:
node --experimental-strip-types --test tests/control_plane_ts/background_services.test.ts; tsc control-plane/dashboard。Four decision-table cases and both type checks passed. - PASS Actual console boot, real backend and UI recovery:
Packaged Chat build; source loopx chat console process in disposable runtime; Ego UI read/recheck/unavailable recovery。Build passed; four tasks, healthy supervisor, HTTP recheck and exit0 at reviewed head; mixed desktop/narrow, expanded/stale/readback inspected. - PASS Repository required validation:
loopx canary premerge --from-git-diff --git-diff-base origin/main。19 selected and six direct checks passed; original module ceiling retained; no exception/budget relaxation. - PASS 当前 live-pool、Lark wakeup 与 ingress 组合回归:49 passed;原执行池、请求和 journal 边界保留。
- PASS 当前真实 loopx chat 入口:四项任务、健康宿主、recheck 和退出码 0;临时运行时无原生凭证或模型调用。
- FAIL → PASS 原始 module ceiling/EOF 检查修复后通过,Chat 模块保持原上限;中间窄屏 CSS 构建错误修好后重新完整打包。未修改预算。
- FAIL → PASS recheck 独立反例在修正前返回 host stopped;新分支实际恢复 host。旧 scanner 的阻塞 pool 反例及当前回归独立保留,不用绿色元数据替代。
- PENDING(诊断) 当前远端 CI 尚未完成。未归因的失败保持 unresolved,不用旧 head 或本地通过宣称远端成功;合并仍需独立 ready 读回。
对主干的风险 / Risks
主要风险是把“扫描进度正常”误当“所有业务请求成功”,以及恢复时跨越已有授权或重复在途工作。当前宿主只调用原 owner 的幂等生命周期入口,重读原启用状态;provider 的 slot allowlist、订阅优先/API 兜底、冷却、原生切换事务、source grant 和 journal 仍独立生效。超时是诊断,线程存活不是成功;原生 probe 未提供的成功时间保持空值。
公共目录和健康事实仅在进程内保存,HTTP 输出只有预先注册的公开 task id、时间与诊断字段,不包含路径、凭证、账号、消息和异常详情。快照与生命周期锁分开,卡住的 reconciler 不阻塞自己的健康读回。关闭先设 stop,再关闭注册 owner;已有一次性目标与 journal 的终态不因监督而重放。独立 wheel 保留 Core-free 入口,旧 provider 不支持探测时只能 unverified。
可以回退公共宿主/API/UI 这一组改动,原策略、密钥和请求回执不用迁移。当前真实进程验证是临时空运行时,native/queued 外部 IO 为合成;不等同于安装用户的服务、额度或长时间运行 SLA。当前 head 的远端 CI、最终合并资格以及升级后的实际 App、服务和额度读回仍待完成。
我的整体评价 / Verdict
APPROVE。现有 HostedWorker 适合线程与进度 IO,新增注册宿主复用它和已有 HTTP 进程循环;TypeScript 统一健康投影,provider 保留事务与授权。 四条真实生产循环共用注册、进度、监督、关闭、HTTP 和 App 读回;专用 profile listeners、原生独立进程入口和 OS 进程监督保留各自 owner。 这是有真实调用者和端到端读回的公共后台能力,不再只是给每个线程换一层包装;下一项同类服务只需在原 owner 边界提供生命周期与观察适配。更大的 profile listener/OS supervisor 统一暂未进入这次范围,现有专用语义有真实消费者,保留不会造成第二份授权规则。
已实看整个设置页:四项任务的正常、重试、逾期、关闭状态在默认视图可扫读;检查历史及原配置入口留在展开项。窄屏修正分类选择器后,长英文名称和展开记录均可读。
仅验证合成私有运行时的 packaged 页面;已安装 App 与真实账号读回仍待合并升级。
我检查了 PR 中实际 packaged 页面:默认四项混合状态、完整展开记录、390×844 窄屏和下方区域,以及不可用后历史状态再恢复的路径。没有通过隐藏后续项目或缩小正文换取首屏;英文分类选择器的拥挤问题已修复。状态历史与必要帮助在展开项,默认页面保留主要结果和重新检查操作。自动恢复不要求额外的人为导航、复制配置或确认;可选查看与恢复仍受原授权控制。
English verdict: APPROVE — head 063b361e62ea11382e1ccea76de35f662b5e4e01. Shared lifecycle, observed progress, typed health and the App journey are source-validated with no blocking finding. Exact-head CI/readiness and installed verification remain separate pending gates.
|
当前 head
祖先提交 没有修改源码、断言、等待时间或冻结预算。原失败证据保留。已尝试只复验这个 job,但 GitHub 因整轮 workflow 仍在运行而拒绝( |
|
按本次维护者授权,此次交付不等待远端 CI;仅对这次合并生效。 精确 head: 已有 CI 失败保留在前述观察记录中;其触发原因未确认,未改断言或预算。当前能力 owner 以 |
Problem and result
Enabled background features had separate lifecycle and health readback. A failed or stopped observer could stay behind an enabled setting, and a scanner failure could unwind its in-flight executor before it resumed. This change delivers a shared process-scoped background host, used by four existing loops across three owners, with a usable Settings → Background services journey.
Shared ownership
HostedWorker.repeatowns cadence, stop-aware waits, error backoff and raw progress; steps run inside their existing lease, pump or executor scope.BackgroundServicesregisters owners, reconciles their current intent at startup/every 15 seconds, isolates failures and fences shutdown. The existing HTTP pump can restore an unexpectedly exited host thread. No additional daemon or persisted enable configuration is introduced.The standalone account wheel remains Core-free. Existing allowlists, subscription-before-API selection, cooldown, native switching transactions and ambiguous-write/no-resend fences remain with their original owners. Other specialized listeners and OS process supervision retain their existing owners; this is the shared lifecycle/diagnostics path for the four registered loops.
Validation
Tested head:
063b361e62ea11382e1ccea76de35f662b5e4e01. Latest targetmainwas integrated before qualification.loopx chatconsole entrypoint in a disposable empty runtime: four tasks registered, health and recheck succeeded, clean exit code 0; no model call or native credential was used.Installed production App/service/quota readback remains after authorized merge and upgrade. For this maintainer-authorized delivery, remote CI is not awaited. Required local validation, the published exact-head source review and capability-owned merge-readiness remain required. Previously observed CI failures remain recorded; this changes no test assertion or budget.
Visual evidence
Packaged frontend with the real common HTTP API and three production owners; disposable synthetic native/queued IO. Captures show mixed retry/healthy/overdue/disabled states, narrow detail and stale-read states, then recovered observations. They are not installed-account screenshots.
The first viewport answers which task needs attention. Success/failure history and original feature settings stay in disclosures. Desktop 1440×1000 and narrow 390×844 were inspected, including long English task names, expanded records, unavailable reads and the lower page. No horizontal overflow; the mobile category remains readable. A native progress heartbeat is never presented as a successful quota sample.