Broadcasting Events
EventFlow supports broadcasting events to all instances of a machine within a system. This is useful when you need to notify multiple instances simultaneously, such as sending reminders to all pending orders or synchronizing traffic lights.
Basic Syntax
Use emit :event to all @machine to send an event to every instance:
emit :check_status to all @orderThis sends the :check_status event to every @order instance in the current system.
Sending Data with Broadcasts
Broadcasts support the same with clause as regular events:
// Inline data
emit :stock_alert to all @order
with $product_id, $remaining_stock
// Table format
emit :price_update to all @subscription
with:
| product_id | $product_id |
| new_price | $new_price |
| old_price | $old_price |State Filtering
Often you only want to broadcast to instances in specific states. Use in to filter:
// Only pending orders
emit :reminder to all @order in #pending
// Multiple states
emit :urgent_notice to all @order in #pending, #awaiting_paymentCombined Example
on :stock_depleted from @warehouse (api)
emit :check_availability to all @order in #pending
with $product_idExecution Semantics
Broadcasts follow the same principles as regular events:
| Aspect | Behavior |
|---|---|
| Delivery | Asynchronous, fire-and-forget |
| Parallelism | All instances receive the event in parallel |
| Ordering | No guaranteed order between recipients |
| Empty broadcast | Silently completes if no instances exist |
| Scope | Only instances within the same system |
Snapshot Semantics
When a broadcast is sent, EventFlow takes a snapshot of matching instances at that moment. Instances created during the broadcast delivery are not included.
// If @order:001, @order:002 exist when this runs,
// only those two receive the event
emit :notify to all @order
// @order:003 created immediately after won't receive itConversation Context
Unlike single-target events, broadcasts create a new conversation for each recipient:
// Regular emit - single conversation
emit :request to @payment
// conversation_id: conv-001
// Broadcast - separate conversations per recipient
emit :reminder to all @order
// @order:001 → conversation_id: conv-002
// @order:002 → conversation_id: conv-003
// @order:003 → conversation_id: conv-004This means each recipient can respond independently without interfering with other recipients' conversations.
Use Cases
Inventory Management
Notify all pending orders when stock changes:
system: e_commerce
machine: @inventory
on :stock_depleted from @warehouse (api)
emit :check_availability to all @order in #pending
with $product_id
machine: @order
on :check_availability from @inventory
? $items contains $product_id
order moves to #needs_review
emit :notify_customer to @notificationDeadline Reminders
Send reminders to all documents awaiting approval:
system: document_approval
machine: @approval_manager
on :deadline_approaching
triggered: every day at 9:00
emit :reminder to all @document in #pending_approval
with $days_remaining
machine: @document
on :reminder from @approval_manager
? $days_remaining < 3
emit :urgent_reminder to @approverEmergency Synchronization
Coordinate multiple traffic lights during emergencies:
system: traffic_control
machine: @intersection_controller
on :emergency_vehicle_detected from @sensor (api)
emit :go_red to all @traffic_light in #green
emit :go_red to all @traffic_light in #yellow
machine: @traffic_light
on :go_red from @intersection_controller
light moves to #redLane Diagram Representation
Broadcasts are shown with double lines (═══) in lane diagrams:
Best Practices
Use State Filters
Always filter by state when possible to avoid unnecessary processing:
// Good - only notifies relevant orders
emit :shipping_delay to all @order in #shipped, #in_transit
// Less efficient - all orders process the event
emit :shipping_delay to all @orderKeep Broadcast Data Minimal
Since the same data goes to all recipients, include only what's universally needed:
// Good - minimal shared data
emit :price_change to all @subscription
with $product_id, $new_price
// Avoid - recipient-specific data doesn't make sense
emit :price_change to all @subscription
with $subscription_specific_discount // Each subscription has different discountHandle Empty Broadcasts Gracefully
Broadcasts to zero instances complete silently. Design your flow to handle this:
on :send_reminders from @scheduler
emit :reminder to all @task in #overdue
// If no overdue tasks, this simply does nothing
// No error, no special handling neededConsider Response Aggregation
If you need to know when all recipients have processed the broadcast, use a counter pattern:
machine: @coordinator
on :start_validation from @admin (api)
$pending_count becomes count of @validator in #idle
emit :validate to all @validator in #idle
coordinator moves to #awaiting_responses
on :validation_complete from @validator
$pending_count decreases by 1
? $pending_count equals 0
coordinator moves to #all_validated
emit :validation_finished to @adminSystem Scope
Broadcasts only reach instances within the same system: definition. They cannot cross system boundaries:
system: order_management
// Broadcast here only reaches @order instances
// defined within order_management system
system: inventory_management
// @order instances here are separate
// and won't receive broadcasts from order_managementFor cross-system communication, use regular emit to a specific machine that can then broadcast within its own system.