Given that you're already using PersistentActor, it's reasonable to leverage its AtLeastOnceDelivery functionality for what you need. AtLeastOnceDelivery essentially ensures that the persistent sender actor will keep sending messages to the receiver at a configurable frequency until it receives confirmation from the receiver (or from some termination routine for canceling ongoing delivery attempts).
As with general PersistentActor (with or without AtLeastOnceDelivery), messages that are persisted will be re-sent should the JVM crash. In the case of AtLeastOnceDelivery, persisted messages will be re-sent upon system recovery until receipt of confirmation. Akka provides method deliver
to send each message tagged with a consecutive monotonically increasing deliveryId
and, upon receiving a confirmation with the corresponding deliveryId
from the receiver, uses method confirmDelivery
to signal successful delivery of the message.
The following snippet, which is part of the sample code from relevant Akka doc, highlights the key AtLeastOnceDelivery logic in the sender actor class (which extends PersistentActor with AtLeastOnceDelivery
). Note that the same persistence handler updateState
is used to persist events corresponding to deliver
and confirmDelivery
for consistent state recovery:
override def receiveCommand: Receive = {
case s: String =>
persist(MsgSent(s))(updateState)
case Confirm(deliveryId) =>
persist(MsgConfirmed(deliveryId))(updateState)
}
override def receiveRecover: Receive = {
case evt: Evt => updateState(evt)
}
def updateState(evt: Evt): Unit = evt match {
case MsgSent(s) =>
deliver(destination)(deliveryId => Msg(deliveryId, s))
case MsgConfirmed(deliveryId) =>
confirmDelivery(deliveryId)
}