Skip to content

chore: cover topic and named queue patterns in skills#7

Draft
anthonyiscoding wants to merge 1 commit intomainfrom
add/queues-topics
Draft

chore: cover topic and named queue patterns in skills#7
anthonyiscoding wants to merge 1 commit intomainfrom
add/queues-topics

Conversation

@anthonyiscoding
Copy link
Copy Markdown
Contributor

@anthonyiscoding anthonyiscoding commented Mar 25, 2026

Document both queue modes side-by-side in core skills and align reference implementations so topic-based enqueue flows and named queue dispatch examples are both clear and consistent.

Summary by CodeRabbit

  • Documentation
    • Shifted event dissemination architecture from pub/sub pattern to queue/topic-based delivery.
    • Added documentation for topic-based queue patterns and routing mechanisms.
    • New guidance comparing topic-based queues, named queues, and hybrid approaches.
    • Updated reference examples demonstrating the new queue-based event handling patterns.

Document both queue modes side-by-side in core skills and align reference implementations so topic-based enqueue flows and named queue dispatch examples are both clear and consistent.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

The pull request transitions the event dissemination architecture from pubsub-style fan-out to queue/topic-based delivery. Documentation and code examples are updated to reflect the shift: commands emit events via enqueue() with topic targets, and read-side projections consume from queue-triggered handlers. New guidance distinguishes topic-based versus named queue modes.

Changes

Cohort / File(s) Summary
Documentation Updates
event-driven-cqrs/SKILL.md, functions-and-triggers/SKILL.md, queue-processing/SKILL.md
Updated narrative and architecture diagrams to describe queue/topic-based event delivery instead of pubsub fan-out. Added "Queue Mode Choice" section contrasting topic-based and named queue approaches, with guidance on when to use each.
Reference Implementations
references/event-driven-cqrs.js, references/functions-and-triggers.js
Modified code examples to emit events via awaited iii.trigger({ function_id: 'enqueue', payload: { topic, data } }) instead of non-awaited publish(). Updated trigger registrations from type: 'subscribe' to type: 'queue' with topic-based configuration.
Queue Processing Example
references/queue-processing.js
Added two new function registrations (orders::emit-created, orders::on-created) and a queue trigger handler demonstrating topic-based queue workflow with message receipt tracking.

Sequence Diagram(s)

sequenceDiagram
    participant Cmd as Command Handler
    participant Queue as Queue/Topic
    participant Proj as Projection<br/>(Consumer)
    participant ReadDB as Read DB

    rect rgba(100, 200, 100, 0.5)
    Note over Cmd,ReadDB: New: Queue/Topic-Based
    Cmd->>Queue: enqueue(topic='orders.created',<br/>data)
    activate Queue
    Queue->>Proj: trigger queue handler<br/>(type: 'queue',<br/>topic: 'orders.created')
    deactivate Queue
    activate Proj
    Proj->>ReadDB: Update projection
    Proj-->>Proj: messageReceiptId returned
    deactivate Proj
    end
Loading
sequenceDiagram
    participant Alert as Alert Logic
    participant Queue as Named Queue
    participant Notif as Notification<br/>Handler
    participant Slack as Slack API

    rect rgba(100, 150, 200, 0.5)
    Note over Alert,Slack: Alert Fan-Out: Enqueue to Named Queue
    Alert->>Queue: TriggerAction.Enqueue<br/>({queue: 'alerts-notify'})
    activate Queue
    Queue->>Notif: Trigger handler<br/>(type: 'queue',<br/>queue: 'alerts-notify')
    deactivate Queue
    activate Notif
    Notif->>Slack: Send low-stock notification
    deactivate Notif
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 From publish winds to queue-held streams,
Events flow through topic dreams,
Named or themed, the choice is ours—
Queue by queue, through ordered doors! 🚪

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: expanding documentation to cover both topic-based and named queue patterns in the skills.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add/queues-topics

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@anthonyiscoding anthonyiscoding marked this pull request as draft March 25, 2026 19:01
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
references/functions-and-triggers.js (1)

89-100: ⚠️ Potential issue | 🟠 Major

