Support for Actor timers, and fix bug in FSM, #15733

* backport of the timers from Akka Typed, #16742
* also fixed a small bug in FSM timers, which could result in that
  a timer from a previous incarnation was let through to new
  incarnation after restart
* no more need for the complicated "how to" section in docs of
  how to schedule periodic messages
This commit is contained in:
Patrik Nordwall 2017-06-16 11:31:00 +02:00
parent 71175eaf54
commit f8a1d635fa
17 changed files with 712 additions and 333 deletions

View file

@ -288,9 +288,9 @@ object PersistentFSM {
/**
* INTERNAL API
*/
// FIXME: what about the cancellable?
@InternalApi
private[persistence] final case class Timer(name: String, msg: Any, repeat: Boolean, generation: Int)(context: ActorContext)
private[persistence] final case class Timer(name: String, msg: Any, repeat: Boolean, generation: Int,
owner: AnyRef)(context: ActorContext)
extends NoSerializationVerificationNeeded {
private var ref: Option[Cancellable] = _
private val scheduler = context.system.scheduler

View file

@ -211,7 +211,7 @@ trait PersistentFSMBase[S, D, E] extends Actor with Listeners with ActorLogging
if (timers contains name) {
timers(name).cancel
}
val timer = Timer(name, msg, repeat, timerGen.next)(context)
val timer = Timer(name, msg, repeat, timerGen.next, this)(context)
timer.schedule(self, timeout)
timers(name) = timer
}
@ -412,8 +412,8 @@ trait PersistentFSMBase[S, D, E] extends Actor with Listeners with ActorLogging
if (generation == gen) {
processMsg(StateTimeout, "state timeout")
}
case t @ Timer(name, msg, repeat, gen)
if ((timers contains name) && (timers(name).generation == gen)) {
case t @ Timer(name, msg, repeat, gen, owner)
if ((owner eq this) && (timers contains name) && (timers(name).generation == gen)) {
if (timeoutFuture.isDefined) {
timeoutFuture.get.cancel()
timeoutFuture = None
@ -575,10 +575,10 @@ trait LoggingPersistentFSM[S, D, E] extends PersistentFSMBase[S, D, E] { this: A
private[akka] abstract override def processEvent(event: Event, source: AnyRef): Unit = {
if (debugEvent) {
val srcstr = source match {
case s: String s
case Timer(name, _, _, _) "timer " + name
case a: ActorRef a.toString
case _ "unknown"
case s: String s
case Timer(name, _, _, _, _) "timer " + name
case a: ActorRef a.toString
case _ "unknown"
}
log.debug("processing {} from {} in state {}", event, srcstr, stateName)
}