Skip to content

本地与远程执行Backend

沿 Environment、ExecBackend 和 ExecProcess trait 比较本地与远程执行 backend 的选择、能力契约和失败边界。

基于rust-v0.150.0
CodexRustExecutionExecServer

本地与远程执行Backend ​

Codex 不在上层代码里分别维护“本地进程 API”和“远程进程 API”。Environment 选择 concrete backend,ExecBackend 只规定 start,返回的 ExecProcess 再统一 read、write、signal、terminate 和事件订阅。差异集中在连接建立、路径解释、sandbox 能力和断线恢复,而不是调用方的接口形状。

本文承接ExecServer架构、ExecServer连接与握手和ExecServer进程RPC,面向理解 Rust trait、Arc 和异步 transport 的读者。范围是 local/remote backend 的选择与契约,不重复 process RPC 字段和握手消息。测试使用同一组断言分别运行 local 与 remote,用于识别真正共享的保证和不能外推的差异。

1. Environment选择 ​

EnvironmentManager 保存 concrete environments,local environment 由本地 runtime paths 构造,remote environment 由 provider/transport 配置构造。调用方先选 environment,再取得 execution/filesystem/http backend。Environment 将三种能力放在同一个具体环境对象中,确保它们共享同一 remote connection/readiness 语义。

源码位置:codex-rs/exec-server/src/environment.rs :: EnvironmentManager

rust
pub struct EnvironmentManager {
    default_environment: Option<String>,
    pub(super) environments: RwLock<HashMap<String, Arc<Environment>>>,
    local_environment: Option<Arc<Environment>>,
    local_runtime_paths: Option<ExecServerRuntimePaths>,
    http_client_factory: HttpClientFactory,
}

2. 统一Backend契约 ​

2.1 start返回 ​

ExecBackend 只要求 start 返回 StartedExecProcess;sandbox type 是可选元数据,旧 peer 不报告时为 None。调用方不需要知道 child 是在当前进程还是另一台 executor 上创建。

源码位置:codex-rs/exec-server/src/process.rs :: ExecBackend、StartedExecProcess

rust
pub struct StartedExecProcess {
    pub process: Arc<dyn ExecProcess>,
    pub sandbox_type: Option<SandboxType>,
}

pub trait ExecBackend: Send + Sync {
    fn start(&self, params: ExecParams) -> ExecBackendFuture<'_>;
}

2.2 process操作 ​

local 与 remote 都返回 ExecProcess,共享 read/write/signal/terminate 和 subscribe_events。事件 Lagged 时,双方都应通过 read 的 sequence 恢复。

源码位置:codex-rs/exec-server/src/process.rs :: ExecProcess

rust
pub trait ExecProcess: Send + Sync {
    fn process_id(&self) -> &ProcessId;
    fn subscribe_events(&self) -> ExecProcessEventReceiver;
    fn read(&self, after_seq: Option<u64>, max_bytes: Option<usize>, wait_ms: Option<u64>)
        -> ExecProcessFuture<'_, ReadResponse>;
    fn write(&self, chunk: Vec<u8>) -> ExecProcessFuture<'_, WriteResponse>;
    fn signal(&self, signal: ProcessSignal) -> ExecProcessFuture<'_, ()>;
    fn terminate(&self) -> ExecProcessFuture<'_, ()>;
}

3. 本地实现 ​

local backend 是 LocalProcess,在 exec-server 进程内维护 process map,直接调用 codex_sandboxing::spawn_process;返回 LocalExecProcess 作为 trait adapter。

源码位置:codex-rs/exec-server/src/local_process.rs :: LocalProcess::start

rust
async fn start(&self, params: ExecParams) -> Result<StartedExecProcess, ExecServerError> {
    let (response, wake_tx, events) = self.start_process(params).await
        .map_err(map_handler_error)?;
    let sandbox_type = sandbox_type_from_protocol(response.sandbox_type);
    Ok(StartedExecProcess {
        process: Arc::new(LocalExecProcess {
            process_id: response.process_id,
            backend: self.clone(),
            wake_tx,
            events,
        }),
        sandbox_type,
    })
}

本地失败主要来自 argv/cwd/sandbox spawn 和本地资源;没有 transport reconnect 这一层。

4. 远程实现 ​

