简体   繁体   中英

Play 2.4: Schedule a recurring task at app startup with dependency injection

I need to schedule a recurring task on the application start, the task itself is very simple just send to the application a fire-and-forget HTTP call. I'm not a play expert, buy i would assume that s straightforward solution would be something like using play.api.libs.concurrent.Akka.system.schedule in Global.onStart . Since Play 2.4, Global configuration is somewhat deprecated in favor of new Guice DI. Hacking the advice from the DI documentation i couldn't come up with a nice solution for this issue. The best i managed to get is writing a wrapper on top of GuiceApplicationLoader calling a custom implementation of BuiltInComponentsFromContext , but in this case i can't use injection to get WSClient . What's the best way to rewrite something like this with Play 2.4:

object Global extends GlobalSettings {
  override def onStart(app: Application) = {
    Akka.system.schedule(2.hours, 2.hours, theTask)
  }
}

Update : this is now better documented for Play 2.6: https://www.playframework.com/documentation/2.6.x/ScheduledTasks


You can solve this by creating a module like this (attention to code comments):

package tasks

import javax.inject.{Singleton, Inject}

import akka.actor.ActorSystem
import com.google.inject.AbstractModule

import play.api.inject.ApplicationLifecycle

// Using the default ExecutionContext, but you can configure
// your own as described here:
// https://www.playframework.com/documentation/2.4.x/ThreadPools
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import scala.concurrent.Future
import scala.concurrent.duration._

class MyRecurrentTaskModule extends AbstractModule {
  override def configure() = {
    // binding the RecurrentTask as a eager singleton will force
    // its initialization even if RecurrentTask is not injected in
    // any other object. In other words, it will starts with when
    // your application starts.
    bind(classOf[RecurrentTask]).asEagerSingleton()
  }
}

@Singleton
class RecurrentTask @Inject() (actorSystem: ActorSystem, lifecycle: ApplicationLifecycle) {

  // Just scheduling your task using the injected ActorSystem
  actorSystem.scheduler.schedule(1.second, 1.second) {
    println("I'm running...")
  }

  // This is necessary to avoid thread leaks, specially if you are
  // using a custom ExecutionContext
  lifecycle.addStopHook{ () =>
    Future.successful(actorSystem.shutdown())
  }

}

After that, you must enable this module adding the following line in your conf/application.conf file:

play.modules.enabled += "tasks.MyRecurrentTaskModule"

Then, just start you application, fire a request to it and see the scheduled task will run every each second.

References :

  1. Understanding Play thread pools
  2. Play Runtime Dependency Injection for Scala
  3. Integrating with Akka

Related questions :

  1. How to correctly schedule task in Play Framework 2.4.2 scala?
  2. Was asynchronous jobs removed from the Play framework? What is a better alternative?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM