TurnEnvironmentSnapshot 不是环境变量字典。它保存这次 Turn 选中的执行环境、cwd、workspace roots、Shell 和 ShellSnapshot,以及环境尚在启动还是已经 Ready。它解决的是本地/远端执行位置的一致性。
从配置 selection 到可执行 TurnEnvironment
TurnEnvironmentSelection 只有 environment id、cwd 和 workspace roots。ThreadEnvironments 用 EnvironmentManager 解析 id,并异步等待环境 ready:本地直接采用本地 Shell;远端读取 EnvironmentInfo 中的 shell 描述;随后并发构建 shell snapshot。
async def resolve_selection(selection):
env = environment_manager.get(selection.environment_id)
if env is None:
return SKIP_UNKNOWN
await env.wait_until_ready()
shell = (await env.info()).shell if env.is_remote else local_shell
turn_env = TurnEnvironment(env, selection.cwd,
selection.workspace_roots, shell)
turn_env.shell_snapshot = spawn_shared(build_shell_snapshot(turn_env))
return turn_env
ThreadEnvironments 使用 ArcSwap 发布 selection 列表。更新时按 environment id 去重,保留第一次出现;完全相同且未失败的 selection 复用旧 resolution;未知 id 记录 warning 后跳过;改变 cwd/roots 会启动新 resolution,但若 Environment Arc 相同,可以复用 connection listener。
被逻辑移除的 listener 会立即 abort。仅依赖 Arc drop 不够,因为旧 ArcSwap reader 可能长期持有旧 snapshot,使已经移除环境继续发送连接事件。
Blocking 与 non-blocking snapshot
Blocking 模式等待每个 selection resolution 完成;non-blocking 模式只 peek 当前结果,尚未完成的记录为 Starting。失败项不会进入 snapshot。Ready 与 Starting 都保持用户选择顺序。
TurnContext 捕获后,refresh_readiness() 只检查这些 Starting future 是否已经完成:成功则提升 Ready,失败则移除。它不会读取 ThreadEnvironments 后来发布的新 selections。
def refresh_readiness(old_snapshot):
result = []
for state in old_snapshot.in_selection_order:
if state.is_ready:
result.append(state)
elif state.resolution.peek() == SUCCESS:
result.append(Ready(state.resolution.value))
elif state.resolution.peek() == PENDING:
result.append(state)
# failed: omit
return TurnEnvironmentSnapshot(result)
primary、local 与 single_local 的语义
primary() 是选择顺序中的第一个 Ready 环境,不保证是 local;local() 查找第一个非远端 Ready 环境。某些只能在单一本地 cwd 上成立的优化使用 single_local_environment:必须没有 Starting、恰好一个 Ready 且它是 local。只看 ready count 会误把“另一个远端仍在启动”当作单环境。
连接状态 Event 为什么 id 为空
Environment connection listener 是 Thread 级后台观察者,不属于某个 Submission 或 Turn,因此发送 EnvironmentConnected/Disconnected 时 Event id 为空字符串。客户端应按 environment_id 和事件类型处理,不能把所有 Event 都强行挂到 Turn ID。
评论
登录后即可评论