Skip to content

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:

flow
emit :check_status to all @order

This 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:

flow
// 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:

flow
// Only pending orders
emit :reminder to all @order in #pending

// Multiple states
emit :urgent_notice to all @order in #pending, #awaiting_payment

Combined Example

flow
on :stock_depleted from @warehouse (api)
  emit :check_availability to all @order in #pending
    with $product_id

Execution Semantics

Broadcasts follow the same principles as regular events:

AspectBehavior
DeliveryAsynchronous, fire-and-forget
ParallelismAll instances receive the event in parallel
OrderingNo guaranteed order between recipients
Empty broadcastSilently completes if no instances exist
ScopeOnly 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.

flow
// 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 it

Conversation Context

Unlike single-target events, broadcasts create a new conversation for each recipient:

flow
// 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-004

This means each recipient can respond independently without interfering with other recipients' conversations.

Use Cases

Inventory Management

Notify all pending orders when stock changes:

flow
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 @notification

Deadline Reminders

Send reminders to all documents awaiting approval:

flow
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 @approver

Emergency Synchronization

Coordinate multiple traffic lights during emergencies:

flow
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 #red

Lane Diagram Representation

Broadcasts are shown with double lines (═══) in lane diagrams:

@inventory@order:001@order:002@order:003:stock_depleted(all)[check]→ #review[check](no match)[check]→ #reviewLegend:broadcast (to all)single event

Best Practices

Use State Filters

Always filter by state when possible to avoid unnecessary processing:

flow
// 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 @order

Keep Broadcast Data Minimal

Since the same data goes to all recipients, include only what's universally needed:

flow
// 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 discount

Handle Empty Broadcasts Gracefully

Broadcasts to zero instances complete silently. Design your flow to handle this:

flow
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 needed

Consider Response Aggregation

If you need to know when all recipients have processed the broadcast, use a counter pattern:

flow
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 @admin

System Scope

Broadcasts only reach instances within the same system: definition. They cannot cross system boundaries:

flow
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_management

For cross-system communication, use regular emit to a specific machine that can then broadcast within its own system.

Released under the MIT License.