从缓存到执行:我实现了自己的任务编排引擎
背景:为什么需要自己再造一个团队接入 monorepo 任务编排工具后,构建快了很多。但我一直对两个问题好奇:缓存的"三层架构"到底怎么设计的?.turbo/cache目录下的.tar.gz文件,里面存了什么?怎么做到"第一次去本地读,第二次去远程读"的降级策略?拓扑执行器怎么实现?把 DAG 图变成"前驱跑完我才跑"的并发调度,代码到底怎么写?于是我用大概400 行 Rust 代码,实现了一个最小可行的任务编排引擎。核心模块就两个:三层缓存层和竞图执行器(Walker)。这篇文章完整拆解它的设计和实现细节。整体架构┌──────────────────────────────────────────────────┐ │ CLI 入口 │ │ run build --concurrency=8 │ └───────────────────┬──────────────────────────────┘ │ ┌───────────┴───────────┐ │ │ ┌─────┴──────┐ ┌──────┴─────────┐ │ 执行器层 │ │ 缓存层 │ │ Walker │ ←──→ │ 三层缓存(Multip) │ │ DAG调度 │ │ Local/Remote │ └────────────┘ └─────────────────┘ │ │ ┌─────┴──────┐ ┌──────┴─────────┐ │ 依赖图构建 │ │ Hash 计算 │ │ 拓扑排序 │ │ 六层输入 │ └────────────┘ └─────────────────┘每层职责:依赖图构建层:读取pipeline.config.json+package.json,遍历所有包×任务的笛卡尔积,解析^build为具体任务,构建 TaskGraphHash 计算层:六层输入 → 任务哈希 → 缓存 key缓存层:三层优先级(本地文件 → 远程 HTTP → 无缓存),tar 归档 + 元数据 sidecar执行器层:Walk 算法——每个节点一个异步 task,等前驱全部完成才启动下面重点拆解后两层。实现细节第1节:三层缓存架构需求很简单:有本地缓存(文件系统)时用本地本地没命中时尝试远程 HTTP 缓存写入时本地同步写、远程异步写(不阻塞任务执行)我用一个MultiplexCache结构体来实现:// packages/task-cache/src/lib.rs struct MultiplexCache { local: LocalCache, remote: OptionRemoteCache, config: CacheConfig, } struct CacheConfig { local_read: bool, local_write: bool, remote_read: bool, remote_write: bool, }四个 bool 的组合覆盖了所有场景:(true, true, false, false)→ 纯本地开发(true, false, true, true)→ CI 只读远程、只写远程(false, false, true, true)→ 纯远程,不产生本