Akka and two-way actor conversations

237 views Asked by At

Akka-based actor messaging feels like a one-way stream/flow of messages from some "upstream" actor to one or more "downstream" actors.

But there might be a legitimate use case for some kind of two-way (request/response) synchronous messaging between two actors. For instance, I might have a CacheActor that manages some cache. Other actors might want to put and get cache entries to this cache, and they need to do so through CacheActor:

// Groovy pseudo-code
class CacheActor extends UntypedActor {
    Map<String,Object> cache

    // ...

    @Override
    void onReceive(Object message) {
        if(message instanceof GetCacheEntry) {
            GetCacheEntry getCacheEntry = message as GetCacheEntry
            String entry = cache.get(getCacheEntry.key)

            // Now what? How to send back to the actor that called this?!?
            getCacheEntry.sender.tell(new GetCacheEntryResult(getCacheEntry.buzz, entry))   // <-- 2. return to sender (again with 'buzz' as sidecar)
        }
    }
}

class FizzActor extends UntypedActor {
    ActorRef cacheActor

    @Override
    void onReceive(Object message) {
        if(message instanceof Buzz) {
            Buzz buzz = message as Buzz
            cacheActor.tell(new GetCacheEntry(buzz, this))  // <-- 1. identify 'this' as the sender and pass 'buzz' in as sidecar
        } else if(message instanceof GetCacheEntryResult) { // <-- 3. recognize that we are processing the result from #1 above
            GetCacheEntryResult result = message as GetCacheEntryResult
            Buzz originalBuzz = result.buzz
            String resultantEntry = result.entry

            // 4. Now keep processing...
        }
    }
}

This is the only way I can envision passing messages back and forth between two actors in a "conversational" request-response style. The problem with it is that its a bit nasty:

  • I have to create new message types (e.g. GetCacheEntryResult) for each response sent back to the requester, which will quickly bloat the code; and
  • Each time one actor responds to another, all of the "context variables" that are "in scope" likely need to be bundled up and sent back to the requesting actor as sidecars, so that they are available to the requester when they receive the answer and need to continue processing (see buzz below). In a more complicated orchestration between several actors, this "context map" is going to get fairly big; and
  • At the end of the day, this solution just feels like code smell to me...

So I ask: is there a better way to do this in Akka? Maybe using Futures or the ask(...) method?

0

There are 0 answers