I’m using a Google Guava LoadingCache to provide child actors. Is that a bad idea? Will some kind of nasty threading issue bite me in the backside if I continue with this strategy?
Here’s the load method from my CacheLoader implementation:
@Override
public ActorRef<Foundation.Command> load(AccountId accountId) {
ActorRef<Foundation.Command> actor = context.spawnAnonymous(
Foundation.create(host, accountId, permissionFinder));
context.watchWith(actor, RemoveFoundationActor.INSTANCE);
return actor;
}
Doing things with the internal state of an actor such as spawning children with context.spawn must only ever be done as a reaction to receiving a message, so a call to load on some thread that the CacheLoader maintains is not safe.
You’d have to replace that with triggering a request-response to the actor, that would then in turn be problematic because it’s not a synchronous operation, so you’d rather have a CompletionStage<ActorRef<Cmd>> - you’d need some form of async loading API in the cache.
Thanks @johanandren. I have decided to ditch my Guava LoadingCache, in favour of a LinkedHashMap that I can manage more explicitly. I don’t feel confident of understanding the LoadingCache's internal thread management.
Just FYI: you can use Caffeine instead of Guava’s LoadingCache. It allows you to define a loader which returns a CompletionStage. This way you can ask inside the loader and return the resulting CompletionStage; when it is complete, the cache will store the resulting actor ref. Caffeine has all the same additional tweaks as Guava’s cache does, and has some annoying bugs fixed.