1

I'm curious if it's possible to safely implement a self-cancelling poller without using a var to keep the instance of akka.actor.Cancellable

So far, I came up with something like what you see in the example below. However, I'm curious if it's safe to assume that the "tick" message will never be dispatched before the hotswap happens, i.e the line that schedules the poller:

tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))

is basically the same as:

val poll = context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick")
tick(1, 5, poll)

So, I would think that in some cases the first tick would be received before the hotswap has a chance to happen... Thoughts?

import akka.actor.{Cancellable, ActorSystem}
import akka.actor.ActorDSL._
import concurrent.duration._

object PollerDemo {
  def run() {
    implicit val system = ActorSystem("DemoPoller")
    import system.dispatcher

    actor(new Act{
      become {
        case "tick" => println("UH-OH!")
        case "start" =>
          become {
            tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
          }
      }
      def tick(curr:Long, max:Long, poll:Cancellable):Receive = {
        case "tick" => {
          println(s"poll $curr/$max")
          if(curr > max)
            cancel(poll)
          else
            become{ tick(curr + 1, max, poll) }
        }
      }
      def cancel(poll:Cancellable) {
        println("cancelling")
        poll.cancel()
        println(s"cancelled successfully? ${poll.isCancelled}")
        println("shutting down")
        context.system.shutdown()
      }
    }) ! "start"

    system.awaitTermination(1 minute)
  }
}
Andrey
  • 8,882
  • 10
  • 58
  • 82
  • The whole point of actor-based programming is that you get to have long-term, shared, mutable state by protecting it within an instance of an Actor. – Randall Schulz Jun 16 '13 at 02:14
  • hmm, people are focusing on the title too much. let me fix it for you guys – Andrey Jun 16 '13 at 04:36

2 Answers2

3

My guess is that your code will be okay. Remember, actors only process their mailbox one at a time. When you receive the start message, you setup a timer that will deliver another message to the mailbox and then you swap the receive implementation. Because you do the receive swap while you are still processing the start message, then you will have already changed the actors's receive behavior before it processes the next message in the mailbox. So when it moves on to process the tick message you can be sure that it will be using the new receive behavior.

You could verify this by sending an additional tick message inside the first become like so:

become {
  self ! "tick"
  tick(1, 5, context.system.scheduler.schedule(Duration.Zero, 3 seconds, self, "tick"))
}

Here we are really eliminating the timer from the equation when asking if a message sent during the become block will be processed by the old receive or the new receive. I did not run this, but from my understanding or akka, both of these ticks should be handled by the new receive.

cmbaxter
  • 35,283
  • 4
  • 86
  • 95
1

You really can't do pure functional programming with actors. Sending them messages is a side-effect. Since their receive function doesn't return a result, all the actor can do when receiving a message is to side effect. Just about every single thing your code does is for side-effects

You might be avoiding vars in your implementation of the code, but become is mutating a var in the Actor superclass. context.system.scheduler.schedule is clearly side-effecting and mutating state somewhere. Every single thing that cancel does is a side effect. system.awaitTermination(1 minute) is not a function...

stew
  • 11,276
  • 36
  • 49
  • i'm not concerned with how akka implements actors, i'm concerned with their usage. actors do indeed return values, by replying to the sender with messages. will you be addressing my actual question? system.awaitTermination is definitely a function check the latest [akka api](http://doc.akka.io/api/akka/2.0/akka/actor/ActorSystem.html). – Andrey Jun 16 '13 at 04:30
  • @Andrey they are methods on objects (hidden state), not functions. – jwinandy Jun 16 '13 at 06:42
  • @stew Whether or not to write your actor internals in a functional style is a meaningful choice, independent of whether sending a message is a side effect or not. It generally helps in many ways to keep mutability confined to a very small number of vars in the actor—of which the behavior stack is one. Akka deliberately is non-dogmatic. – Roland Kuhn Jun 17 '13 at 14:19
  • @Andrey While actors can reply zero or more times to the sender of a message, I would not call this “returning a value”, because a method return value is associated with rather strong semantic limitations whereas actors can communicate freely, using any pattern they like. – Roland Kuhn Jun 17 '13 at 14:21