> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/temporalio/temporal/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Sourcing Implementation

> How Temporal implements event sourcing for durable workflow execution

# Event Sourcing Implementation

Temporal's durable execution guarantee is built on **event sourcing**: an architectural pattern where state changes are stored as a sequence of immutable events. This page explains how Temporal implements event sourcing to achieve reliable workflow execution.

## What is Event Sourcing?

Event sourcing is a pattern where:

1. **All state changes** are captured as events
2. **Events are immutable** and stored in append-only logs
3. **Current state** can be reconstructed by replaying events from the beginning
4. **Historical state** can be reconstructed by replaying events up to any point in time

```mermaid theme={null}
flowchart LR
    subgraph Events["Event Log (Immutable)"]
        direction TB
        E1["Event 1<br/>WorkflowStarted"]
        E2["Event 2<br/>ActivityScheduled"]
        E3["Event 3<br/>ActivityCompleted"]
        E4["Event 4<br/>WorkflowCompleted"]
        E1 --> E2 --> E3 --> E4
    end
    
    subgraph State["Current State (Derived)"]
        MS["Mutable State<br/>Status: Completed<br/>Result: Success"]
    end
    
    Events -->|Replay| State
    
    style Events fill:#e1f5ff
    style State fill:#fff4e1
```

## Why Event Sourcing for Workflows?

Event sourcing is particularly well-suited for workflow execution:

<AccordionGroup>
  <Accordion title="Durability">
    Events are persisted before being applied, ensuring no state is lost even if the server crashes.
  </Accordion>

  <Accordion title="Auditability">
    Complete history of what happened and when, enabling debugging and compliance.
  </Accordion>

  <Accordion title="Replay-Based Execution">
    Workers can reconstruct workflow state by replaying events, enabling deterministic execution.
  </Accordion>

  <Accordion title="Time Travel">
    Can reconstruct state at any point in the past for debugging or workflow reset.
  </Accordion>

  <Accordion title="Conflict Resolution">
    In multi-cluster setups, event logs can be merged and conflicts resolved.
  </Accordion>
</AccordionGroup>

## Temporal's Event Sourcing Model

### Workflow History Events

In Temporal, **Workflow History Events** are the foundation of event sourcing:

* Each workflow execution has its own linear sequence of events
* Events are assigned monotonically increasing **EventIDs** (starting at 1)
* Events are **publicly exposed** via APIs (unlike internal state)
* Events contain both metadata and optional payloads

### Event Structure

Each event contains:

```protobuf theme={null}
message HistoryEvent {
    int64 event_id = 1;                    // Monotonic sequence number
    google.protobuf.Timestamp event_time = 2;  // When event occurred
    EventType event_type = 3;              // Type of event
    int64 task_id = 4;                     // Associated task ID
    
    // Event-specific attributes (one of):
    WorkflowExecutionStartedEventAttributes workflow_execution_started_attributes = 5;
    ActivityTaskScheduledEventAttributes activity_task_scheduled_attributes = 6;
    // ... etc
}
```

### Event Types

Temporal defines dozens of event types representing state transitions:

**Workflow Execution:**

* `WorkflowExecutionStarted`
* `WorkflowExecutionCompleted`
* `WorkflowExecutionFailed`
* `WorkflowExecutionTimedOut`
* `WorkflowExecutionCanceled`
* `WorkflowExecutionTerminated`

**Workflow Tasks:**

* `WorkflowTaskScheduled`
* `WorkflowTaskStarted`
* `WorkflowTaskCompleted`
* `WorkflowTaskFailed`
* `WorkflowTaskTimedOut`

**Activities:**

* `ActivityTaskScheduled`
* `ActivityTaskStarted`
* `ActivityTaskCompleted`
* `ActivityTaskFailed`
* `ActivityTaskTimedOut`
* `ActivityTaskCancelRequested`
* `ActivityTaskCanceled`

**Timers:**

