RFC: Pulseflare Projection Engine + Task Management #8
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
RFC: Pulseflare Projection Engine + Task Management
背景
Pulseflare v2 已经是被动 event store + projection API。现在需要:
设计
Projection Definition
Projection def 存 D1,用 JSONata 做 expression(参考 OGraph 方案,CF Workers 兼容)。
Fold 逻辑:
(state, event) → newState,按occurred_at ASC顺序逐条 fold。Task Pool 示例
按项目过滤:加
key_prefix: "task:pulse:"。Task Detail 示例
增量缓存
projections表已有,扩展为:Fold 时从
last_event_id之后增量计算,不用每次全量扫。Task 事件约定
Claim 乐观锁
不加服务端原子操作。Agent claim 后查 projection,第一个 claim event 生效,后续忽略(fold 逻辑:已 claimed 则
state不变)。API
新增:
POST /projections/defs— 注册 projection defGET /projections/defs— 列出所有 defGET /projections/defs/:name— 查看 defDELETE /projections/defs/:name— 删除 def修改:
GET /projections/:name— 全局 projection(fold 所有匹配 events)GET /projections/:name/:key— 按 key 实例化的 projection(fold 该 key 的 events)Store 层新增:
queryEvents({kinds?, keyPrefix?, since?, sinceId?, limit?})— 多 kind + key 前缀查询依赖
jsonatanpm 包(~150KB,零原生依赖,CF Workers 兼容)实施步骤
queryEvents多条件查询方法;扩展 projections 表结构不做
Review Comments — 小橘 🍊
1. 两类 Projection:LazyProjection + GuardProjection
expression:(state, event) → newStatecheck+transitionGuard 是 Lazy 的超集。
2. Guard 解决 Claim 竞争
不需要乐观锁。写入时同步 fold + check,D1 单 writer 串行,无竞争窗口:
3. task-lifecycle GuardProjection 示例
4. 其他意见
(kind, key)复合索引GET /projections/:name/:key对两类都适用5. 更新后的写入流程
GuardProjection 拆为独立 issue #9,作为 PulseStore 核心能力先实现。#8 的 Pulseflare projection engine 基于 #9 构建。
优先级:#9 > #8
— 小橘 🍊