Планирование повторяющегося актера при запуске системы Play 2.4.3

Недавно я начал работать в Scala и Play Framework и только что обновил сервис, над которым работал, до Play 2.4.3. Моя конечная цель — создать ночной процесс, который запускает метод службы в моем игровом приложении с целью планирования событий с помощью вызова метода, который я сейчас вызываю с помощью Актера.

У меня была основная идея этой работы через файл Global.scala с переопределением onStart, но затем я увидел документацию по игре об отказе от использования GlobalSettings (https://www.playframework.com/document/2.4.x/GlobalSettings) и пытались перевести его на подход с внедренной зависимостью.

Вот то, что я собрал воедино до сих пор:

Код модуля:

import javax.inject._

import com.myOrganization.myPackage.Actors.ScheduleActor
import play.api.libs.concurrent.AkkaGuiceSupport
import play.libs.Akka
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import akka.actor.{ActorRef, ActorSystem}
import scala.concurrent.duration._
import play.Application

import com.google.inject.AbstractModule

@Singleton
class NightlyEvalSchedulerStartup @Inject()(system: ActorSystem, @Named("ScheduleActor") scheduleActor: ActorRef) {
  Akka.system.scheduler.schedule(10.seconds, 20.seconds, scheduleActor, "ScheduleActor")
}

class ScheduleModule extends AbstractModule with AkkaGuiceSupport {
  def configure() = {
    bindActor[ScheduleActor]("ScheduleActor")
    bind(classOf[NightlyEvalSchedulerStartup]).asEagerSingleton
  }
}

Класс актера:

import akka.actor.{Actor, Props}
import com.myOrganization.myPackage.services.MySchedulingService

object ScheduleActor {
  def props = Props[ScheduleActor]

  class updateSchedules
}

class ScheduleActor extends Actor {
  val MySchedulingService: MySchedulingService = new MySchedulingService
  def receive = {
    case "runScheduler" => MySchedulingService.nightlyScheduledUpdate()
  }
}

Application.conf

play.modules.enabled += "com.myOrganization.myPackage.modules.ScheduleModule"

Сервис обращается к методу, который в основном основан на коде логики Scala и взаимодействии с базой данных через Anorm.

Каждый раз, когда я пытаюсь запустить службу с запуском активатора (или запустить после получения запроса Http), я получаю следующую ошибку:

Oops, cannot start the server.
com.google.inject.CreationException: Unable to create injector, see the following errors:

1) Error injecting constructor, java.lang.RuntimeException: There is no started application

Я попытался запустить тот же код, заменив часть Aka.system.scheduler... простым println(), и все, казалось, работало нормально, то есть служба запустилась, и я увидел свое сообщение на консоли. Итак, я предполагаю, что мне не хватает какой-то зависимости для планировщика Akka, которая вызывает его взрыв. Любые предложения, которые вы можете предложить, были бы замечательными, я весь день бился об этом головой.

EDIT (решенный код на запрос):

Код модуля с добавленным кодом для получения приблизительной оценки 3 часов ночи следующей ночи. Это может измениться в будущем, но пока работает:

package com.myOrganization.performanceManagement.modules

import com.myOrganization.performanceManagement.Actors.ScheduleActor
import com.myOrganization.performanceManagement.Actors.ScheduleActor.nightlySchedule
import org.joda.time.{Seconds, LocalDate, LocalTime, LocalDateTime}
import play.api.libs.concurrent.AkkaGuiceSupport
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import akka.actor.{ActorRef, ActorSystem}
import scala.concurrent.duration.{FiniteDuration, SECONDS, HOURS }
import org.joda.time._
import com.google.inject.{Inject, Singleton, AbstractModule}
import com.google.inject.name.Named

class ScheduleModule extends AbstractModule with AkkaGuiceSupport {
  override def configure() = {
    bindActor[ScheduleActor]("ScheduleActor")
    bind(classOf[NightlyEvalSchedulerStartup]).asEagerSingleton()
  }
}

@Singleton
class NightlyEvalSchedulerStartup @Inject()(system: ActorSystem, @Named("ScheduleActor") scheduleActor: ActorRef) {
  //Calculate initial delay to 3am the next day.
  val currentTime: DateTime = DateTime.now
  val targetDateTime = currentTime.plusDays(1).withTimeAtStartOfDay()

  //Account for Daylight savings to an extent, not mandatory that it starts at 3am, just after midnight.
  val initialDelaySeconds = targetDateTime.getHourOfDay match {
    case 0 => new Duration(currentTime, targetDateTime.plusHours(3)).getStandardSeconds
    case 1 => new Duration(currentTime, targetDateTime.plusHours(2)).getStandardSeconds
  }

  //Schedule first actor firing to occur at calculated delay and then every 24 hours.
  system.scheduler.schedule(FiniteDuration(initialDelaySeconds, SECONDS), FiniteDuration(24, HOURS), scheduleActor, nightlySchedule)
}

Актер:

package com.myOrganization.performanceManagement.Actors

import akka.actor.{ActorSystem, Actor}
import com.google.inject.Inject
import com.myOrganization.performanceManagement.services.PMEvalSchedulingService

object ScheduleActor {
  case object nightlySchedule
}

class ScheduleActor @Inject() (actorSystem: ActorSystem) extends Actor {
  val pMEvalSchedulingService: PMEvalSchedulingService = new PMEvalSchedulingService
  override def receive: Receive = {
    case nightlySchedule =>
        println("Called the scheduler")
        pMEvalSchedulingService.nightlyScheduledEvaluationsUpdate()
  }
}

person Skyler    schedule 09.10.2015    source источник


Ответы (1)


Ну, в моем случае самая большая проблема заключалась в том, что при планировании вызова актера в NightlyEvalSchedulerStartup() я вызывал Akka.system... что заставляло систему создавать экземпляр новой AkkaSystem до того, как приложение существовало. Удалив систему akk, мы получили внедренную зависимость, которая была готова к работе. Надеюсь, это поможет кому-то в будущем!

person Skyler    schedule 09.10.2015
comment
Не могли бы вы опубликовать код, на котором вы остановились, чтобы решить эту проблему? - person Gavin Schulz; 11.10.2015