Don't emit orders.completed before fulfillment starts.

orders::create only validates the request and queues orders::fulfill, so consumers on this topic will observe a completion that has not happened yet. Rename this to orders.created/orders.accepted, or move the emit into the actual fulfillment completion path.

💡 Possible fix

Consumer side:

-iii.registerFunction({ id: 'notifications::on-order-complete' }, async (data) => {
+iii.registerFunction({ id: 'notifications::on-order-created' }, async (data) => {
   const logger = new Logger()
-  logger.info('Order completed event received', { orderId: data.order_id })
+  logger.info('Order created event received', { orderId: data.order_id })
   return { processed: true }
 })

 iii.registerTrigger({
   type: 'queue',
-  function_id: 'notifications::on-order-complete',
-  config: { topic: 'orders.completed' },
+  function_id: 'notifications::on-order-created',
+  config: { topic: 'orders.created' },
 })

Producer side:

   await iii.trigger({
     function_id: 'enqueue',
     payload: {
-      topic: 'orders.completed',
+      topic: 'orders.created',
       data: { order_id: data.order_id },
     },
   })

Also applies to: 119-126

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@references/functions-and-triggers.js` around lines 89 - 100, The trigger is
listening to the topic 'orders.completed' but the producer only validates and
queues fulfillment (orders::create → orders::fulfill), so consumers will see a
completion event before fulfillment actually finishes; update the trigger
configuration (the iii.registerTrigger call that references function_id
'notifications::on-order-complete') to subscribe to a more accurate topic such
as 'orders.created' or 'orders.accepted', or instead move emission of
'orders.completed' from the create path into the actual fulfillment completion
path (where orders::fulfill finishes) so the topic name matches the real
lifecycle event.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@references/event-driven-cqrs.js`:
- Around line 154-157: notify::low-stock-alert races with proj::catalog-on-sell
because both independently consume inventory.item-sold and the alert handler can
read inventory-read before the projection decrement has been written; fix by
ensuring the alert receives the post-sale stock value or by emitting/triggering
the low-stock notification from the projection update path after
proj::catalog-on-sell finishes writing inventory-read. Specifically, either
include the updated stock count on the inventory.item-sold event (so
notify::low-stock-alert can make a correct decision) or invoke
notify::low-stock-alert (or publish a dedicated low-stock topic) from inside the
proj::catalog-on-sell projection write routine once the decrement is persisted.
- Around line 51-55: The appendEvent() followed by multiple iii.trigger({
function_id: 'enqueue', ... }) calls is non-atomic: appendEvent() can succeed
while one or more enqueue fan-out calls fail, leaving event-log ahead of
projections. Fix by adopting an outbox/replay-marker pattern: make appendEvent()
persist the event plus an outbox entry or advance a replay marker in the same
atomic operation/transaction, then have a separate reliable dispatcher read the
outbox/replay marker and call iii.trigger('enqueue', ...) (or enqueue) only
after the write is committed; alternatively, enqueue the fan-out work into the
same durable store (outbox table) and have a background process perform
iii.trigger() from that outbox with retry/at-least-once semantics so projections
and event-log stay consistent. Ensure code changes touch appendEvent(), the
outbox/replay marker persistence, and the dispatcher that invokes
iii.trigger/enqueue.

---

Outside diff comments:
In `@references/functions-and-triggers.js`:
- Around line 89-100: The trigger is listening to the topic 'orders.completed'
but the producer only validates and queues fulfillment (orders::create →
orders::fulfill), so consumers will see a completion event before fulfillment
actually finishes; update the trigger configuration (the iii.registerTrigger
call that references function_id 'notifications::on-order-complete') to
subscribe to a more accurate topic such as 'orders.created' or
'orders.accepted', or instead move emission of 'orders.completed' from the
create path into the actual fulfillment completion path (where orders::fulfill
finishes) so the topic name matches the real lifecycle event.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e7204104-ef4f-46a6-af09-305ea6607fbe

📥 Commits

Reviewing files that changed from the base of the PR and between 22a6bdb and 0613aa9.

📒 Files selected for processing (6)
  • event-driven-cqrs/SKILL.md
  • functions-and-triggers/SKILL.md
  • queue-processing/SKILL.md
  • references/event-driven-cqrs.js
  • references/functions-and-triggers.js
  • references/queue-processing.js

Comment on lines +51 to +55
// Emit domain event for all topic queue consumers to process
await iii.trigger({
function_id: 'enqueue',
payload: { topic: 'inventory.item-added', data: event },
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Event-log append and fan-out are not atomic.

appendEvent() completes before each enqueue call, so a failure here leaves event-log ahead of the projections. Because the query endpoints read projections rather than event-log, the system stays inconsistent until you replay manually. Consider persisting an outbox/replay marker with the append.

Also applies to: 82-85

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@references/event-driven-cqrs.js` around lines 51 - 55, The appendEvent()
followed by multiple iii.trigger({ function_id: 'enqueue', ... }) calls is
non-atomic: appendEvent() can succeed while one or more enqueue fan-out calls
fail, leaving event-log ahead of projections. Fix by adopting an
outbox/replay-marker pattern: make appendEvent() persist the event plus an
outbox entry or advance a replay marker in the same atomic
operation/transaction, then have a separate reliable dispatcher read the
outbox/replay marker and call iii.trigger('enqueue', ...) (or enqueue) only
after the write is committed; alternatively, enqueue the fan-out work into the
same durable store (outbox table) and have a background process perform
iii.trigger() from that outbox with retry/at-least-once semantics so projections
and event-log stay consistent. Ensure code changes touch appendEvent(), the
outbox/replay marker persistence, and the dispatcher that invokes
iii.trigger/enqueue.

Comment on lines +154 to +157
// Projections consume domain events independently via queue topic triggers
iii.registerTrigger({ type: 'queue', function_id: 'proj::catalog-on-add', config: { topic: 'inventory.item-added' } })
iii.registerTrigger({ type: 'queue', function_id: 'proj::catalog-on-sell', config: { topic: 'inventory.item-sold' } })
iii.registerTrigger({ type: 'queue', function_id: 'proj::sales-analytics', config: { topic: 'inventory.item-sold' } })
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Low-stock alerts race the sell projection.

notify::low-stock-alert and proj::catalog-on-sell consume inventory.item-sold independently, so this handler can read inventory-read before the decrement lands and miss threshold crossings. Put the post-sale stock on the ItemSold event, or trigger the alert from the code path that writes the updated projection.

💡 Possible direction
 const event = {
   type: 'ItemSold',
   sku,
+  name: item.name,
   quantity,
   revenue: quantity * item.price,
+  remaining_stock: item.stock - quantity,
   timestamp: new Date().toISOString(),
 }

 iii.registerFunction({ id: 'notify::low-stock-alert' }, async (event) => {
-  const item = await iii.trigger({ function_id: 'state::get', payload: { scope: 'inventory-read', key: event.sku } })
-  if (item && item.stock <= 5) {
+  if (event.remaining_stock <= 5) {
     await iii.trigger({
       function_id: 'notify::slack-low-stock',
-      payload: { sku: event.sku, name: item.name, remaining: item.stock },
+      payload: { sku: event.sku, name: event.name, remaining: event.remaining_stock },
       action: TriggerAction.Enqueue({ queue: 'alerts-notify' }),
     })
   }
 })

Also applies to: 162-177

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@references/event-driven-cqrs.js` around lines 154 - 157,
notify::low-stock-alert races with proj::catalog-on-sell because both
independently consume inventory.item-sold and the alert handler can read
inventory-read before the projection decrement has been written; fix by ensuring
the alert receives the post-sale stock value or by emitting/triggering the
low-stock notification from the projection update path after
proj::catalog-on-sell finishes writing inventory-read. Specifically, either
include the updated stock count on the inventory.item-sold event (so
notify::low-stock-alert can make a correct decision) or invoke
notify::low-stock-alert (or publish a dedicated low-stock topic) from inside the
proj::catalog-on-sell projection write routine once the decrement is persisted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant