With untyped actors there is explicit support for building Finite State Machines. No support is needed in Akka Typed as it is straightforward to represent FSMs with behaviors.
To see how the Akka Typed API can be used to model FSMs here’s the Buncher example ported from the untyped actor FSM docs. It demonstrates how to:
Model states using different behaviors
Model storing data at each state by representing the behavior as a method
Implement state timeouts
The events the FSM can receive become the type of message the Actor can receive:
source// FSM event becomes the type of the message Actor supportssealed trait EventfinalcaseclassSetTarget(ref:ActorRef[Batch])extendsEventfinalcaseclassQueue(obj:Any)extendsEventcaseobjectFlushextendsEventcaseobjectTimeoutextendsEvent
SetTarget is needed for starting it up, setting the destination for the Batches to be passed on; Queue will add to the internal queue while Flush will mark the end of a burst.
Untyped FSMs also have a D (data) type parameter. Akka Typed doesn’t need to be aware of this and it can be stored via defining your behaviors as methods.
source// states of the FSM represented as behaviorsdef idle(data:Data):Behavior[Event]=Behaviors.receiveMessage[Event]{ message:Event=>(message, data) match {case(SetTarget(ref),Uninitialized)=>
idle(Todo(ref,Vector.empty))case(Queue(obj), t @Todo(_, v))=>
active(t.copy(queue = v :+ obj))case _ =>Behaviors.unhandled
}}def active(data:Todo):Behavior[Event]=Behaviors.withTimers[Event]{ timers =>// instead of FSM state timeout
timers.startSingleTimer(Timeout,Timeout,1.second)Behaviors.receiveMessagePartial {caseFlush|Timeout=>
data.target !Batch(data.queue)
idle(data.copy(queue =Vector.empty))caseQueue(obj)=>
active(data.copy(queue = data.queue :+ obj))}}