Search code examples
scalaplayframeworkquartz-scheduler

Issues with initializing service class that has dependency on running application on startup (play 2.4 / scala)


I am currently digging into using Quartz in our play 2.4 application. Initially, I tried initializing everything through Global object, and everything worked perfectly.

Now, I an trying to move away from Global utilize modules infrastructure. Here is what I have until now.

JobSchedulingService

@Singleton
class JobSchedulingService @Inject()(lifecycle: ApplicationLifecycle) extends ClassLogger{

  lazy val schedulerFactory = current.injector.instanceOf[StdSchedulerFactory]

  lazy val scheduler = schedulerFactory.getScheduler

  /**
    * Let's make sure that scheduler shuts down properly
    */
  lifecycle.addStopHook{ () =>
    Future.successful{
      if (scheduler.isStarted) {
        scheduler.shutdown(true)
      }
    }
  }

  protected def init() : Unit = {
    logger.info("Initializing scheduler...")
    scheduler.start()
  }

  init()
}

SchedulerModule - here for initialization of the service above.

class SchedulerModule extends AbstractModule{
  override def configure(): Unit = {
    bind(classOf[JobSchedulingService]).asEagerSingleton
  }
}

And in my application.conf I added:

play.modules.enabled += "scheduling.modules.SchedulerModule"

It looks pretty strait forward. However, when the app starts I am getting an exception:

2016-03-23 00:07:42,173 INFO s.JobSchedulingService - Initializing scheduler... 2016-03-23 00:07:42,213 ERROR application -

! @6pfp72mh6 - Internal server error, for (GET) [/] ->

play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:

1) Error injecting constructor, java.lang.RuntimeException: There is no started application at scheduling.JobSchedulingService.(JobSchedulingService.scala:15) at scheduling.modules.SchedulerModule.configure(SchedulerModule.scala:11) (via modules: com.google.inject.util.Modules$OverrideModule -> scheduling.modules.SchedulerModule) while locating scheduling.JobSchedulingService

...

The thing is, in our app, the scheduler is based of off persistence job storage and should restart when the application restarts. Again, when I did it through Global, it worked perfectly.

How do I get around this problem? What is the correct way to initialize an instance on startup?

Thanks,


Solution

  • You should probably be using the dependency injection for everything. Inject the scheduler like..

    class JobSchedulingService @Inject()(lifecycle: ApplicationLifecycle, schedulerFactory: StdSchedulerFactory) extends ClassLogger{
      lazy val scheduler = schedulerFactory.getScheduler