remote backend 通过 environment 的 transport/client 把同一 ExecParams 发给远端 exec-server,返回远端 process 的代理。上层仍只看到 ExecProcess,但断线会表现为 transport failure;恢复由 LazyRemoteExecServerClient 的 reconnect/session resume 处理,process owner 仍在 executor。

源码位置:codex-rs/exec-server/src/remote_process.rs :: RemoteProcess::start、RemoteExecProcess

rust
async fn start(
    &self,
    params: ExecParams,
    network_policy_decider: Option<Arc<dyn NetworkPolicyDecider>>,
) -> Result<StartedExecProcess, crate::ExecServerError> {
    let client = self.client.get().await?;
    let session = client.start_process(params, network_policy_decider).await?;
    let sandbox_type = sandbox_type_from_protocol(session.sandbox_type());
    Ok(StartedExecProcess {
        process: Arc::new(RemoteExecProcess { session }),
        sandbox_type,
    })
}

该片段展示 remote process 的真实模式:连接对象负责 RPC,environment 负责选择 transport,返回的 Session 再实现 ExecProcess。HTTP、filesystem 和 process 都遵循“能力 facade + environment-owned transport”,但它们的 payload 和恢复状态各自独立。

5. 共享与差异 ​

维度共同契约本地差异远程差异
启动结果StartedExecProcess直接 spawntransport/backend start
进程操作ExecProcess本地 sessionRPC proxy
输出read + events本地 retained queue远端 replay/live events
sandbox typeoptional metadata当前 executor 判定peer 报告或缺省 None
失败typed ExecServerErrorpath/spawn/resourcedisconnect/reconnect/protocol

表格只描述源码已有契约,不代表 local 与 remote 的性能、延迟或所有 sandbox 能力相同。

6. 验证 ​

6.1 同一断言 ​

exec_process_starts_and_exits、exec_process_streams_output 和 exec_process_write_then_read 使用 use_remote: bool 参数化,同一 arrange/action/assert 分别运行 local 与 remote。它证明高层 process contract 一致,不证明 transport 实现相同。

源码位置:codex-rs/exec-server/tests/exec_process.rs :: assert_exec_process_starts_and_exits、assert_exec_process_streams_output

text
cd codex-rs
cargo test -p codex-exec-server --test exec_process exec_process_starts_and_exits -- --test-threads=1
cargo test -p codex-exec-server --test exec_process exec_process_streams_output -- --test-threads=1
cargo test -p codex-exec-server --test exec_process exec_process_write_then_read -- --test-threads=1
cargo test -p codex-exec-server --lib environment::tests -- --test-threads=1

6.2 差异边界 ​

remote 专用测试覆盖 inherited fd 拒绝和 transport disconnect recovery;local 不适用这些断言。它们证明 remote 的额外失败边界,而不是 local 缺陷。

源码位置:codex-rs/core/src/unified_exec/mod_tests.rs :: remote_exec_server_rejects_inherited_fd_launches、codex-rs/exec-server/tests/exec_process.rs :: remote_exec_process_recovers_after_transport_disconnect

text
cd codex-rs
cargo test -p codex-core --lib remote_exec_server_rejects_inherited_fd_launches -- --test-threads=1
cargo test -p codex-exec-server --test exec_process remote_exec_process_recovers_after_transport_disconnect -- --test-threads=1

remote_exec_server_rejects_inherited_fd_launches 需要远程测试环境;没有该 fixture 时测试会按条件跳过,不能把跳过当作远程断言已经执行。

7. 源码排查 ​

text
rg -n "struct EnvironmentManager|LOCAL_ENVIRONMENT_ID|REMOTE_ENVIRONMENT_ID|get_exec_backend" codex-rs/exec-server/src/environment.rs
rg -n "trait ExecBackend|trait ExecProcess|StartedExecProcess" codex-rs/exec-server/src/process.rs
rg -n "use_remote|create_for_tests\(Some|remote_exec_server" codex-rs/exec-server/tests codex-rs/core/src/unified_exec

本地与远程的共同学习主线是 trait contract;真正差异在 environment 选择、transport、路径/继承 fd、断线恢复和 sandbox 能力。下一篇ExecServer并发与集成测试将分析 request admission、并发 lane 和跨 transport 集成测试。