feat: cloud 门禁/超时/成本/沙箱收敛为单一判定源
- 新增标准库叶子层 timeouts/gates/quota/sandbox_policy: 审批 3600 与单轮 600 各有名常量与环境覆盖层,已建项 expires_at 永不重算;目录/控制/合并状态门禁统一判定, 目录违规无任何覆盖参数;配额取数与比较唯一来源 (USD 先于无价、命中均为 >=、无价只计 actual 行); /tmp 隔离矩阵与失联清理判定纯函数化。 - 调用点委托:server/worker/automations/auto_memory 的 配额 SQL 与比较、server/tree/marker 的目录解析、 marker 的控制门、sandbox 的任务容器名正则、两处 300 秒 陈旧阈值默认值均收敛,别名与错误文案不变。 - 统一两个 P0 口径分歧:服务端无价计数由全部 usd IS NULL 行改为 actual-only;显式不限额用户在服务端准入亦不受 无价上限约束(与 worker 运行时一致)。 - 不新增门禁种类与 record 模式(主线无此实现);不改 skill_seed/skills/SKILL.md;不改 v1.1 契约与分支保护。 - 新增 test_arch_converge.py 18 项。
This commit is contained in:
1 parent
2720acef46
commit
41e8c98512
16 files changed
+1068
-301
No files matched your search
@@ -0,0 +1,88 @@
|
||||
"""沙箱与清理的单一口径(纯函数层,只依赖标准库)。
|
||||
|
||||
收敛前分层口径散在各处注释里,本模块把它钉成可单测
|
||||
的函数,调用点只传事实、不再各写一套:
|
||||
|
||||
1. /tmp 隔离矩阵(Docker 外层 vs 宿主 bwrap 内层):
|
||||
- Docker 执行器:容器 /tmp 与 /var/tmp 固定为 tmpfs
|
||||
(sandbox.build_run_command 在额外挂载之后追加
|
||||
--tmpfs,且 /tmp 目标的额外挂载在解析时即被拒绝),
|
||||
容器内 /tmp 绝不落在宿主 /tmp。
|
||||
- 宿主 bwrap / 本地执行器:/tmp 不隔离。宿主级 bwrap
|
||||
的 /tmp 会落到宿主 /tmp 上,内层 codex 的 bwrap
|
||||
--proc 挂载亦不受本仓库控制——本模块只如实标注,
|
||||
绝不宣称“内层沙箱已修”。
|
||||
- 任务容器名正则(codex-<32 位 hex 任务 id>)此前只
|
||||
活在 sandbox.cleanup_stale_containers 的注释与正则里;
|
||||
现收为 TASK_CONTAINER_RE,sandbox 直接复用它。
|
||||
清理绝不按 "codex-" 前缀删:基础设施容器
|
||||
(如 codex-postgres)名字不匹配正则,永远不被删。
|
||||
2. 失联清理判定(cleanup_decision):worker
|
||||
_reap_kill_requests 的状态与心跳两道门——任务必须
|
||||
已是 interrupted,且心跳停滞超过阈值(心跳取
|
||||
COALESCE(last_heartbeat, updated_at),与
|
||||
server.sweep_stale_tasks 同口径;无心跳时间戳时按
|
||||
已停滞处理,与 _reap 旧代码的 fall-through 一致;
|
||||
恰等于阈值时不杀,旧代码是 hb >= now - threshold 即
|
||||
跳过)。请求 pending、执行器有 kill_container、容器
|
||||
名由任务 id 派生这三道门仍在 worker 侧,不进本层:
|
||||
本层只判“该不该杀”,不执行杀。
|
||||
3. Worker 寻址(worker_address):workers 注册表只有
|
||||
worker_id 一列身份,默认形为“主机名-进程号”
|
||||
(worker.py,未给 --worker-id 时)。本函数从该串
|
||||
派生 (host, pid):取最后一个连字符后全为数字的一段
|
||||
作 pid,否则 pid 为 None。注册表本身不加 host/pid
|
||||
列——加列需 PG 迁移与 test_p2_migrations 登记,超出
|
||||
本轨收敛范围;寻址先用派生函数,不动表结构。
|
||||
单一状态来源仍是:workers 表(注册与心跳)+
|
||||
tasks.last_heartbeat(陈旧判定)+ kill_requests
|
||||
(清理意图),三者缺一不可,不得另起一套状态表。
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
TMPFS_PATHS = ("/tmp", "/var/tmp")
|
||||
TASK_CONTAINER_RE = re.compile(r"^codex-[0-9a-f]{32}$")
|
||||
|
||||
|
||||
def tmpfs_isolated(executor_kind, path):
|
||||
"""某执行器下某路径是否走 tmpfs 隔离:(isolated, reason)。"""
|
||||
if executor_kind == "docker" and path in TMPFS_PATHS:
|
||||
return True, "docker --tmpfs 隔离,容器内路径不落宿主"
|
||||
if executor_kind == "docker":
|
||||
return False, "docker 下仅 /tmp 与 /var/tmp 走 tmpfs"
|
||||
if executor_kind in ("host-bwrap", "local"):
|
||||
return False, "宿主 bwrap / 本地执行器 /tmp 不隔离,会落宿主"
|
||||
return False, "未知执行器,按不隔离处理(fail-closed 口径)"
|
||||
|
||||
|
||||
def cleanup_decision(status, heartbeat_ts, now, threshold_seconds):
|
||||
"""失联清理判定:放行回 (True, reason),否则 (False, reason)。
|
||||
|
||||
status 必须为 'interrupted';心跳停滞须严格超过阈值
|
||||
(恰等于阈值不杀);heartbeat_ts 为 None 时按已停滞
|
||||
处理(与 _reap 旧代码一致:无时间戳不阻拦收殓)。
|
||||
"""
|
||||
if status != "interrupted":
|
||||
return False, "任务不在 interrupted,不杀(防复活任务被旧请求误杀)"
|
||||
if heartbeat_ts is None:
|
||||
return True, "无心跳时间戳,按已停滞处理"
|
||||
try:
|
||||
age = now - float(heartbeat_ts)
|
||||
except (TypeError, ValueError):
|
||||
return False, "心跳时间戳不可解析,不杀"
|
||||
if age > threshold_seconds:
|
||||
return True, "心跳停滞 %.0f 秒,超过阈值 %s 秒" % (
|
||||
age, threshold_seconds)
|
||||
return False, "owner 可能还活着(心跳 %d 秒前),留待下轮" % age
|
||||
|
||||
|
||||
def worker_address(worker_id):
|
||||
"""从 worker_id 派生 (host, pid):pid 取末段纯数字,否则 None。"""
|
||||
if not worker_id or not isinstance(worker_id, str):
|
||||
return "", None
|
||||
if "-" in worker_id:
|
||||
host, _, tail = worker_id.rpartition("-")
|
||||
if host and tail.isdigit():
|
||||
return host, int(tail)
|
||||
return worker_id, None
|
||||
Reference in new issue
Block a user