Please note: Although I'd prefer a solution using Akka's Java API (which is what I'm using), I'm happy with any working solution and can probably figure out how to translate Scala-based answers into Java-land.
I have an Akka app that has many actors, two of which are Fizz
and Buzz
. The Fizz
actor can accept 2 types of messages:
StartNewTimerTask
; andResetAllTimerTasks
The Buzz
actor simply accepts a DoItNow
message. The message flow between these actors and the rest of the system is as follows:
- Anything (other actors, even event-driven components outside the actor system) can send
StartNewTimerTask
messages to theFizz
actor at any time - Each time the
Fizz
actor receives aStartNewTimerTask
message, it creates and starts a new asynchronous/non-blocking timer that attempts to run for, say, 8 seconds. If the timer gets to the end (8 seconds) then aDoItNow
message is sent to theBuzz
actor - The
Fizz
actor can accept any number of concurrentStartNewTimerTask
messages, and as such, can be "managing" potentially multiple timers at the same time, with each one counting towards that 8-second magical number. Hence if 20 other actors sendStartNewTimerTask
messages to theFizz
actor all within a few seconds of each other, then theFizz
actor would be "managing" 20 non-blocking, independent timers at the same time. And when each of those 20 timers reaches their respective 8-second duration, they send 20 independentDoItNow
messages to theBuzz
actor - When the
Fizz
actor receives aResetAllTimerTasks
message, any timers that are currently "in progress" will be interrupted/cancelled (so that they stop counting down to the 8-second duration, thus preventing them from sending aDoItNow
message toBuzz
). Hence, borrowing from our example above, if between timest=1
andt=3
theFizz
actor received 20StartNewTimerTask
messages, then att=10
perhaps 14 of their respective timers would have elapsed and firedDoItNow
messages, and perhaps 6 would still be in progress. If at that exact momentFizz
received aResetAllTimerTasks
message, it would stop those 6 timers from elapsing and firing messages, and so in this exampleBuzz
would only receive 14DoItNow
messages
I know that the Java 8 API (sans Akka) advocates extending TimerTask
and submitting these tasks to the Timer#scheduleAtFixedRate
method, but I'm not sure if that conflicts with Akka at all or if there is a better way to implement this functionality with the Akka API. My best attempt thus far:
// Groovy pseudo-code
class MyTimerTask extends TimerTask {
@Inject
ActorRef buzz
@Override
void run() {
// No op!
}
void completeTask() {
buzz.tell(new DoItNow(), null)
}
}
class Fizz extends UntypedAbstractActor {
@Inject
Timer timer
@Override
void onReceive(Object message) {
if(message in StartNewTimerTask) {
timer.scheduleAtFixedRate(new MyTimerTask(), 0, 8 * 1000)
} else if(message in ResetAllTimerTasks) {
timer.cancel()
}
}
}
class Buzz extends UntypedAbstractActor {
@Override
void onReceive(Object message) {
if(message in DoItNow) {
// Do something super cool now...
}
}
}
However I don't think I'm managing timers correctly or tapping into the full potential of the Akka scheduler/timer API. Any thoughts?