Search code examples
scalaredisakkaakka-typed

creating a RedisClient from a typed akka behavior


Im trying to use this scala redis library etaty which needs an implicit akka.actor.ActorSystem when creating it's RedisClient object. I used the context.system.classicSystem in the Behaviors.setup method to provide the needed implicit.

Here is my code

 
def apply(): Behavior[Command] = Behaviors.setup { context =>
    implicit val system  = context.system
    implicit val classic  = context.system.classicSystem

   lazy val redis  = RedisClient(
      host = host,
      port = port
    )

However, I getting this errors in my logs.

java.lang.UnsupportedOperationException: cannot create top-level actor [RedisClient-$a] from the outside on ActorSystem with custom user guardian
    at akka.actor.ActorSystemImpl.actorOf(ActorSystem.scala:895)
    at redis.RedisClientActorLike.<init>(Redis.scala:41)
    at redis.RedisClient.<init>(Redis.scala:86)
    at ng.logicbud.deidara.core.db.redis.RedisDbService$.redis$lzycompute$1(RedisDbService.scala:34)
    at ng.logicbud.deidara.core.db.redis.RedisDbService$.redis$1(RedisDbService.scala:34)
    at ng.logicbud.deidara.core.db.redis.RedisDbService$.$anonfun$apply$2(RedisDbService.scala:62)
    at akka.actor.typed.internal.BehaviorImpl$ReceiveMessageBehavior.receive(BehaviorImpl.scala:152)
    at akka.actor.typed.Behavior$.interpret(Behavior.scala:274)
    at akka.actor.typed.Behavior$.interpretMessage(Behavior.scala:230)
    at akka.actor.typed.internal.adapter.ActorAdapter.handleMessage(ActorAdapter.scala:129)
    at akka.actor.typed.internal.adapter.ActorAdapter.aroundReceive(ActorAdapter.scala:106)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:577)
    at akka.actor.ActorCell.invoke(ActorCell.scala:547)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
    at akka.dispatch.Mailbox.run(Mailbox.scala:231)
    at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)

Solution

  • This is because the redis client wants to create a top level actor under /user which is not possible with a typed actor system because there the /user actor is yours and the only one who is allowed to spawn children of that actor is itself.

    The etaty library should be updated to not require doing that (for example return an actor for you to start, or use systemActorOf to start its own internal actors). You can however work around this by using a classic actor system in your app, and adapting to the typed APIs instead.