I'm trying to figure out how to model the state of a remote "IoT" device with a persistent-actor, for example:
The user wants to turn on a light so we do the most logical.
OnCommand
LightTurnedOnEvent
and updates its state to on
So that makes sense but the problem here is the light is actually never turned on. Ok so then we build a LightControlActor
that knows low level hardware-controll voodoo. This actor listen for LightTurnedOnEvent
and when it gets it it does it thing and turnes on the light.
Awsome now we have a light turned on! But not happy. LightTurnedOnEvent
is kind of lying here, the light is not turned on yet. Following this logic LightTurnedOnEvent
should be generated by the LightControlActor
and my persistent actor should generate some SentRequestToTurnOnLight
but now this gets complicated for me with all the different semantics.
OnCommand
Persistent actor recivecs OnCommand
generate RequestedLightTurnOnEvent
and set state to pending.
LightController picks up on the RequestedLightTurnOnEvent
and tries to turn on the light on the external system.
So then what? Now how do I update the state of the persistent actor? Have the LightController send some veird command SetStateToOnCommand
?
So how do I update the persistent state when the light is actually turned on?
One idea is to go with something like "saga" for your events.
LightController: State idle
lightController ! OnCommand
persist(LightTurnOnAttempted)
lightControl ! LightTurnOnCommand
become(pending)
LightControl:
lightControl ! LightTurnOnCommand
performLightTurnOnAsyncFunction.map(_ => TurnOnLightCommand) pipeTo lightController
LightController: State pending
lightController ! TurnOnLightCommand
persist(LightTurnedOn)
become(initialized)
This gives you fine grained control. In case of crash and during the process of recovery, you can check whether the light was turned on or the LightController
was in pending state. If it was in pending state, you can resend the LightTurnOnCommand
.