Typed group route: how to add routees

I have tried this example but think that I misunderstand both the example and the documentation. I have tried to adapt the example but get:

Message [concurrency.StatsWorker$Available] to Actor[akka://WorkStealSystem/user/WorkerRouter#530679135] was dropped. No routees in group router for [ServiceKey[concurrency.StatsWorker$Command](StatsService)]. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

My question is: do I need to use Routers.pool() to add routees to the group router or is their some other way to do this? I have the following:

    val groupRouter: GroupRouter[StatsWorker.Command] = Routers.group(App.StatsServiceKey)
    val serviceRouter: ActorRef[StatsWorker.Command] = ctx.spawn( groupRouter, "WorkerRouter")

    val worker = StatsWorker(serviceRouter)
    val service = ctx.spawn(worker, "WorkerService")

    // published through the receptionist to the other nodes in the cluster
    ctx.system.receptionist ! Receptionist.Register(StatsServiceKey, service)

And in the StatsWorkerI have:

  def apply(serviceRouter: ActorRef[StatsWorker.Command]): Behavior[Command] =
    Behaviors.setup { ctx =>
      ctx.log.info("Worker starting up")
      ctx.log.info("Sending available")
      serviceRouter ! Available(ctx.self)
      ctx.log.info("Waiting for job")
      waitJob(ctx)
  }

which results on the above log message.

My objective is to have a set of actors register themselves so that they be contacted by another set of actors. More concretely can I assume that if I use:

    val groupRouter: GroupRouter[StatsWorker.Command] = Routers.group(App.StatsServiceKey)
    val serviceRouter: ActorRef[StatsWorker.Command] = ctx.spawn( groupRouter, "WorkerRouter")

    val worker = AnotherWorker(serviceRouter)
    val service = ctx.spawn(worker, "WorkerService")

the AnotherWorker actor can send messages to the group?

My apologies if I am completely off the mark, but I am a beginner.
TIA

Registration to the receptionist (actor messaging) and spawning actors is async, in addition to this also the group router picking up what actors are registered for the ServiceKey is async. This means you cannot make assumptions about in which order these things happen. When the StatsWorker is started, the router may or may not know of any routees yet, as you noticed with the log entry. To build a robust application your worker needs to handle both scenarios, for example by retrying that Available request periodically if it does not get any work.

In addition to this there is something strange with your logic, the StatsWorker is both handed the router and registered with the service key the router is created with, which means the Available message would be sent to itself through the router? Isn’t that intended to go to some form of work manager rather?

Appreciate the help.

Just testing - I would use AnotherWorker. My problem is spawning the routees. Hence the question about the Routers.pool(). I was under the impression that I could spawn various StatsWorker as above in separate VMs and the send would be automatically routed to these.

Adding actors for a service key on any node in the cluster eventually leads to a group router for that service key routing to them so you have understood that correctly.

Note that there is no delivery guarantee, the group router list state can be empty because it did not yet see any registration from the receptionist and in that case messages will end up in dead letters, which is what you see in your log.

If the chosen routee is on another cluster node the message can also get lost on the way to the remote node, or the routee could crash with the message still in its inbox. This is an important aspect of Akka to understand. You can read more about it in the docs under Message Delivery Reilability

Ah, ok.

Ok, makes sense now.

Thank you.