tags:

views:

222

answers:

3

I have a scala actor that does some work whenever a client requests it. When, and only when no client is active, I would like the Actor to do some background processing.

What is the easiest way to do this? I can think of two approaches:

  1. Spawn a new thread that times out and wakes up the actor periodically. A straight forward approach, but I would like to avoid creating another thread (to avoid the extra code, complexity and overhead).

  2. The Actor class has a reactWithin method, which could be used to time out from the actor itself. But the documentation says the method doesn't return. So, I am not sure how to use it.

Edit; a clarification:

Assume that the background task can be broken down into smaller units that can be independently processed.

+1  A: 

It sounds like the problem you describe is not well suited to the actor sub-system. An Actor is designed to sequentially process its message queue:

  • What should happen if the actor is performing the background work and a new task arrives?

An actor can only find out about this is it is continuously checking its mailbox as it performs the background task. How would you implement this (i.e. how would you code the background tasks as a unit of work so that the actor could keep interrupting and checking the mailbox)?

  • What should happen if the actor has many background tasks in its mailbox in front of the main task?

Do these background tasks get thrown away, or sent to another actor? If the latter, how can you prevent CPU time being given to that actor to perform the tasks?

All in all, it sounds much more like you need to explore some grid-style software that can run in the background (like Data Synapse)!

oxbow_lakes
I understand your concern. But it is critical that the background task I want to run _has_ to be done when the actor is not doing anything. To ans your questions: 1. The background task can be broken into smaller units. It's ok if the actor finishes doing the unit of background work it is currently doing before processing a normal request. 2. Hoping to use Actor.mailboxSize to ignore background tasks when others are waiting in queue.
HRJ
+2  A: 

Just after asking this question I tried out some completely whacky code and it seems to work fine. I am not sure though if there is a gotcha in it.

import scala.actors._

object Idling

object Processor extends Actor {
  start

  import Actor._

  def act() = {
    loop {

      // here lie dragons >>>>>
      if (mailboxSize == 0) this ! Idling
      // <<<<<<

      react {
        case msg:NormalMsg => {
          // do the normal work
          reply(answer)
        }

        case Idling=> {
          // do the idle work in chunks
        }

        case msg => println("Rcvd unknown message:" + msg)
      }

    }
  }
}

Explanation

Any code inside the argument of loop but before the call to react seems to get called when the Actor is about to wait for a message. I am sending a Idling message to self here. In the handler for this message I ensure that the mailbox-size is 0, before doing the processing.

HRJ
The only way that this can work is if you are sending the idle tasks to this actor *not* through messages. Otherwise, any idle task will result in a mailbox with one item in it
oxbow_lakes
@oxbow_lakes Not sure I understand. This code works in practice, and I am sending the idle task via a message.
HRJ
From your own answer I can suggest that you are inventing a "priority receive" (originating from Erlang, but can be implemented using Scala actors)
Alexander Azarov
@HRJ - how can the actor have any idle tasks in its message queue if its `mailbox` is empty? It surely must be the case that the actor is getting the idle tasks from somewhere else...
oxbow_lakes
+3  A: 

Ok, I see I need to put my 2 cents. From the author's answer I guess the "priority receive" technique is exactly what is needed here. It is possible to find discussion in "Erlang: priority receive question here at SO". The idea is to accept high priority messages first and to accept other messages only in absence of high-priority ones.

As Scala actors are very similar to Erlang, a trivial code to implement this would look like this:

def act = loop {
  reactWithin(0) {
    case msg: HighPriorityMessage => // process msg
    case TIMEOUT =>
      react {
        case msg: HighPriorityMessage => // process msg
        case msg: LowPriorityMessage => // process msg
      }
  }
}

This works as follows. An actor has a mailbox (queue) with messages. The receive (or receiveWithin) argument is a partial function and Actor library looks for a message in a mailbox which can be applied to this partial function. In our case it would be an object of HighPriorityMessage only. So, if Actor library finds such a message, it applies our partial function and we are processing a message of high priority. Otherwise, reactWithin with timeout 0 calls our partial function with argument TIMEOUT and we immediately try to process any possible message from the queue (as it waits for a message we cannot exclude a possiblity to get HighPriorityMessage).

Alexander Azarov
Although my solution works in practice, I think this is more idiomatic, hence accepting it. I originally wanted to use reactWithin but didn't find any documentation on `TIMEOUT`
HRJ