enragedginger / akka-quartz-scheduler

Quartz Extension and utilities for cron-style scheduling in Akka
Other
559 stars 114 forks source link

Running multiple Play instances fires jobs multiple times #88

Closed pybuche closed 4 years ago

pybuche commented 5 years ago

Hi,

I'm not exactly sure if this can be handled, but I'm struggling to find a way to have only one scheduler for my Play app that is deployed and replicated via Heroku.

I use the scheduler this way: Module.scala

package fr.staycation

import com.google.inject.AbstractModule
import play.api.libs.concurrent.AkkaGuiceSupport
import play.api.{Configuration, Environment}

import fr.staycation.commons.scheduled.{TaskActor, TaskScheduler}

class Module(environment: Environment, conf: Configuration) extends AbstractModule with AkkaGuiceSupport {
  override def configure() = {
    bindActor[TaskActor]("task-actor")
    bind(classOf[TaskScheduler]).asEagerSingleton()
  }
}

TaskScheduler

package fr.staycation.commons.scheduled

import akka.actor.{ActorRef, ActorSystem}
import com.typesafe.akka.extension.quartz.QuartzSchedulerExtension
import com.typesafe.config.Config
import com.typesafe.scalalogging.StrictLogging
import javax.inject.{Inject, Named, Singleton}

import fr.staycation.commons.scheduled.Tasks._

import scala.concurrent.ExecutionContext

@Singleton
class TaskScheduler @Inject()(actorSystem: ActorSystem, @Named("task-actor") taskActor: ActorRef, config: Config)
  (implicit executionContext: ExecutionContext) extends StrictLogging {
    logger.info("Starting Scheduler...")
    val scheduler = QuartzSchedulerExtension.get(actorSystem)

    scheduler.schedule("ExpireBookings", taskActor, ExpireBookings)
    ...other schedules
}

And the TaskActor that handle Akka messages and execute jobs.

Everything is working well with one instance of my app, but if I replicate it, the scheduler fire as many events as there are instances...

In this part of the README, it says:

Because it is an Actor which provides no "Singleton"-like guarantee, it becomes too easy for users to accidentally spin up multiple scheduler instances, each of which is backed by its own threadpool. Instead, with akka-quartz-scheduler we use Akka's Extension system which provides a plugin model – we guarantee only one Quartz Scheduler is ever spun up per ActorSystem

But it looks like there are 2 Actor systems running independently... Am I missing something, how can I synchronize my 2 instances so that the scheduler fires event only once ?

Thanks !

enragedginger commented 5 years ago

Hi @pybuche,

Can you explain what you mean by "if I replicate it"? Are you talking about replicating your app on Heroku? Is it basically spinning up multiple instances of your Play application?

jarlah commented 4 years ago

You need to setup the Play application in an Akka cluster to avoid having the same actor being spun up on both nodes. I was just looking at this issue now and was beginning to get afraid this is actually an issue, but as I conclude its an issue with missing Akka cluster configuration. Correct me if I am wrong. When both apps are in the same Akka cluster, there exists options to check that the actor does not exist in the cluster. Or sumtin sumtin. Until I need it, need to know basis :P

enragedginger commented 4 years ago

@jarlah I believe you're correct. I'm going to close this issue for now. Thanks for investigating.