views:

618

answers:

1

I'd like to use actors in a program where I'll have some kind of restriction around treating some of the actors as if they were queues. For example, suppose I have some external system to which change events are applied and also some cache of the external system's data. So I have 2 actors:

  1. ChangeApplicationActor
  2. CacheActor

As part of the ChangeApplicationActor, when I apply a change to some entity X in the external system, I want to send some event to tell the CacheActor to sync:

val changeApplicationActor = actor { 
  loop {
    react {
      case ChangeInstruction(x) => 
        externalSystem.applyChange(x)
        cacheActor ! Sync(x)
    }
  }
}

But I Now have two requirements:

  1. The CacheActor has internal state and ideally I'd like it to process its Sync instructions sequentially
  2. If I end up with the CacheActor's inbox containing two Sync(x) instructions for the same value of x, then I'd like to ignore the second one (i.e. I should only have one pending Sync instruction for any given value of x)

Is there any way of forcing an actor to be single-threaded? Is there any way I can access the actor's mailbox and remove any duplicate events? Can I not avoid implementing the CacheActor as, um, not an Actor?

+2  A: 

An actor is guaranteed to only execute on one thread at a time, and the messages in the actor's mailbox are in FIFO order, so #1 is there.

2 is trickier as there is no builtin support for it. There's an attribute on the actor called "mailbox." You can access the mailbox directly instead of through receive or react. All you have to do is pull call the matching Sync messages out of the mailbox before you are done processing the message. When doing this, you must synchronize on the actor in order to keep another thread from attempting the add stuff to the mailbox during a message send.

It should be noted that synchronizing on the actor eliminates the deadlock freedom guarantees made by the library, and will reduce scalability. But from a practical point of view you probably will be ok.

Erik Engbrecht
Is that really true about react only processing one message at a time? I don't see it mention that even once in Programming in Scala? In fact, I'm pretty sure you're wrong. On page 593 it says: "If [the react method] finds a message that can be handled, [it] will schedule the handling of that message for later execution and throw an exception". The important piece being "for later execution"
oxbow_lakes
OK - seems like you're correct, sorry. I asked a different question: http://stackoverflow.com/questions/1007010/can-scala-actors-process-multiple-messages-simultaneously
oxbow_lakes
Also the MessageQueue documentation states explicitly that I should not be using it from outside the package
oxbow_lakes
Using MessageQueue from outside the package is indeed risky. It's not designed for general use, and subject to change. That being said, internally the actor simply locks then accesses the queue, and you can do the same without corrupting anything.
Erik Engbrecht