IronClaw 深度剖析(五):任务调度与并行执行——多 Job 并发模型
系列导读:IronClaw 是一个基于 Rust 的 AI Agent 执行平台,采用多层级 Docker 沙箱架构实现安全隔离。本系列从架构到实现逐步拆解其核心设计。本篇聚焦任务调度系统——从三层调度模型到 Orchestrator/Worker 模式,从 Docker 沙箱生命周期到自修复机制,揭示 IronClaw 如何管理数百个并发 Job 的复杂调度场景。
- 仓库地址:https://github.com/nearai/ironclaw
- 分析版本:v0.28.2(main 分支)
一、为什么任务调度是 Agent 系统的核心挑战
当 AI Agent 从"单次对话工具"演进为"7×24 小时自主执行的生产系统"时,任务调度成为决定系统可靠性的关键基础设施。一个生产级 Agent 平台需要同时应对以下挑战:
| 挑战 | 典型场景 | IronClaw 的解决方案 |
|---|---|---|
| 多租户隔离 | 不同用户的 Agent 不能相互干扰 | Docker 容器级隔离,每 Job 独立容器 |
| 资源竞争 | 某个 Agent 耗尽 CPU/内存 | cgroup 限制(2GB 内存 / 1024 CPU shares) |
| 迭代安全 | Agent 陷入无限循环 | 服务器端强制 max_iterations 上限 500 |
| 故障恢复 | 容器崩溃后资源泄漏 | SandboxReaper + AutonomousRecovery 双保险 |
| 凭据安全 | API Key 泄露风险 | 按需获取 /credentials,不注入环境变量 |
IronClaw 的调度系统通过三层调度模型和Orchestrator/Worker 架构解决了这些挑战。让我们从架构全貌开始,逐层深入。
二、三层调度模型:从宏观目标到微观执行
IronClaw 的调度系统采用清晰的三层架构,将"长期目标"、"线程生命周期"和"运行时分发"解耦:
graph TB
subgraph Layer1["Layer 1: MissionManager
长期目标管理"]
M1["Mission
OneShot / Interval / Cron"]
M2["MissionStatus
Active / Paused / Completed"]
M1 --> M2
end
subgraph Layer2["Layer 2: ThreadManager
线程生命周期管理"]
T1["Thread
Chat / Background / Routine / Sub"]
T2["ThreadState
Created → Running → Waiting / Completed / Failed"]
T3["ThreadTree
父子线程关系追踪"]
T1 --> T2 --> T3
end
subgraph Layer3["Layer 3: Dispatcher
运行时 Lane 分发"]
D1["RuntimeAdapterRequest"]
D2["ExtensionPackage + CapabilityDescriptor"]
D3["ResourceReservation"]
D1 --> D2 --> D3
end
Layer1 -->|"Mission 触发"| Layer2
Layer2 -->|"Step 执行"| Layer3
Layer3 -->|"ActionResult"| Layer2
Layer2 -->|"MissionCompleted"| Layer1
style Layer1 fill:#e1f5fe
style Layer2 fill:#f3e5f5
style Layer3 fill:#e8f5e9MissionManager(crates/ironclaw_engine/src/runtime/mission.rs)位于最顶层,负责管理长期运行目标。Mission 按照 OneShot、Interval 或 Cron 的节奏触发,自动在预定时间点生成 Thread。
ThreadManager(crates/ironclaw_engine/src/runtime/manager.rs)是调度的核心枢纽。它将 v1 版本中分散的 Session、Job、Routine、Sub-agent 等概念统一为单一的 Thread 原语,通过 ThreadType 区分用途,通过 ThreadState 状态机管理生命周期。
Dispatcher(crates/ironclaw_dispatcher/src/lib.rs)是最底层的运行时分发层。它的设计哲学是"组合而非解析"——不自己解析 Extension Manifest、不实施沙箱策略、不预留预算,仅将已经过验证的 Capability Descriptor 路由到对应的运行时 Lane。
三、Orchestrator/Worker 模式:分布式执行的核心架构
IronClaw 采用经典的 Orchestrator-Worker 模式将控制平面与执行平面分离:
graph LR
subgraph Orchestrator["Orchestrator (src/orchestrator/)"]
API["api.rs
~800行"]
AUTH["auth.rs
~400行"]
JM["job_manager.rs
~1542行"]
RP["reaper.rs
~969行"]
MOD["mod.rs"]
end
subgraph Worker["Worker (src/worker/)"]
WA["api.rs
~300行"]
PLLM["proxy_llm.rs
~400行"]
WC["container.rs
~350行"]
WJ["job.rs
~500行"]
ACP["acp_bridge.rs
~400行"]
CLB["claude_bridge.rs
~500行"]
AR["autonomous_recovery.rs
~300行"]
end
subgraph Sandbox["Docker Sandbox"]
DC["Worker Container
沙箱执行环境"]
end
Orchestrator -- "HTTP/API" --> Worker
Worker -- "沙箱创建请求" --> Sandbox
Sandbox -- "日志/结果返回" --> Worker
Worker -- "状态/心跳上报" --> Orchestrator
style Orchestrator fill:#fff3e0
style Worker fill:#e3f2fd
style Sandbox fill:#fce4ec3.1 Orchestrator 的职责
Orchestrator 是 IronClaw 的主二进制文件,承担中央控制节点的角色:
| 模块 | 职责 | 规模 |
|---|---|---|
api.rs | Worker HTTP API 端点(LLM 代理、状态上报、心跳) | ~800 行 |
auth.rs | 凭据授权(OsRng 生成安全令牌)、TokenStore | ~400 行 |
job_manager.rs | 容器生命周期管理、Job 状态机维护 | ~1542 行 |
reaper.rs | 后台清理孤儿容器 | ~969 行 |
3.2 Worker 的三种工作模式
Worker 是实际执行 Agent 逻辑的容器化进程,支持三种 JobMode:
// src/orchestrator/job_manager.rs
pub enum JobMode {
/// 标准 IronClaw Worker,LLM 调用通过 Orchestrator 代理
Worker,
/// 直接启动 `claude` CLI 的桥接模式
ClaudeCode,
/// 启动任何 ACP(Agent Client Protocol)兼容 Agent
Acp,
}三种模式的设计意图非常清晰:Worker 模式是标准 LLM 代理,所有 LLM 请求通过 proxy_llm.rs 转发到 Orchestrator 的 /worker/{id}/llm/complete 端点;ClaudeCode 模式是 Claude CLI 的桥接实现,在容器内安装 @anthropic-ai/claude-code@latest;Acp 模式则是开放的协议桥接,可对接任何符合 ACP 规范的第三方 Agent。
3.3 Job 状态定义
每个 Job 的生命周期都在 Orchestrator 的 JobManager 中被精确追踪:
// src/orchestrator/job_manager.rs - Job 状态与创建参数
pub struct JobCreationParams {
/// Worker 的凭据授权(通过 `/credentials` 端点按需获取)
pub credential_grants: Vec<CredentialGrant>,
/// 可选:指定挂载哪些 MCP 服务器
pub mcp_servers: Option<Vec<String>>,
/// Worker Agent 循环的最大迭代次数(服务器端限制为 1..=500)
pub max_iterations: Option<u32>,
/// ACP 模式下的 Agent 定义
pub acp_agent: Option<AcpAgentConfig>,
/// MCP 服务器配置(JSON 格式)
pub mcp_config_json: Option<serde_json::Value>,
}
// Job 状态机
// Created -> Starting -> Running -> [Completing | Failed | Cancelled] -> Cleanedmax_iterations 的服务器端限制尤其值得关注:const MAX_WORKER_ITERATIONS: u32 = 500;。这个硬上限防止了 Agent 陷入无限循环消耗资源,是生产系统的关键安全阀。
四、Docker Sandbox 架构:四级镜像体系与安全策略
4.1 四级 Docker 镜像
IronClaw 定义了 4 个专门的 Docker 镜像,各司其职:
| 镜像 | Dockerfile | 用途 | 关键特征 |
|---|---|---|---|
| 主应用 | Dockerfile | 云端部署 | cargo-chef 分层缓存、WASM 目标预装、panic=abort |
| Worker 沙箱 | Dockerfile.worker | 沙箱化 Job 执行 | 非 root 用户(UID 1000)、内置开发工具链、Claude CLI |
| 测试网关 | Dockerfile.test | 轻量级 Web 测试 | libSQL 后端、端口 3003、沙箱禁用 |
| WASM 构建沙箱 | docker/sandbox.Dockerfile | WASM 组件构建 | 双目标 wasm32-wasip2 + wasm32-unknown-unknown |
4.2 安全策略:纵深防御
Worker 沙箱的安全模型体现了"最小权限原则"的每一层:
stateDiagram-v2
[*] --> PullingImage : Orchestrator 创建 Job
PullingImage --> Configuring : 拉取镜像完成
Configuring --> Running : 配置环境变量与挂载
Running --> Streaming : 启动容器,流式日志
Streaming --> Completed : 正常退出
Streaming --> Failed : 异常退出 / 超时
Streaming --> Cancelled : 用户取消 / Token 过期
Completed --> Cleaning : 自动清理
Failed --> Cleaning : 自动清理
Cancelled --> Cleaning : 自动清理
Cleaning --> [*] : 容器移除
Running --> Orphaned : Orchestrator 崩溃
Orphaned --> Reaped : SandboxReaper 扫描移除
Reaped --> [*]
note right of Configuring
安全配置:
- User: sandbox (UID 1000)
- Memory: 2GB
- CPU: 1024 shares
- Privileged: false
- 无环境变量注入凭据
end note4.3 Docker 安全配置代码
以下是 Worker 容器的核心安全配置,使用 bollard crate 与 Docker API 交互:
// src/sandbox/config.rs - 资源限制与沙箱策略
pub struct ResourceLimits {
pub memory_mb: u64, // 默认: 2048 MB
pub cpu_shares: i64, // 默认: 1024
pub timeout_secs: u64, // 默认: 300
}
pub enum SandboxPolicy {
ReadOnly, // 只读文件系统访问
ReadWrite, // 读写文件系统访问
FullAccess, // 需要 SANDBOX_ALLOW_FULL_ACCESS 环境变量
}
// 凭据获取方式:Worker 通过 /credentials 端点按需拉取
// 绝不通过环境变量注入敏感信息
const CONTAINER_LABEL: &str = "ironclaw.job_id";关键安全设计:所有容器以非特权用户 sandbox(UID 1000)运行,Privileged 设为 false,内存限制 2GB,CPU shares 1024。所有出站流量通过 host.docker.internal 上的 HTTP 代理路由,凭据绝不以环境变量形式注入容器——Worker 需通过认证后的 /credentials 端点按需获取授权令牌。
4.4 容器执行输出
// src/sandbox/container.rs - 容器执行结果
pub struct ContainerOutput {
pub exit_code: i64, // 进程退出码
pub stdout: String, // 标准输出
pub stderr: String, // 标准错误
pub duration: Duration, // 执行耗时
pub truncated: bool, // 输出截断标志(防止日志爆炸)
}五、Routine/Hooks 系统:声明式生命周期管理
5.1 Hooks 系统
Hooks(src/hooks/)提供了事件驱动的生命周期回调和声明式 Bundle 机制:
| 文件 | 职责 |
|---|---|
mod.rs | Hook 注册表与执行引擎 |
hook.rs | 核心 Hook trait 与实现 |
registry.rs | Hook 注册与查找 |
bootstrap.rs | 引导 Hook Bundle |
bundled.rs | 内置 Hook 集合 |
session_summary.rs | 会话摘要生成 |
Hook 类型覆盖 Agent 全生命周期:启动时、停止时、出错时触发回调;声明式 Bundle 预配置常见场景的 Hook 组合;SessionSummaryHook 以可配置间隔生成周期性洞察。
5.2 Webhooks 入口
Webhooks(src/webhooks/mod.rs)提供通用的主机验证 Webhook 入口,端点为 /webhook/tools/{tool}。在接收 Webhook 之前进行主机验证,然后根据工具名称路由到对应的处理逻辑,全程进行安全校验的负载处理。
5.3 进程管理:ironclaw_processes crate
ironclaw_processes 是 IronClaw 的进程生命周期管理基础设施,提供完整的进程管理能力:
ironclaw_processes/
src/
lib.rs - 公共 API 与 re-export
types.rs - 核心 trait: ProcessStore, ProcessExecutor, ProcessManager
cancellation.rs - 协作式取消令牌 + 进程级注册表
host.rs - ProcessHost: 读取/轮询/等待/取消 接口
memory_store.rs - 内存版 ProcessStore / ProcessResultStore
filesystem_store.rs - 持久化文件系统后端
wrappers.rs - 可组合装饰器(Eventing, ResourceManaged)
services.rs - BackgroundProcessManager, ProcessServices核心 trait 设计简洁明了:ProcessStore 负责进程记录的 CRUD,ProcessResultStore 负责执行结果的存取,ProcessExecutor 负责实际执行逻辑,ProcessManager 负责高层编排。ProcessCancellationRegistry 追踪所有活跃进程,ResourceManagedProcessStore 确保失败时的资源清理,EventingProcessStore 则对外发出事件供监控与恢复使用。
六、Heartbeat 心跳系统:活性检测与自动恢复
6.1 心跳时序
Worker 通过定期心跳向 Orchestrator 报告存活状态:
sequenceDiagram
participant W as Worker Container
participant O as Orchestrator
participant DR as Docker Daemon
participant SD as systemd
rect rgb(225, 245, 254)
Note over W,O: 正常心跳循环
loop 每 30-60 秒
W->>O: POST /worker/{job_id}/heartbeat
O-->>W: 200 OK(续期超时计时器)
end
end
rect rgb(255, 243, 224)
Note over W,O: Worker 无响应场景
W-xO: 心跳超时(未收到)
O->>O: 标记 Job 为 Failed
O->>DR: 强制移除容器
O->>O: 触发 Reaper 扫描
end
rect rgb(232, 245, 233)
Note over DR,SD: 基础设施级健康检查
loop 每 5 秒
DR->>DR: pg_isready 健康检查
end
SD->>SD: Restart=always
RestartSec=5
end6.2 Heartbeat 端点实现
// Worker 端:定期发送心跳
// src/worker/api.rs - WorkerHttpClient
pub struct WorkerHttpClient {
client: reqwest::Client,
orchestrator_url: String,
job_id: Uuid,
}
impl WorkerHttpClient {
/// 发送心跳信号,防止 Orchestrator 判定 Job 超时
pub async fn send_heartbeat(&self) -> Result<(), WorkerError> {
let url = format!(
"{}/worker/{}/heartbeat",
self.orchestrator_url, self.job_id
);
self.client
.post(&url)
.send()
.await?
.error_for_status()?;
Ok(())
}
}6.3 多层健康监测
IronClaw 的健康监测是"Defense in Depth"的典范:
- 应用层:Worker 定期
POST /worker/{id}/heartbeat,Orchestrator 据此续期 Job 超时计时器 - 容器层:Docker Compose 配置
pg_isready健康检查,每 5 秒检测 PostgreSQL 可用性 - 主机层:systemd 服务配置
Restart=always,服务崩溃后 5 秒内自动重启
七、Self-repair 自修复机制:三重重试策略
生产系统中的故障不可避免,IronClaw 通过三重自修复机制构建韧性:
graph TB
subgraph WorkerSide["Worker 侧:AutonomousRecovery"]
A1["错误检测"]
A2["指数退避重试"]
A3["LLM 代理失败优雅降级"]
A4["恢复状态保持"]
A1 --> A2 --> A3 --> A4
end
subgraph OrchestratorSide["Orchestrator 侧:SandboxReaper"]
B1["每 300s 扫描"]
B2["检测 ironclaw.job_id 标签容器"]
B3["对比 ContextManager 活跃 Job"]
B4["容器存活 > 600s 且无活跃 Job?"]
B5["强制移除孤儿容器"]
B1 --> B2 --> B3 --> B4 -->|"是"| B5
B4 -->|"否"| B1
end
subgraph RetryLayer["瞬态故障重试:TransientFailureRetry"]
C1["max_retries: 3"]
C2["base_delay: 1s"]
C3["max_delay: 30s"]
C1 --> C2 --> C3
end
style WorkerSide fill:#e8f5e9
style OrchestratorSide fill:#fff3e0
style RetryLayer fill:#fce4ec7.1 SandboxReaper:孤儿容器清理
reaper.rs 解决了 Agent 进程在"容器创建"和"清理"之间崩溃导致的资源泄漏问题:
// src/orchestrator/reaper.rs - SandboxReaper 配置
pub struct ReaperConfig {
/// 扫描孤儿容器的间隔(默认:300 秒 = 5 分钟)
pub scan_interval: Duration,
/// 孤儿判定阈值:容器存活超过此时长且无对应活跃 Job(默认:600 秒 = 10 分钟)
pub orphan_threshold: Duration,
/// 用于关联 Job ID 的容器标签键
pub container_label: String, // 默认: "ironclaw.job_id"
}
impl Default for ReaperConfig {
fn default() -> Self {
Self {
scan_interval: Duration::from_secs(300), // 5 min
orphan_threshold: Duration::from_secs(600), // 10 min
container_label: "ironclaw.job_id".to_string(),
}
}
}Reaper 算法简洁高效:
- 每 300 秒扫描 Docker 中所有带
ironclaw.job_id标签的容器 - 对每个容器,检查 ContextManager 中是否存在对应的活跃 Job
- 如果 Job 已不存在(或已完成)且容器存活时间超过 600 秒
- 立即强制移除该孤儿容器
7.2 AutonomousRecovery:Worker 侧自主恢复
autonomous_recovery.rs 位于 Worker 端,负责错误检测与恢复:
- 指数退避重试策略,避免对故障服务造成雪崩效应
- LLM 代理失败时的优雅降级(切换到备用策略)
- 恢复过程中保持执行状态,不丢失上下文
7.3 瞬态故障重试配置
// src/sandbox/manager.rs - 瞬态故障重试配置
pub struct RetryConfig {
pub max_retries: u32, // 默认: 3 次
pub base_delay_ms: u64, // 默认: 1000 ms(1 秒)
pub max_delay_ms: u64, // 默认: 30000 ms(30 秒)
}重试采用指数退避算法:第 1 次等待 1 秒,第 2 次等待 2 秒,第 3 次等待 4 秒……直到达到 30 秒上限。这种策略既不会过早放弃(最多 3 次),也不会对故障服务造成过大压力。
八、资源管理与并发控制
8.1 并发模型
IronClaw 的并发管理采用 Rust 的 Arc<RwLock<...>> 模式,在 Tokio 异步运行时上实现高效的并发控制:
| 层级 | 机制 | 数据结构 |
|---|---|---|
| Docker 级 | 每 Job 独立容器 | HashMap<Uuid, JobState> |
| 运行时 | Tokio async | Arc<RwLock<...>> |
| 取消 | 协作式取消 | ProcessCancellationToken |
| 清理 | Job 完成/超时自动触发 | drop() + reaper 兜底 |
8.2 凭据安全架构
IronClaw 的凭据安全设计体现了"零信任"理念:
graph LR
subgraph OrchestratorSecrets["Orchestrator 安全区"]
TS["TokenStore"]
OR["OsRng
密码学安全随机数"]
end
subgraph WorkerContainer["Worker 容器(最小权限)"]
CG["CredentialGrant
限定范围令牌"]
API["/credentials 端点
按需获取"]
end
UserSecrets["用户主密钥"] -->|"生成"| TS
OR -->|"派生"| CG
TS -->|"响应请求"| API
API -->|"拉取(非推送)"| CG
style OrchestratorSecrets fill:#e8f5e9
style WorkerContainer fill:#fff3e0核心原则:
- 主密钥始终存储在 Orchestrator 的
TokenStore中,永不离开安全区 - 每个 Job 获得独立生成的
CredentialGrant令牌,作用域严格限定 - Worker 通过认证的
/credentials端点按需拉取凭据(Pull 模式),而非 Orchestrator 主动推送 - 绝不将凭据注入容器的环境变量
九、总结:IronClaw 调度系统的五大设计哲学
回顾 IronClaw 的任务调度与并行执行架构,可以提炼出五条核心设计哲学:
分层解耦:MissionManager → ThreadManager → Dispatcher 的三层架构,每一层只关注自己的抽象层次,上层不关心下层的实现细节。
容器级隔离:每 Job 独占一个 Docker 容器,配合非 root 用户、资源限制、代理隔离,实现真正的多租户安全。
Fail-safe 默认:
max_iterations服务器端硬上限、GateDecision无None变体(fail-closed)、SandboxReaper 自动兜底清理——系统默认为安全状态。按需授权:凭据通过
/credentials端点按需获取,不注入环境变量,每 Job 独立令牌,最小权限原则贯穿始终。韧性设计:瞬态故障重试(指数退避)、AutonomousRecovery 状态保持、SandboxReaper 孤儿清理、systemd 自动重启——多层故障恢复机制确保系统在任何单点故障下都能自动恢复。
这套调度系统使 IronClaw 能够在单节点上可靠地并发执行数十个 Agent Job,同时保持严格的资源隔离和安全边界。对于正在构建 Agent 平台的开发者来说,IronClaw 的 Orchestrator/Worker 模式、Docker 沙箱策略和自修复机制都是极具参考价值的设计范例。
系列文章导航:
- (一)架构总览与核心组件
- (二)Engine v2:统一执行引擎与 CodeAct 模式
- (三)Docker 沙箱安全模型深度解析
- (四)Capability 系统与执行门控
- (五)任务调度与并行执行——多 Job 并发模型 ← 本文
- (六)事件驱动架构与状态持久化
参考资料:
- IronClaw 源代码仓库:https://github.com/nearai/ironclaw
- bollard crate(Rust Docker API 客户端):https://docs.rs/bollard
- Engine v2 架构文档:
crates/ironclaw_engine/CLAUDE.md- 分析版本:v0.28.2(main 分支)