Skip to main content
BlockX 是一个面向链上数据的函数执行框架。它接收 Client 提交的 task,在 Worker 上扫描触发数据、并行执行用户编写的轻量 Python 函数,再把结果写回 BlockDB。核心计算模式是 onchain table -> onchain table 的单行状态计算。 BlockX 只负责计算执行。task 生成、DAG 编排、触发器管理和定时任务都由 Client 负责。 这一组页面面向要给 BlockX 贡献代码的开发者。如果你只想知道”代码在哪、改什么该看哪里”,直接去 仓库结构与代码分层

一句话看懂系统

1

Client 申请执行资源

Client 向任意一个 Coordinator 调用 ReserveWorkerSlot(taskId)。Coordinator 基于 etcd 中的 Worker 心跳选一个候选 Worker,向它调用 RequestTaskSlot,把 workerAddr + slotId 交回 Client。Client 也可以跳过 Coordinator 直连 Worker。
2

Client 提交 task

Client 向目标 Worker 调用 SubmitTask(task, slotId?)。Worker 校验并激活 slot,创建 task 上下文,固定本 task 使用的函数代码快照。
3

Worker 分三个阶段执行

Builder 阶段串行运行 Call Builder,扫描触发数据生成 call list;Calls 阶段由 dispatcher 把 call 窗口化投递到常驻的 Python Executor 进程池并行执行;Plugin 阶段由 Writer Plugin 把汇聚后的 outputs 一次性写入 BlockDB。
4

Client 取结果

SubmitTask 只返回提交确认。Client 通过 GetTaskResultWatchTasks 流从同一个 Worker 拿到终态 TaskResult
完整的端到端时序、slot 状态机和结果模型见 Task 生命周期

组件图

图中每个方框都对应一个组件页。Sync Invoker 复用 Worker 的 executor adapter、Pool Manager、Function Code View 和 IO 子系统代码,在自己的进程里拉起独立的 Executor 池,但不走 slot / task 流程;bundle 集群用同一套代码、不同的进程 profile 和 etcd 注册前缀部署,专门跑大范围 bundle 回填任务。

组件与职责

核心约束

这些约束贯穿所有组件的设计。改动代码时如果发现自己在打破其中一条,先回头看对应 spec。
  • 以 task 为中心:task 是最小调度单元,只在一个 Worker 上执行;所有缓存和状态共享都锚定在 task 上,task 结束即释放。
  • task 内 call 全并行:call 之间没有顺序依赖,共享同一时刻的只读世界状态。
  • 同一 task 内函数版本固定:task 激活时固定 taskCodeEpoch,之后的顶层 call 和子函数调用都基于同一份代码快照解析;代码热更新只影响新 task。
  • Python 侧 IO 必须可劫持:用户函数通过 SDK 发起的 BlockDB / RPC 请求都被 hook 回 Worker 统一处理,不允许 Executor 直连外部存储。
  • 函数只读、写入走 Plugin:用户函数不能写 BlockDB;每个 task 至多一个 Writer Plugin,在 Plugin 阶段一次性写入。
  • 不做 task 级自动重试,不支持取消:框架只提供超时;是否重投由 Client 根据 TaskResult.retryable 决定。Worker 内部允许对单个 call 做有界 attempt 重试。
  • Worker 本地 slot 表是唯一真相:Coordinator 只维护可丢弃的派生视图,etcd 只承载注册和心跳。多个 Coordinator 同时选中同一 Worker 时,在 Worker 的原子容量检查处收敛。
  • TaskResult 只表达 task 级结果:不返回每个 call 的返回值;终态只有 SUCCEEDED / FAILED,失败时用错误码和 retryable 表达。

三条设计原则

  • Sans-IO:状态机、调度决策、协议映射收敛在纯内存 core/,adapter 承担 RPC、UDS、存储、时钟和观测。WorkerCoreCoordinatorCoreDispatcherCore 都按”输入事件 → core 决策 → adapter 执行命令”的单向模式工作。
  • Scoped Resource Context:IO 访问这类以资源拥有权和生命周期回收为中心的子系统,按 Worker 级共享作用域与 task 级局部作用域组织,把 quota、cache、singleflight、deadline 绑定到作用域生命周期。
  • Occam’s Razor:如无必要,勿增实体。优先复用既有概念、状态、接口、错误码和协议。
原则如何落到代码约束,见 设计原则与代码约定

不适用场景

BlockX 不适合以下计算:
  • 依赖同一张表大量行数据的计算,例如大范围聚合、复杂窗口统计、K 线计算。
  • 需要任意时间窗口状态和大规模有状态计算的场景。
  • 强依赖流式引擎 exactly-once 状态恢复的复杂计算。
  • 普通在线表的任意增量流式计算。

建议阅读顺序

1

先看主链路

Task 生命周期协议与接口。读完你应该能说出一个 task 经过哪些 RPC、哪些阶段、哪些状态。
3

按要改的组件深入

从上面的组件表进入对应页面。每个组件页都列出代码位置、核心类型、扩展点和测试。
4

动手前看开发指南

改动行为语义时,先改 BlockX 仓库 docs/specs/ 下的设计文档,再改代码,两者放在同一个 PR。