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?