Document how to schedule periodic messages from an actor to itself. #2513

This commit is contained in:
Björn Antonsson 2012-10-05 15:15:17 +02:00
parent 89c1f66b1f
commit 99ad1e0eeb
5 changed files with 352 additions and 2 deletions

View file

@ -0,0 +1,98 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.pattern
import language.postfixOps
import akka.actor.{ Props, ActorRef, Actor }
import scala.concurrent.util.duration._
import scala.concurrent.util.{ FiniteDuration, Duration }
import akka.testkit.{ TimingTest, AkkaSpec, filterException }
import docs.pattern.SchedulerPatternSpec.ScheduleInConstructor
object SchedulerPatternSpec {
//#schedule-constructor
class ScheduleInConstructor extends Actor {
import context._
val tick = system.scheduler.schedule(500 millis, 1000 millis, self, "tick")
//#schedule-constructor
var target: ActorRef = null
def this(target: ActorRef) = { this(); this.target = target }
//#schedule-constructor
override def postStop() = tick.cancel()
def receive = {
case "tick"
// do something useful here
//#schedule-constructor
target ! "tick"
case "restart"
throw new ArithmeticException
//#schedule-constructor
}
}
//#schedule-constructor
//#schedule-receive
class ScheduleInReceive extends Actor {
import context._
//#schedule-receive
var target: ActorRef = null
def this(target: ActorRef) = { this(); this.target = target }
//#schedule-receive
override def preStart() =
system.scheduler.scheduleOnce(500 millis, self, "tick")
// override postRestart so we don't call preStart and schedule a new message
override def postRestart(reason: Throwable) = {}
def receive = {
case "tick"
// send another periodic tick after the specified delay
system.scheduler.scheduleOnce(1000 millis, self, "tick")
// do something useful here
//#schedule-receive
target ! "tick"
case "restart"
throw new ArithmeticException
//#schedule-receive
}
}
//#schedule-receive
}
class SchedulerPatternSpec extends AkkaSpec {
def testSchedule(actor: ActorRef, startDuration: FiniteDuration,
afterRestartDuration: FiniteDuration) = {
filterException[ArithmeticException] {
within(startDuration) {
expectMsg("tick")
expectMsg("tick")
expectMsg("tick")
}
actor ! "restart"
within(afterRestartDuration) {
expectMsg("tick")
expectMsg("tick")
}
system.stop(actor)
}
}
"send periodic ticks from the constructor" taggedAs TimingTest in {
testSchedule(system.actorOf(Props(new ScheduleInConstructor(testActor))),
3000 millis, 2000 millis)
}
"send ticks from the preStart and receive" taggedAs TimingTest in {
testSchedule(system.actorOf(Props(new ScheduleInConstructor(testActor))),
3000 millis, 2500 millis)
}
}

View file

@ -111,6 +111,34 @@ This is where the Spider pattern comes in."
The pattern is described `Discovering Message Flows in Actor System with the Spider Pattern <http://letitcrash.com/post/30585282971/discovering-message-flows-in-actor-systems-with-the>`_.
Scheduling Periodic Messages
============================
This pattern describes how to schedule periodic messages to yourself in two different
ways.
The first way is to set up periodic message scheduling in the constructor of the actor,
and cancel that scheduled sending in ``postStop`` or else we might have multiple registered
message sends to the same actor.
.. note::
With this approach the scheduler will be restarted with the actor on restarts.
.. includecode:: code/docs/pattern/SchedulerPatternSpec.scala#schedule-constructor
The second variant sets up an initial one shot message send in the ``preStart`` method
of the actor, and the then the actor when it receives this message sets up a new one shot
message send. You also have to override ``postRestart`` so we don't call ``preStart``
and schedule the initial message send again.
.. note::
With this approach we won't fill up the mailbox with tick messages if the actor is
under pressure, but only schedule a new tick message when we have seen the previous one.
.. includecode:: code/docs/pattern/SchedulerPatternSpec.scala#schedule-receive
Template Pattern
================
@ -127,4 +155,3 @@ This is an especially nice pattern, since it does even come with some empty exam
Spread the word: this is the easiest way to get famous!
Please keep this pattern at the end of this file.