iii-event-driven-cqrs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Event-Driven CQRS & Event Sourcing

事件驱动型CQRS与事件溯源

Comparable to: Kafka, RabbitMQ, CQRS/Event Sourcing systems
同类技术:Kafka、RabbitMQ、CQRS/事件溯源系统

Key Concepts

核心概念

Use the concepts below when they fit the task. Not every CQRS system needs all of them.
  • Write side: Commands validate input and publish domain events via pubsub
  • Read side: Multiple projections subscribe to events independently, building query-optimized views in state
  • Event log: Events are appended to state as an ordered log (event sourcing)
  • PubSub handles fan-out — one event reaches all projections and downstream consumers
  • HTTP triggers expose both command endpoints (POST) and query endpoints (GET)
当任务符合以下场景时使用这些概念,并非所有CQRS系统都需要全部概念。
  • 写入端:命令验证输入并通过pubsub发布领域事件
  • 读取端:多个投影独立订阅事件,在状态中构建查询优化视图
  • 事件日志:事件以有序日志的形式追加到状态中(事件溯源)
  • PubSub 处理扇出——单个事件可送达所有投影和下游消费者
  • HTTP触发器 同时暴露命令端点(POST)和查询端点(GET)

Architecture

架构

text
HTTP POST /inventory (command)
  → cmd::add-inventory-item → validate → append event to state
    → publish('inventory.item-added')
      ↓ (fan-out via subscribe triggers)
      → proj::inventory-list (updates queryable list view)
      → proj::inventory-stats (updates aggregate counters)
      → notify::inventory-alert (sends low-stock alerts)

HTTP GET /inventory (query)
  → query::list-inventory → reads from projection state
text
HTTP POST /inventory (command)
  → cmd::add-inventory-item → validate → append event to state
    → publish('inventory.item-added')
      ↓ (fan-out via subscribe triggers)
      → proj::inventory-list (updates queryable list view)
      → proj::inventory-stats (updates aggregate counters)
      → notify::inventory-alert (sends low-stock alerts)

HTTP GET /inventory (query)
  → query::list-inventory → reads from projection state

iii Primitives Used

使用的iii原语

PrimitivePurpose
registerWorker
Initialize the worker and connect to iii
registerFunction
Define commands, projections, and queries
trigger({ function_id: 'state::set/get/list', payload })
Event log and projection state
trigger({ function_id: 'publish', payload })
Publish domain events
registerTrigger({ type: 'subscribe', config: { topic } })
Subscribe projections to events
registerTrigger({ type: 'http' })
Command and query endpoints
trigger({ ..., action: TriggerAction.Void() })
Fire-and-forget notifications
原语用途
registerWorker
初始化worker并连接到iii
registerFunction
定义命令、投影和查询
trigger({ function_id: 'state::set/get/list', payload })
事件日志和投影状态
trigger({ function_id: 'publish', payload })
发布领域事件
registerTrigger({ type: 'subscribe', config: { topic } })
订阅事件的投影
registerTrigger({ type: 'http' })
命令和查询端点
trigger({ ..., action: TriggerAction.Void() })
即发即弃的通知

Reference Implementation

参考实现

See ../references/event-driven-cqrs.js for the full working example — an inventory management system with commands that publish domain events and multiple projections building query-optimized views.
查看../references/event-driven-cqrs.js获取完整的工作示例——一个库存管理系统,其中命令会发布领域事件,多个投影构建查询优化视图。

Common Patterns

常见模式

Code using this pattern commonly includes, when relevant:
  • registerWorker(url, { workerName })
    — worker initialization
  • trigger({ function_id: 'state::set', payload: { scope: 'events', key, value } })
    — event log append
  • trigger({ function_id: 'publish', payload: { topic, data } })
    — domain event publishing
  • registerTrigger({ type: 'subscribe', function_id, config: { topic } })
    — projection subscriptions
  • Command functions with
    cmd::
    prefix, projection functions with
    proj::
    prefix, query functions with
    query::
    prefix
  • Multiple projections subscribing to the same topic independently
  • const logger = new Logger()
    — structured logging per command/projection
使用此模式的代码通常包含以下内容(相关时):
  • registerWorker(url, { workerName })
    —— worker初始化
  • trigger({ function_id: 'state::set', payload: { scope: 'events', key, value } })
    —— 事件日志追加
  • trigger({ function_id: 'publish', payload: { topic, data } })
    —— 领域事件发布
  • registerTrigger({ type: 'subscribe', function_id, config: { topic } })
    —— 投影订阅
  • 命令函数使用
    cmd::
    前缀,投影函数使用
    proj::
    前缀,查询函数使用
    query::
    前缀
  • 多个投影独立订阅同一主题
  • const logger = new Logger()
    —— 每个命令/投影的结构化日志

Adapting This Pattern

模式适配

Use the adaptations below when they apply to the task.
  • Add new projections by registering subscribe triggers on existing event topics
  • Use separate state scopes for each projection (e.g.
    inventory-list
    ,
    inventory-stats
    )
  • Commands should validate before publishing — reject invalid commands early
  • For critical event processing, use
    TriggerAction.Enqueue({ queue })
    instead of pubsub for guaranteed delivery
  • Event IDs should be unique and monotonic for ordering (e.g.
    evt-${Date.now()}-${counter}
    )
当以下情况适用于任务时,进行相应适配:
  • 通过在现有事件主题上注册订阅触发器来添加新投影
  • 为每个投影使用单独的状态作用域(例如
    inventory-list
    inventory-stats
  • 命令应在发布前进行验证——尽早拒绝无效命令
  • 对于关键事件处理,使用
    TriggerAction.Enqueue({ queue })
    替代pubsub以保证交付
  • 事件ID应唯一且单调递增以保证顺序(例如
    evt-${Date.now()}-${counter}

Pattern Boundaries

模式适用边界

  • If the task is about simple CRUD with reactive side effects, prefer
    iii-reactive-backend
    .
  • If the task needs durable multi-step pipelines with retries, prefer
    iii-workflow-orchestration
    .
  • Stay with
    iii-event-driven-cqrs
    when command/query separation, event sourcing, and independent projections are the primary concerns.
  • 如果任务是带有反应式副作用的简单CRUD操作,优先使用
    iii-reactive-backend
  • 如果任务需要带重试机制的持久化多步骤流水线,优先使用
    iii-workflow-orchestration
  • 当命令/查询分离、事件溯源和独立投影是主要需求时,选择
    iii-event-driven-cqrs

When to Use

适用场景

  • Use this skill when the task is primarily about
    iii-event-driven-cqrs
    in the iii engine.
  • Triggers when the request directly asks for this pattern or an equivalent implementation.
  • 当任务主要涉及在iii引擎中使用
    iii-event-driven-cqrs
    时,使用此技能。
  • 当请求直接要求此模式或等效实现时触发。

Boundaries

使用限制

  • Never use this skill as a generic fallback for unrelated tasks.
  • You must not apply this skill when a more specific iii skill is a better fit.
  • Always verify environment and safety constraints before applying examples from this skill.
  • 切勿将此技能作为无关任务的通用 fallback。
  • 当更特定的iii技能更合适时,不得应用此技能。
  • 在应用此技能中的示例前,始终验证环境和安全约束。