Skip to content

The Actor Model

EventMachine is an actor system. Each machine instance is an actor — an independent entity with encapsulated state that communicates exclusively through message passing.

What Makes EventMachine an Actor System?

The Actor Model, introduced by Carl Hewitt in 1973, defines actors as the fundamental unit of computation. Every actor can:

  1. Receive messages → EventMachine machines receive events via send()
  2. Change internal state → State transitions and context mutations
  3. Send messages to other actorssendTo(), dispatchTo(), raise()
  4. Create new actorsmachine and job keys create child actors

EventMachine maps these principles to a Laravel-native, database-backed architecture.

Actor Model Mapping

Actor Model PrincipleEventMachine Equivalent
Encapsulated StateContextManager — private, only accessible within the machine
Message Passingsend(), sendTo(), dispatchTo(), raise()
No Shared StateEach machine has its own context, isolated from others
Create New Actorsmachine key (child machines), job key (job actors)
Behavior for Next MessageState transitions determine which events are accepted
Actor IdentitymachineClass + rootEventId
Actor Persistencemachine_events table
Actor HierarchyParent-child via machine/job key delegation

Virtual Actor Model

EventMachine follows the Virtual Actor pattern, similar to Microsoft Orleans:

  • Database-backed: Machines are persisted in the database. They "exist" conceptually even when not loaded in memory.
  • Identity-based: Any machine can be addressed by its class + root event ID, from anywhere in the application.
  • Always-available: sendTo() can reach any machine instance — restore it, deliver the event, persist the result.
  • Auto-persistence: Every transition is automatically written to the database.
Orleans ConceptEventMachine Equivalent
GrainMachine instance
Grain Identity (type + key)machineClass + rootEventId
Grain StateContextManager
Grain ActivationMachine::create(state: $rootEventId) (restore)
Grain-to-Grain callsendTo() / dispatchTo()
Grain Persistencemachine_events table

Coming From Other Actor Systems

If you've used other actor frameworks, here's how EventMachine maps:

Your FrameworkYour ConceptEventMachine
Akkatell (fire-and-forget)sendTo() / dispatchTo()
Akkaask (request-response)Not available — use @done
AkkaSupervision (restart/stop)@fail / @timeout transitions
ElixirGenServer.castdispatchTo()
ElixirGenServer.callsendTo() (sync, but no response)
Elixirhandle_infoon map events
ElixirSupervision treeParent-child via machine key
XStateinvokemachine key
XStatespawnNot available — use dispatchTo() + Machine::create()
XStatesendTo(actorRef)sendTo(machineClass, rootEventId)
XStatefromPromisejob key

Event Sources

EventMachine receives events from multiple sources:

SourceMechanismExample
HTTPEndpointsUser submits a form → machine receives SUBMIT
Timeafter/every on transitions7 days pass → machine receives ORDER_EXPIRED
Cronschedules + MachineSchedulerDaily at 00:10 → all expired instances receive CHECK_EXPIRY
Child lifecycle@done/@fail/@timeoutChild machine completes → parent receives @done
Cross-machinesendTo()/dispatchTo()Another machine sends an event
Selfraise()Machine raises an internal event

What EventMachine Is NOT

  • Not an in-memory actor system — State is database-backed, not in process memory
  • Not a long-running process — PHP runs request-response, not persistent actors
  • Not a distributed system — Single Laravel application (use Horizon for queue workers)
  • Not hot-reloadable — PHP reloads on every request by nature
  • No request-response pattern — Messages are one-way; use @done for results

Testing

Actors are testable in isolation. See Testing Overview.

Released under the MIT License.