0
votes

In my app I have a supervisor which creates some workers. Each of these workers needs two QueueClients instances (with different configurations and different instances between workers). I'm new to guice and I'm having problems to inject these dependencies in child actors.

This is my worker class:

object LegacyConsumer {

  trait Factory {
    def apply(): Actor
  }

}

class LegacyConsumer @Inject()(
  eventsClient: QueueClient,
  deadLetterClient: QueueClient
) extends Actor with ActorLogging {

  override def preStart(): Unit = {
    log.error("prestart")
    log.error(eventsClient.toString)
  }

  def receive: PartialFunction[Any, Unit] = {
    case _ =>
      log.error("received message consumer")
  }
}

As you can see I need the two QueueClients for construction:

trait QueueClient {
...

  def numMessages: Int
}

class SqsClient @Inject()(name: String, key: String, secret: String, zone: String) extends Logging with QueueClient {
...
}

This is how I trying to create my workers

class LegacyConsumerSupervisor @Inject()(
  consumerFactory: LegacyConsumer.Factory,
  @Named("numWorkers") workers: Int
)
  extends Actor with ActorLogging with InjectedActorSupport {

  override def preStart(): Unit = {
    (1 to workers).foreach { workerNumber =>
      val key = s"WORKER-$workerNumber"
      injectedChild(consumerFactory(), key, _.withDispatcher("akka.legacy-consumer-dispatcher"))
    }
  }

And finally this is how my bindings look like

class ChatModule extends AbstractModule with ScalaModule with AkkaGuiceSupport{
  override def configure() {
    bind[Actor].annotatedWith(Names.named(LegacyConsumerSupervisor.name)).to[LegacyConsumerSupervisor]

    bind(classOf[Int])
      .annotatedWith(Names named "numWorkers")
      .toInstance(ConfigurationHelper.getInt("chat.legacy.num-workers"))

    bindActorFactory[LegacyConsumer, LegacyConsumer.Factory]

    bind(classOf[QueueClient])
//      .annotatedWith(Names named "legacyEventsClient")
        .toInstance(
          new SqsClient(
            ConfigurationHelper.getString("chat.legacy.events.name"),
            ConfigurationHelper.getString("chat.legacy.events.key"),
            ConfigurationHelper.getString("chat.legacy.events.secret"),
            ConfigurationHelper.getString("chat.legacy.events.region")
          )
        )

    bind(classOf[QueueClient])
//      .annotatedWith(Names named "legacyDeadLetterClient")
        .toInstance(
          new SqsClient(
            ConfigurationHelper.getString("chat.legacy.dead-letter.name"),
            ConfigurationHelper.getString("chat.legacy.dead-letter.key"),
            ConfigurationHelper.getString("chat.legacy.dead-letter.secret"),
            ConfigurationHelper.getString("chat.legacy.dead-letter.region")
          )
        )
  }
}

How can I inject different instances of queue clients into each worker? All legacyEventsClients and legacyDeadLetterClients have the same config (based on typesafe config). Does the solution something related with Assisted injection?

The error I'm getting now:

A binding to ...QueueClient was already configured at ...configure(ChatModule.scala:29). at ...configure(ChatModule.scala:40)

So I think the problem is about try to inject the same binding twice to different instances... I tried to do with named parameters but then the same instance of client is injected to each LegacyConsumer

Regards

1

1 Answers

0
votes

I've finally did this and it works:

bindings:

    bind(classOf[QueueClient])
      .annotatedWith(Names named "legacyEventsClient")
      .toProvider(new Provider[SqsClient] {
        override def get = {
          new SqsClient(
            ConfigurationHelper.getString("chat.legacy.events.name"),
            ConfigurationHelper.getString("chat.legacy.events.key"),
            ConfigurationHelper.getString("chat.legacy.events.secret"),
            ConfigurationHelper.getString("chat.legacy.events.region")
          )
        }
      })

    bind(classOf[QueueClient])
      .annotatedWith(Names named "legacyDeadLetterClient")
      .toProvider(new Provider[SqsClient] {
        override def get = {
          new SqsClient(
            ConfigurationHelper.getString("chat.legacy.dead-letter.name"),
            ConfigurationHelper.getString("chat.legacy.dead-letter.key"),
            ConfigurationHelper.getString("chat.legacy.dead-letter.secret"),
            ConfigurationHelper.getString("chat.legacy.dead-letter.region")
          )
        }
      })

and in my worker class:

class LegacyConsumer @Inject()(
  @Named("legacyEventsClient") eventsClient: QueueClient,
  @Named("legacyDeadLetterClient") deadLetterClient: QueueClient
) extends Actor with ActorLogging {

  override def preStart(): Unit = {
    log.error("prestart")
  }

  def receive: PartialFunction[Any, Unit] = {
    case _ =>
      log.error("received message consumer")
  }
}