Moonlight is a simple delayed job (or, in other words, background job) framework for Playframework.
Here are important notes:
- Moonlight uses Postgresql through Slick. This requires you to configure Slick correctly.
- Use JSON to serialize/deserialize job's params.
At GIVE.asia, we've built Moonlight because we wanted a delayed job framework for moderate load. At the same time, we want to avoid introducing a new datastore to our system.
We are using Playframework on Heroku with Postgresql (through Slick), so Moonlight fits perfectly into our setting.
The usage requires some degree of involvement.
Please see a full working example in the folder test-project
and the live demo
here: https://moonlight-test.herokuapp.com.
(The worker dyno isn't free, so it's off. Therefore, the job will be added but not processed).
We've provided a set of SQLs for creating/updating required schemas. Please see conf/evolutions/default/1.sql
.
Please apply the SQLs to your database.
resolvers += Resolver.bintrayRepo("givers", "maven")
libraryDependencies += "givers.moonlight" %% "play-moonlight" % "x.x.x"
The artifacts are hosted here: https://bintray.com/givers/maven/play-moonlight
You can define a delayed job by providing WorkerSpec
which allows you to specify params and job runner. Here's an
example:
@Singleton
class SimpleExecutor @Inject()(implicit ec: ExecutionContext)
extends JobExecutor(SimpleExecutor.Type) {
override def run(data: SimpleExecutor.Job): Future[Unit] = Future.successful(())
}
object SimpleExecutor {
case class Job(data: String)
implicit case object Type extends JobTypeJson[Job]("Simple")(Json.format)
}
class SimpleScheduledJob @Inject() (implicit val executionContext: ExecutionContext) extends ScheduledJob {
type IN = String
private val logger = Logger(this.getClass)
override def run(input: IN): Future[Unit] = {
logger.info(s"[$input]")
Future.unit
}
}
Create a module with defined SimpleExecutor
and SimpleScheduledJob
:
class MoonlightModule extends play.api.inject.Module {
def bindings(environment: Environment, configuration: Configuration) = Seq(
bind[MoonlightSettings].toInstance(new MoonlightSettings(
parallelism = Runtime.getRuntime.availableProcessors(),
pauseDurationWhenNoJobs = 10.seconds,
maintenanceInterval = 1.minutes,
betweenRunAttemptInterval = 10.minutes,
countMetricsCollectionInterval = 1.minute,
maxJobRetries = 3,
jobRunTimeout = 10.seconds,
completedJobsTtl = (24 * 30).hours,
executors = Seq(simpleExecutor),
schedulerInputs = Seq(
SchedulerInput[SimpleScheduledJob]("job1", cronExpression("0 * * * * ? *"), 10.seconds)
)
))
)
}
Then, install the module and configure Slick's database connection in application.conf
by:
play.modules.enabled += "modules.MoonlightModule"
slick.dbs.default.db.properties.url="postgres://user:pass@localhost:5432/database"
You can run Moonlight locally with sbt 'runMain givers.moonlight.v2.MoonlightApplication dev'
.
On Heroku, you can run Moonlight by adding the below line to Procfile
:
moonlight: target/universal/stage/bin/giveasia -Dconfig.resourceapplication.conf -main givers.moonlight.v2.MoonlightApplication -- prod
Please see a full example in the folder test-project-v2
.
Please don't hesitate to ask questions by opening a Github issue. We want you to use Moonlight successfully.