Skip to content

核心概念 ​

本页解释 Pulse 的数据模型和执行规则。建议先运行快速开始,再用这里的概念理解分支、汇聚、复用与取消。

定义与执行 ​

Pulse 使用四个核心对象:

对象保存什么生命周期
Key[T]数据名称与 Go 类型随定义使用
NodeID、描述、读写声明、函数与切面属于图定义
Graph节点、端口、依赖与挂载的子图可以被反复执行
Execution本轮输入、数据槽位、状态、错误与取消域对应一次运行

可以把 Graph 理解为一份处理说明,把 Execution 理解为按这份说明执行的一个请求。两个请求使用同一份说明,并不共享执行槽位。

每次 g.Run(ctx, in) 都创建新的执行。要取得句柄,使用 g.NewExecution(ctx, in),随后调用 e.Start() 与 e.Wait()。同一个 Execution 只能成功启动一次。

图定义的隔离不意味着业务对象被复制:闭包捕获的计数器、客户端,以及传入的 map、slice、指针仍可能共享。并发执行时,这些对象的同步由应用负责。

Key:有名字和类型的数据 ​

pulse.NewKey[string]("summary") 表示名为 summary 的字符串数据。同名、同类型的 Key 等价;在一张图内,同名键不能混用不同类型。未初始化的零 Key 不能用作输入或端口。

节点通过 Requires 声明读取权限,通过 Provides 声明写入权限。读取未声明的输入或写入未声明的输出会返回 ErrUndeclared。不同类型的声明通过 pulse.Deps 组合。

每条数据只有一个来源:它可以是声明给宿主的入口,也可以由一个节点产生。重复来源在装配时被拒绝。多个下游节点可以读取同一个普通值;多个 channel 读者会竞争流元素,流需要额外规则,见流式处理。

端口:图的公共接口 ​

Key 用于内部读写,端口决定宿主和父图能访问哪些数据:

  • DeclareInput 声明可从外部提供的输入;本轮值通过 Inputs 提供。
  • DeclareOutput 声明可从本轮执行读取的输出。
  • 子图通过声明的端口接线,内部 Key 不会自动成为公共接口。

一个 Key 同时声明为入口与出口时,可以形成透传接口。如果它是可选入口,本轮没有提供且没有节点依赖它,结束后仍可能是 pending。这是明确的正常状态,不会被改写为跳过。

具体声明、接线与读取见输入与输出和子图。

数据槽位的三种状态 ​

Key 标识数据;一次 Execution 中对应的槽位保存这次数据的到达情况。

状态含义是否已经到达
pending尚未提供结果否
ready已提供一个值,包括合法零值是
skipped已明确表示这次没有值是

ready 与 skipped 都会结束等待。0、空串和合法 nil 值不能代替缺失状态;它们可以是业务有效值。具体 nil 输入限制见输入与输出。

Set 写入值,Skip 写入正常缺值。同一槽位的同态重复写是幂等首写:再次 Set 不覆盖原值,再次 Skip 不改变状态。Set 与 Skip 相互冲突。宿主向 Inputs 重复提供同一键则会在 Seed / SkipSeed 时被拒绝。

成功返回的节点,其尚未写入的声明输出会自动跳过。需要选择一路时,应写入被选中的输出,并明确跳过其它输出;分支指南给出完整例子。

节点何时运行 ​

普通节点遵守以下规则:

  1. 没有输入依赖的节点可以开始运行。
  2. 有输入的节点等待所有输入到达;到达可以是 ready 或 skipped。
  3. 所有输入到达后,只要至少一项为 ready,节点就进入处理函数;全部为 skipped 时,节点跳过处理函数,输出也跳过。

例如摘要有值、标签跳过时,报告节点仍可进入函数。它需要用 TryGet 或 Batch 明确收集有值的部分。如果业务要求摘要和标签缺一不可,在函数里返回 WaitAll 的结果,选择整体跳过。

这不是“收到第一项就立即处理”。汇聚节点始终等各路都表明结果,再按声明的策略处理。分支与汇聚说明两种策略及对应 API。

跳过、失败与取消 ​

跳过是正常结果。 节点可以跳过一项输出,或通过 NoValue / 跳过结果结束整个节点。整张图全部跳过也可以成功;Wait 不把正常跳过作为错误返回。

真实错误是执行失败。 节点返回非跳过错误时,Pulse 记录错误并取消本次执行,使等待者和协作处理函数退出。节点 panic 会被转换为执行错误。错误不会被静默转成缺值。

取消需要业务协作。 在 HTTP、数据库、循环和阻塞操作中使用 rc.Context()。Go 无法安全终止一个忽略取消的业务函数;Wait 和 Timeout 仍需等待函数退出。

封口与复用 ​

Validate 成功,或某次 Execution 成功启动时,会封口整棵定义树,包括已挂载的子图。封口固定节点和端口,避免执行中发生结构变化。

校验失败不会封口,可补全定义后重试。封口后的 Graph 仍可执行,也可挂载到其它图;它冻结的是定义,并没有被某次执行消耗。

若同一个子图挂在两个位置,每个位置创建独立子 Execution。挂载位置还会出现在观测的 Site.Path 中,便于区分复用模块的不同实例。

切面与观测 ​

Aspect 包住节点的等待与处理过程,适合显式重试和超时。先声明的切面位于外层。Retry 为每次尝试暂存输出,失败且将重试时丢弃这些写入;这不回滚外部副作用。重试与取消解释组合顺序和限制。

Topology 描述静态结构,Snapshot 描述一轮执行的状态,Observer 提供事件。状态快照不携带业务值,读取视图也不会推进执行。业务输出通过声明出口读取,事件通过可选 observe 包接入日志。

下一步:选择一个使用任务,或查阅生命周期参考。

开发版 API 文档 · Go 1.26+ · MIT