Как использовать @Singleton из актера Akka?

#scala #dependency-injection #akka

#scala #внедрение зависимостей #akka

Вопрос:

Я новичок в внедрении зависимостей, и теперь, когда я перенес свое приложение на Play 2.5.x, мне нужно учиться.

У меня есть одноэлементный сервис, который выглядит примерно так:

 import javax.inject._
@Singleton
class WorkerService {
   def doWork(work:String) {
      ...
   }
}
  

У меня есть актер, который выглядит примерно так:

 import scala.concurrent.duration.DurationInt
import scala.language.postfixOps
import akka.actor._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scalaj.http._

import WorkerService

object PollActor {
  def props(host: String) = Props(new PollActionActor(host))
}

// Actor that polls a host for information
class PollActor(host: String) extends Actor with ActorLogging {
    // timer for poll
    var timer: Cancellable = context.system.scheduler.schedule(0 second, 10 second, self, TimeStep())

    // handle messages
    override def receive = {
        case TimeStep() =>
            getWork match {
                case Some(work:String) =>
                    // How to do this?: ChecklistService.doWork(work)
                case None =>
            }
    }

    def getWork = {
        try {
            Some(Http(host)
                    .option(HttpOptions.readTimeout(10000))
                    .option(HttpOptions.connTimeout(10000))
                    .asString.body)
        } catch {
          case _:Throwable =>
            None
        }
    }

    case class TimeStep()
}
  

И контроллер что-то вроде этого:

 @Singleton
class Application @Inject() (implicit system: ActorSystem) extends Controller {
    val pollActor = system.actorOf(PollActor.props("127.0.0.1"))

    def index = Action {
        pollActor ! TimeStep
    }
}
  

Как я могу вызвать WorkerService.doWork временной шаг актера?

Ответ №1:

Вероятно, вам не следует создавать актера в классе Application.

Попробуйте использовать модуль для создания своего актера следующим образом

 class ApplicationConfigModule extends AbstractModule with AkkaGuiceSupport {

  override def configure(): Unit = {
    bindActor[PollActor]("poll-actor")
  }
}
  

в вашем resources/application.conf поместите это

 play.modules.enabled  = "com.nowtv.platform.search.module.ApplicationConfigModule"
  

Затем внедрите сервис в свой актер

 class PollActor @Inject()(WorkerService: workerService) extends Actor 
  

И внедрите актера в свой контроллер, чтобы вы могли использовать его там

 @Singleton
class Application @Inject() (@Named("poll-actor") pollActor: ActorRef) extends Controller {
  

Комментарии:

1. Спасибо, я попробую это, как только мое приложение сможет снова что-то запустить, эта миграция — огромная боль.

2. Хорошо, похоже, это работает для актеров, у которых нет параметров в конструкции, но это не работает: object PollActor { def props(out: ActorRef) = Props(new PollActor(out)) } class PollActor @Inject()(WorkerService: workerService)(host: String) extends Actor { ... }

3. Я попробовал это, и это сработало, но моему приложению стало очень сложно следовать, поэтому я вернулся к одноэлементным шаблонам Scalas и инициировал их из класса Application с введенными параметрами. Создание приложения с нуля было бы другим делом. Спасибо!