* `TimerStarted`
* `TimerFired`
* `TimerCanceled`

**Child Workflows:**

* `StartChildWorkflowExecutionInitiated`
* `ChildWorkflowExecutionStarted`
* `ChildWorkflowExecutionCompleted`
* `ChildWorkflowExecutionFailed`

**Signals and Updates:**

* `WorkflowExecutionSignaled`
* `WorkflowExecutionUpdateAccepted`
* `WorkflowExecutionUpdateCompleted`

See [`temporal/api/enums/v1/event_type.proto`](https://github.com/temporalio/api/blob/master/temporal/api/enums/v1/event_type.proto) for the complete list.

## Event Generation

### Who Creates Events?

Events are created by the **History Service** in response to:

1. **User Application Requests**: Start, Signal, Cancel, Terminate, Update
2. **Worker Completions**: Workflow Task completed, Activity Task completed
3. **Timer Expirations**: Workflow timers, activity timeouts, workflow timeouts
4. **System Operations**: Workflow reset, replication

### Event Generation Flow

```mermaid theme={null}
flowchart TB
    Input["Input<br/>(Request/Timer/Completion)"]
    
    subgraph History["History Service"]
        Handler[Request Handler]
        Logic[State Transition Logic]
        Events["Generate Events<br/>(in-memory)"]
    end
    
    subgraph Persistence
        Append["Append Events<br/>to History Log"]
        Update["Update Mutable State<br/>(atomic transaction)"]
    end
    
    Input --> Handler
    Handler --> Logic
    Logic --> Events
    Events --> Append
    Events --> Update
    
    style History fill:#fff4e1
    style Persistence fill:#e1f5ff
```

### Event Attributes

Each event type has specific attributes. For example:

**`ActivityTaskScheduled` event:**

```protobuf theme={null}
message ActivityTaskScheduledEventAttributes {
    string activity_id = 1;
    ActivityType activity_type = 2;
    string task_queue = 3;
    Payloads input = 4;
    Duration schedule_to_close_timeout = 5;
    Duration schedule_to_start_timeout = 6;
    Duration start_to_close_timeout = 7;
    Duration heartbeat_timeout = 8;
    RetryPolicy retry_policy = 9;
    // ... etc
}
```

## Event Persistence

### Storage Structure

Events are stored in the **history\_node** table (Cassandra) or equivalent:

* Events are grouped into **batches** (typically 1-100 events per batch)
* Each batch is a **binary blob** (protobuf serialized)
* Batches are identified by `(namespaceID, workflowID, runID, nodeID)`
* NodeID represents the batch number

```sql theme={null}
-- Simplified Cassandra schema
CREATE TABLE history_node (
    tree_id         uuid,
    branch_id       uuid,
    node_id         bigint,
    txn_id          bigint,
    data            blob,      -- Serialized batch of events
    data_encoding   text,
    PRIMARY KEY ((tree_id), branch_id, node_id, txn_id)
);
```

### Batching Strategy

Events are batched for efficiency:

* **Multiple events per write**: Reduces database round-trips
* **Configurable batch size**: Balance between latency and throughput
* **Atomic batch writes**: All events in a batch are written together

### Event Versioning

For workflow reset and replication:

* Events are organized in a **tree structure**
* Each branch has a **branchToken**
* Enables branching history for reset scenarios

```mermaid theme={null}
flowchart LR
    subgraph Original["Original Execution"]
        O1[Event 1] --> O2[Event 2] --> O3[Event 3] --> O4[Event 4]
    end
    
    subgraph Reset["After Reset to Event 2"]
        R1[Event 1] --> R2[Event 2] --> R3[Event 3'] --> R4[Event 4']
    end
    
    O2 -.->|Reset| R2
    
    style Original fill:#ffe1e1
    style Reset fill:#e1ffe1
```

## State Reconstruction

### Mutable State as Cache

While events are the source of truth, Temporal maintains **Mutable State** as a cache:

* Summarizes current workflow state
* Avoids replaying entire history on every request
* Persisted alongside events
* Can be regenerated from events if corrupted

### Consistency Model

Mutable State and Events are kept consistent:

```go theme={null}
// Pseudo-code for state transition
func UpdateWorkflow(workflow, events, tasks) error {
    tx := db.BeginTransaction()
    
    // 1. Append events to history log
    tx.AppendEvents(workflow.ID, events)
    
    // 2. Update mutable state (includes last event ID)
    workflow.MutableState.LastEventID = events.Last().ID
    tx.UpdateMutableState(workflow.ID, workflow.MutableState)
    
    // 3. Add tasks for processing
    tx.AddTasks(workflow.ID, tasks)
    
    // All or nothing
    return tx.Commit()
}
```

<Info>
  Mutable State stores the `LastEventID` it reflects. If Mutable State is lost or corrupted, it can be rebuilt by replaying events from the beginning.
</Info>

### Replay Process

When a worker receives a Workflow Task:

1. **Receive History Events**: Worker gets events since last Workflow Task
2. **Replay Workflow Code**: Worker executes workflow function
3. **Compare Commands**: Worker's commands must match history exactly
4. **Non-Determinism Detection**: If commands diverge, workflow fails

```mermaid theme={null}
sequenceDiagram
    participant History as History Service
    participant Worker
    participant Workflow as Workflow Code
    
    Worker->>History: PollWorkflowTask
    History-->>Worker: Events [1-10]
    
    Worker->>Workflow: Replay(Events[1-10])
    Workflow->>Workflow: Execute deterministically
    Workflow-->>Worker: Commands
    
    alt Commands match history
        Worker->>History: Commands [11-15]
        History-->>Worker: OK
    else Commands don't match
        Worker->>History: WorkflowTaskFailed<br/>(Non-determinism)
    end
```

## Deterministic Execution

### Why Determinism Matters

Event sourcing requires **deterministic replay**:

* Workflow code must produce the same commands when replayed
* Same events in, same commands out
* Enables workers to resume workflows without state serialization

### Determinism Rules

Workflow code must:

<Warning>
  **Do NOT:**

  * Call non-deterministic functions (random, time, UUIDs)
  * Perform I/O or network calls directly
  * Access mutable global state
  * Use language features with non-deterministic behavior
</Warning>

<Info>
  **Do:**

  * Use workflow APIs for time, randomness, UUIDs
  * Schedule Activities for side effects
  * Use Signals/Queries for external input
  * Write pure, deterministic logic
</Info>

### Enforcing Determinism

Temporal SDKs enforce determinism:

* **Workflow sandbox**: Restricts available APIs
* **Deterministic time**: `workflow.Now()` returns time from events
* **Deterministic random**: `workflow.Random()` uses seeded RNG
* **Deterministic UUID**: `workflow.UUID()` generates deterministic UUIDs

## Event-Driven State Machine

### Commands as Intent

Workers don't directly modify state; they express **intent via Commands**:

* `ScheduleActivityTask`
* `StartTimer`
* `StartChildWorkflowExecution`
* `CompleteWorkflowExecution`
* `CancelTimer`

Commands are sent when a Workflow Task completes.

### Command Processing

History Service processes commands:

1. **Validate**: Check if command is valid given current state
2. **Generate Events**: Create events representing the command's effect
3. **Update State**: Apply events to Mutable State
4. **Create Tasks**: Schedule follow-up tasks (Transfer, Timer)

```mermaid theme={null}
flowchart LR
    Worker["Worker<br/>RespondWorkflowTaskCompleted"] -->|Commands| History[History Service]
    
    subgraph Processing
        Validate[Validate Commands]
        Generate[Generate Events]
        Persist[Persist Events & State]
        Tasks[Create Tasks]
        
        Validate --> Generate --> Persist --> Tasks
    end
    
    History --> Processing
    Processing --> Next[Next Workflow Task]
    
    style Processing fill:#fff4e1
```

## Querying Event History

### GetWorkflowExecutionHistory API

Users can retrieve workflow history:

```go theme={null}
resp, err := client.GetWorkflowHistory(
    ctx,
    workflowID,
    runID,
    false,  // waitForNewEvents
    enumspb.HISTORY_EVENT_FILTER_TYPE_ALL_EVENT,
)

for resp.HasNext() {
    event, err := resp.Next()
    // Process event
}
```

### Event Filtering

Filters available:

* **All Events**: Complete history
* **Close Event**: Only workflow completion event

### Pagination

History can be large:

* Events are paginated (default page size: 1000)
* Use continuation tokens for next page
* Can be streamed efficiently

## Advanced Topics

### Workflow Reset

Reset allows "rewinding" a workflow:

1. Choose a **reset point** (EventID)
2. Create a **new branch** from that point
3. Original branch is marked as ancestor
4. New execution continues from reset point

```go theme={null}
// Reset workflow to Event ID 50
client.ResetWorkflowExecution(ctx, &workflowservice.ResetWorkflowExecutionRequest{
    WorkflowId: workflowID,
    RunId:      runID,
    Reason:     "Fixing bug in activity",
    EventId:    50,
})
```

### Multi-Cluster Replication

For global namespaces:

* Events are replicated across clusters
* Each cluster maintains its own event log
* **Version vectors** track causal relationships
* **Conflict resolution** merges divergent histories

### History Archival

Old workflows can be archived:

* Events moved from primary database to archival storage (S3, GCS)
* Reduces load on primary database
* Archived history can be retrieved on demand
* Configurable retention period before archival

### History Compression

For long-running workflows:

* History can be compressed (gzip, etc.)
* Reduces storage costs
* Transparent decompression on read

## Performance Considerations

### Event Size

<Warning>
  Large event payloads impact performance:

  * Slower persistence writes
  * More memory for replay
  * Higher network transfer costs

  Limit payload sizes via dynamic config:

  * `BlobSizeLimitError`: Hard limit (default 2MB)
  * `BlobSizeLimitWarn`: Warning threshold (default 512KB)
</Warning>

### History Size

Long-running workflows accumulate events:

* Use **Continue-As-New** to "reset" a workflow's history
* Starts a new run with same workflow ID
* Previous run's history is preserved but not loaded

```go theme={null}
// Workflow code
if executionCount > 1000 {
    return workflow.NewContinueAsNewError(
        ctx,
        WorkflowFunction,
        newArgs,
    )
}
```

### Read Optimization

Mutable State caching:

* Recently accessed workflows are cached in memory
* Avoids reading history from database
* Significantly improves latency
* Cache invalidation on state changes

## Comparison with Other Patterns

### vs. CRUD (Mutable State)

Traditional CRUD:

* Overwrites state in place
* No history of changes
* Difficult to debug past issues

Event Sourcing:

* Appends immutable events
* Complete audit trail
* Can reconstruct any past state

### vs. Event Streaming (Kafka)

Kafka-style event streaming:

* Generic event transport
* No built-in state management
* Consumers maintain their own state

Temporal Event Sourcing:

* Specialized for workflow execution
* Integrated state management (Mutable State)
* Deterministic replay semantics
* Strongly typed event schemas

## Further Reading

<CardGroup cols={2}>
  <Card title="History Service" icon="database" href="/architecture/history-service">
    How History Service manages events
  </Card>

  <Card title="Workflow Lifecycle" icon="diagram-project" href="/architecture/workflow-lifecycle">
    See event generation in action
  </Card>

  <Card title="Architecture Overview" icon="sitemap" href="/architecture/overview">
    High-level system architecture
  </Card>

  <Card title="SDK Documentation" icon="book" href="https://docs.temporal.io/dev-guide">
    Writing deterministic workflows
  </Card>
</CardGroup>
