akka.actor.Timers.scala Maven / Gradle / Ivy
/*
* Copyright (C) 2017-2019 Lightbend Inc.
*/
package akka.actor
import akka.util.JavaDurationConverters._
import scala.concurrent.duration.FiniteDuration
import akka.annotation.DoNotInherit
import akka.dispatch.Envelope
import akka.util.OptionVal
/**
* Scala API: Mix in Timers into your Actor to get support for scheduled
* `self` messages via [[TimerScheduler]].
*
* Timers are bound to the lifecycle of the actor that owns it,
* and thus are cancelled automatically when it is restarted or stopped.
*/
trait Timers extends Actor {
private def actorCell = context.asInstanceOf[ActorCell]
private val _timers = new TimerSchedulerImpl(context)
/**
* Start and cancel timers via the enclosed `TimerScheduler`.
*/
final def timers: TimerScheduler = _timers
override protected[akka] def aroundPreRestart(reason: Throwable, message: Option[Any]): Unit = {
timers.cancelAll()
super.aroundPreRestart(reason, message)
}
override protected[akka] def aroundPostStop(): Unit = {
timers.cancelAll()
super.aroundPostStop()
}
override protected[akka] def aroundReceive(receive: Actor.Receive, msg: Any): Unit = {
msg match {
case timerMsg: TimerSchedulerImpl.TimerMsg =>
_timers.interceptTimerMsg(timerMsg) match {
case OptionVal.Some(m: AutoReceivedMessage) =>
context.asInstanceOf[ActorCell].autoReceiveMessage(Envelope(m, self))
case OptionVal.Some(m) =>
if (this.isInstanceOf[Stash]) {
// this is important for stash interaction, as stash will look directly at currentMessage #24557
actorCell.currentMessage = actorCell.currentMessage.copy(message = m)
}
super.aroundReceive(receive, m)
case OptionVal.None => // discard
}
case _ =>
super.aroundReceive(receive, msg)
}
}
}
/**
* Java API: Support for scheduled `self` messages via [[TimerScheduler]].
*
* Timers are bound to the lifecycle of the actor that owns it,
* and thus are cancelled automatically when it is restarted or stopped.
*/
abstract class AbstractActorWithTimers extends AbstractActor with Timers {
/**
* Start and cancel timers via the enclosed `TimerScheduler`.
*/
final def getTimers: TimerScheduler = timers
}
/**
* Support for scheduled `self` messages in an actor.
* It is used by mixing in trait `Timers` in Scala or extending `AbstractActorWithTimers`
* in Java.
*
* Timers are bound to the lifecycle of the actor that owns it,
* and thus are cancelled automatically when it is restarted or stopped.
*
* `TimerScheduler` is not thread-safe, i.e. it must only be used within
* the actor that owns it.
*/
@DoNotInherit abstract class TimerScheduler {
/**
* Start a periodic timer that will send `msg` to the `self` actor at
* a fixed `interval`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
*/
def startPeriodicTimer(key: Any, msg: Any, interval: FiniteDuration): Unit
/**
* Start a periodic timer that will send `msg` to the `self` actor at
* a fixed `interval`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
*/
def startPeriodicTimer(key: Any, msg: Any, interval: java.time.Duration): Unit =
startPeriodicTimer(key, msg, interval.asScala)
/**
* Start a timer that will send `msg` once to the `self` actor after
* the given `timeout`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
*/
def startSingleTimer(key: Any, msg: Any, timeout: FiniteDuration): Unit
/**
* Start a timer that will send `msg` once to the `self` actor after
* the given `timeout`.
*
* Each timer has a key and if a new timer with same key is started
* the previous is cancelled and it's guaranteed that a message from the
* previous timer is not received, even though it might already be enqueued
* in the mailbox when the new timer is started.
*/
def startSingleTimer(key: Any, msg: Any, timeout: java.time.Duration): Unit =
startSingleTimer(key, msg, timeout.asScala)
/**
* Check if a timer with a given `key` is active.
*/
def isTimerActive(key: Any): Boolean
/**
* Cancel a timer with a given `key`.
* If canceling a timer that was already canceled, or key never was used to start a timer
* this operation will do nothing.
*
* It is guaranteed that a message from a canceled timer, including its previous incarnation
* for the same key, will not be received by the actor, even though the message might already
* be enqueued in the mailbox when cancel is called.
*/
def cancel(key: Any): Unit
/**
* Cancel all timers.
*/
def cancelAll(): Unit
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy