Skip to content

Runtime EventBus vs Integration Messaging vs Outbox

Purpose

This document clarifies the architectural boundaries, responsibilities, and correct usage of:

  • Runtime EventBus
  • Integration Messaging
  • Outbox

The goal is to avoid responsibility overlap, prevent SRP violations, and provide a clear decision framework for contributors.

This is a normative architecture decision, not a suggestion.


High-Level Comparison

+-------------------+------------------------+----------------------+
| Concern           | Runtime EventBus       | Integration Messaging|
|                   |                        | / Outbox             |
+-------------------+------------------------+----------------------+
| Scope             | In-process             | Cross-process        |
| Persistence       | No                     | Yes (Outbox)         |
| Delivery Guarantee| No                     | Yes                  |
| Retry / DLQ       | No                     | Yes                  |
| Use Case          | Coordination           | Integration          |
| Latency           | Very low               | Higher               |
| Lifecycle         | Application runtime    | Background workers   |
+-------------------+------------------------+----------------------+

1. Runtime EventBus

Definition

The Runtime EventBus is an in-process coordination mechanism.

It exists to decouple components inside the same running application, enabling:

  • Local fan-out
  • Agent orchestration
  • Tool execution lifecycle hooks
  • RAG step coordination
  • Observability and tracing propagation

It is not a messaging system.


Core Characteristics

  • In-memory
  • Non-persistent
  • No retry guarantees
  • No ordering guarantees across restarts
  • No delivery guarantees
  • Extremely low latency

What Runtime EventBus MUST do

  • Publish and subscribe to runtime signals
  • Support async handlers
  • Propagate tracing context
  • Fail fast

What Runtime EventBus MUST NOT do

  • Persist events
  • Retry delivery
  • Guarantee delivery
  • Integrate with brokers
  • Replace messaging systems
  • Replace Outbox

Example Usage

event_bus.publish(
    event_name="agent.step.completed",
    payload={
        "agent_id": agent_id,
        "step": step_name,
        "duration_ms": duration,
    }
)

Typical Use Cases

  • Agent execution steps
  • Tool invocation lifecycle
  • RAG pipeline coordination
  • Internal state transitions
  • Observability hooks

2. Integration Messaging

Definition

Integration Messaging is the system responsible for cross-process and cross-service communication.

It is built around message brokers (Kafka, Redis Pub/Sub, Google PubSub, etc.).

This layer is responsible for reliability, retries, DLQs, delayed delivery, and telemetry.


Core Characteristics

  • Cross-process
  • Broker-backed
  • Retry-aware
  • DLQ-aware
  • Delay-aware
  • Observability-rich
  • Payload-agnostic

What Integration Messaging MUST do

  • Define Producer / Consumer protocols
  • Abstract broker-specific behavior
  • Handle retries and DLQ
  • Support delayed delivery
  • Capture lineage and causality
  • Ensure telemetry consistency

What Integration Messaging MUST NOT do

  • Act as an in-process EventBus
  • Manage domain transactions
  • Assume transactional consistency
  • Implement business logic

Example Usage

producer.publish(
    topic="documents.ingested",
    message={
        "document_id": doc_id,
        "tenant_id": tenant_id,
    }
)

Typical Use Cases

  • Service-to-service communication
  • Async background workflows
  • Event-driven integrations
  • Delayed processing
  • External consumers

3. Outbox

Definition

The Outbox is a reliability pattern, not an event system.

It guarantees that side effects (messages, webhooks, integrations) are emitted only after a successful transaction, and at least once.

It decouples transactional state changes from integration effects.


Core Characteristics

  • Persistent
  • Transaction-bound
  • Retry-aware
  • Ordering-aware
  • Storage-backed
  • Broker-agnostic

What Outbox MUST do

  • Persist side effects atomically with domain transactions
  • Retry failed deliveries
  • Enforce ordering when required
  • Prevent message loss
  • Support DLQ semantics

What Outbox MUST NOT do

  • Act as a runtime EventBus
  • Replace Integration Messaging
  • Know about subscribers
  • Contain business logic

Example Usage

@publish_on_success(
    event_name="memory.created",
    payload_builder=lambda result: {
        "memory_id": result.id,
        "tenant_id": result.tenant_id,
    }
)
async def create_memory(...):
    ...

4. Relationship Between the Three

Correct Dependency Direction

Domain Logic
    |
    v
Outbox (Persistence & Reliability)
    |
    v
Integration Messaging (Broker)

Separately:

Runtime Components
    |
    v
Runtime EventBus (In-Process)

Forbidden Couplings

The following are explicitly forbidden:

Outbox -> Runtime EventBus
Runtime EventBus -> Outbox
Runtime EventBus -> Messaging Broker
Messaging Broker -> Runtime EventBus

5. Decision Guide

Use Runtime EventBus when:

  • Communication is local
  • No persistence is required
  • Failure can be tolerated
  • Low latency is critical

Use Integration Messaging when:

  • Communication crosses process boundaries
  • Consumers may be offline
  • Retry and DLQ are required
  • External systems are involved

Use Outbox when:

  • Side effects depend on successful transactions
  • Message loss is unacceptable
  • Ordering matters
  • Exactly-once semantics are desired at the domain level

6. Architectural Rule (Non-Negotiable)

Runtime coordination, integration messaging, and transactional reliability are three distinct concerns and MUST remain separate.

Any design that merges these concerns is considered architecturally invalid in Athomic.


Status

  • Runtime EventBus: Runtime coordination layer
  • Integration Messaging: Integration and transport layer
  • Outbox: Transactional reliability layer

All three are intentionally independent.