Instance Management
EventFlow follows an event-sourced architecture where each machine instance (aggregate) maintains its state through a sequence of events. This page explains how instances are created, identified, and managed.
Event Sourcing Foundation
Every machine instance is an aggregate root in event sourcing terms:
When an event arrives:
- Identify the target aggregate (by aggregate_id)
- Load all previous events for that aggregate
- Replay events to rebuild current state
- Process the new event
- Persist the new event to the store
Aggregate Lifecycle
Creating a New Aggregate
The first event in a machine's flow creates a new aggregate instance. The system automatically generates a unique aggregate ID:
machine: @order
scenario: order lifecycle
on> :checkout from @customer // First event → creates NEW aggregate
// aggregate_id auto-generated: "order-abc123"
order moves to #pending
emit :payment_request to @paymentWhen :checkout arrives:
- No existing aggregate reference → System generates
aggregate_id - New aggregate created with state
#pending - Event stored:
{aggregate_id: "order-abc123", event: ":checkout", ...}
INFO
The > prefix indicates this is an API/public endpoint (externally accessible). Whether it creates a new aggregate depends on whether it's the first event in the machine's flow, not on the > prefix itself.
Subsequent Events
Events after the first one target an existing aggregate and require a valid reference:
on :payment_success from @payment // Requires EXISTING aggregate
order moves to #paid
on> :cancel_order from @customer // API endpoint, but requires existing aggregate
order moves to #cancelledIf a subsequent event arrives without a valid aggregate reference (via conversation context or explicit ID), the runtime throws an error.
Aggregate Reference
How does :payment_success know which order instance to update?
Answer: Through Conversation Context - see the Conversations page for details.
Event Routing Summary
The > prefix and aggregate creation are independent concepts:
>prefix = API/public endpoint (externally accessible)- Aggregate creation = determined by event position in flow (first event creates, subsequent events require reference)
| Event Type | API Endpoint? | Creates Aggregate? | Routing |
|---|---|---|---|
on> :event (first in flow) | Yes | Yes (new) | New aggregate_id generated |
on> :event (subsequent) | Yes | No | Requires aggregate reference, else error |
on :event (internal) | No | Depends on context | Conversation context → correct aggregate |
Example
machine: @order
scenario: checkout flow
// First event → creates new aggregate (order-abc123)
// Also an API endpoint (externally callable)
on> :checkout from @customer
order moves to #awaiting_payment
emit :payment_request to @payment
// Internal event → requires existing aggregate
// Routed via conversation context
on :payment_success from @payment
order moves to #paid
// API endpoint but NOT first event
// Requires aggregate reference in payload, else runtime error
on> :cancel_order from @customer
? order is in #awaiting_payment
order moves to #cancelledRuntime Error for Missing Reference
When a non-first event arrives without a valid aggregate reference:
EventFlowError: Cannot route event ':cancel_order' to @order
- No aggregate_id provided in event payload
- No conversation context available
Hint: This event requires an existing order aggregate.
Include 'order_id' in your request or use conversation context.Instance Isolation
Each instance has its own:
- State - current machine state
- Context - all
$variables - Event history - all events that have been processed
@order:abc123 → state: #paid, $total: 1200, $items: ["Laptop"]
@order:xyz789 → state: #pending, $total: 50, $items: ["Mouse"]Instances never share state. They only communicate through events.
State Reconstruction
Because all events are stored, state can be reconstructed at any point:
Events for order-abc123:
1. :checkout → state becomes #pending
2. :payment_request → (emit, no state change)
3. :payment_success → state becomes #paid
4. :shipped → state becomes #shipped
Current state: #shippedThis enables:
- Time-travel debugging - replay events to any point
- Audit trails - complete history of all changes
- State recovery - rebuild from events after failure
Multiple Instances
A machine definition is a template. Many instances can exist:
@order (machine definition)
├── @order:abc123 (instance 1)
├── @order:xyz789 (instance 2)
├── @order:def456 (instance 3)
└── ... (any number of instances)Each instance:
- Processes its own events
- Has its own state and context
- Is identified by a unique aggregate_id