Code Monkey home page Code Monkey logo

akka-quartz-scheduler's Introduction

akka-quartz-scheduler

Build Status

Quartz Extension and utilities for true scheduling in Akka 2.6.x.

Current release is built for Scala 2.13.x and Akka 2.6.x and is available on Maven Central. If you would like support for a different combination of Scala and Akka, simply post your request on the issues page (as well as a reason as to why the currently available versions won't work for you. I'm always curious about these things).

Why Akka and Quartz?

Note that this is named and targeted as akka-quartz-scheduler for a reason: it is not a complete port of Quartz. Rather, we utilize the concepts of Quartz' scheduling system to provide a more robust and reliable scheduling component to Akka than the one already available.

The goal here is to provide Akka with a scheduling system that is closer to what one would expect for Cron type jobs – set up long-running ActorSystems that can have certain events kicked off by Quartz.

There aren't currently any plans on having anything to do with the distributed transaction, persistence, clustering or any other nonsense anytime soon. This is for cron-ey type timing and scheduling.

There is the ability in Quartz to pass JobDataMaps around that accrue mutable state across job ticks; we currently do NOT support that to enforce integrity, but may expose a deeper actor structure later that gives some ability to work around that, if need arises.

Why Not Use $OtherComparableTool Instead?

  1. What's wrong with Akka's existing Scheduler? As Viktor Klang points out, 'Perhaps the name "Scheduler" was unfortunate, "Deferer" is probably more indicative of what it does.'

    The Akka Scheduler is designed to setup events that happen based on durations from the current moment: You can say "fire this job in 15 minutes, every 30 minutes thereafter" but not "fire a job every day at 3pm".

    Furthermore, Akka's default scheduler is executed around a HashedWheelTimer – a potential precision loss for jobs, as it does not provide strong guarantees on the timeliness of execution.

  2. Why not just use the Quartz component in Akka's Camel Extension?

    1. To begin with, Akka's Camel extension was not available in Akka 2.0.x, only in 2.1+
    2. Camel brings with it a whole architecture change (Consumers, Producers, etc) and is not exactly "lightweight" to plug in if all you want is Quartz support.
    3. We wanted to bring the scheduling concept of Quartz into Akka as cleanly as possible with native configuration integration and a lightweight feel.
  3. What about that other akka-quartz component up on GitHub?

    The interface to this aforementioned akka-quartz component is via Actors - one creates an instance of an Actor that has its own Quartz Scheduler underneath it, and sends messages to that Actor to schedule jobs. 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. This means we will never create anything but one single Thread Pool which you have control over the size of, for any given ActorSystem.

Finally, a common failure of the above listed alternatives is that configuration of things like a repeating schedule should be separated from code in a configuration file which an operations team (not the developers) can control. Thus, akka-quartz-scheduler only allows specifying the following in code: the name of a job, what actor to send the tick to, and the message to send on a tick. The configuration of how frequently to 'tick' on a schedule is externalised to the Akka configuration file; when a schedule request is made its name is matched up with an entry in the config which specifies the rules the actual scheduling should follow.

Thus, development can outline the skeleton of repeating jobs in their code, specifying only what to do WHEN a 'tick' of the schedule fires. Then, operations has complete control over how often a job runs and what rules it follows to determine the schedule of firing.

This, among other things, prevents accidental mistakes such as changing a schedule in development for testing. A change of that sort is fixable without Operations needing to require a recompilation of source code.

TODO

  • investigate supporting listeners, with actor hookarounds.
  • misfires and recovery model - play nice with supervision, deathwatch, etc [docs page 23 - very close to supervision strategy]

Usage

See CHANGELOG.md for a list of changes by release.

Usage of the akka-quartz-scheduler component first requires including the necessary dependency in your SBT project:

// For Akka 2.6.x and Akka Typed Actors 2.6.x and Scala 2.12.x, 2.13.x, 3.1.x
libraryDependencies += "com.enragedginger" %% "akka-quartz-scheduler" % "1.9.3-akka-2.6.x"

// For Akka 2.6.x and Scala 2.12.x, 2.13.x
libraryDependencies += "com.enragedginger" %% "akka-quartz-scheduler" % "1.8.5-akka-2.6.x"

// For Akka 2.5.x and Scala 2.11.x, 2.12.x, 2.13.x
libraryDependencies += "com.enragedginger" %% "akka-quartz-scheduler" % "1.8.1-akka-2.5.x"

// For Akka 2.4.x and Scala 2.11.x, 2.12.x
libraryDependencies += "com.enragedginger" %% "akka-quartz-scheduler" % "1.6.0-akka-2.4.x"

Note: As of Akka 2.6, Scala 2.11 is no longer supported. If you wish to use newer versions of akka-quartz-scheduler, but you're stuck on Scala 2.11 for some reason, please open an issue / PR and we'll see what we can do.

//Older versions of the artifact for those that require pre Akka 2.3 or pre Scala 2.11
//If you would like a current version of the artifact to be published for your required version
//of Akka and Scala, simply file on issue on the project page.
resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"


// For Akka 2.0.x
libraryDependencies += "com.typesafe.akka" %% "akka-quartz-scheduler" % "1.2.0-akka-2.0.x"
// For Akka 2.1.x
libraryDependencies += "com.typesafe.akka" %% "akka-quartz-scheduler" % "1.2.0-akka-2.1.x"
// For Akka 2.2.x
libraryDependencies += "com.typesafe.akka" %% "akka-quartz-scheduler" % "1.2.0-akka-2.2.x"
// For Akka 2.3.x and Scala 2.10.4
libraryDependencies += "com.typesafe.akka" % "akka-quartz-scheduler_2.10" % "1.4.0-akka-2.3.x"

Note that the version name includes the Akka revision (Previous releases included the Akka release in the artifact name, which broken Maven).

Akka Typed Actor (2.6.x)

If you use newer Akka Actor version then, from within your Akka project you can create and access a Typed Scheduler:

// Akka Typed Actors sample.
import com.typesafe.akka.extension.quartz.QuartzSchedulerTypedExtension

val scheduler = QuartzSchedulerTypedExtension(typedSystem)

Where typedSystem represents an instance of an Akka Typed ActorSystem[-T] – note that QuartzSchedulerTypedExtension is scoped to that ActorSystem[-T] and there will only ever be one instance of it per ActorSystem[-T].

The primary external method on the scheduler instance is schedule, used for scheduling a job:

def scheduleTyped[T](name: String, receiver: ActorRef[T], msg: T): java.util.Date

OR

def scheduleTyped[T](name: String, receiver: ActorRef[T], msg: T, startDate: Option[Date]): java.util.Date

The arguments to schedule are:

  • name: A String identifying the name of this schedule. This must match a schedule present in the configuration
  • receiver: A typed ActorRef[T], who will be sent msg each time the schedule fires
  • msg: An instance of A, representing a message instance which will be sent to receiver each time the schedule fires
  • startDate: An optional Date, for postponed start of a job. Defaults to now.

Invoking scheduleTyped[A] returns an instance of java.util.Date, representing the first time the newly setup schedule will fire.

Each time the Quartz schedule trigger fires, Quartz will send a copy of msg to your receiver actor.

Note that you can use the same logic for scheduling Quartz with Akka Typed Actor as the older version.

Akka Actor (2.5.x)

If you use old Akka Actor version then, from within your Akka project you can create and access a Scheduler:

// Akka Actors sample.
import com.typesafe.akka.extension.quartz.QuartzSchedulerExtension

val scheduler = QuartzSchedulerExtension(system)

Where system represents an instance of an Akka ActorSystem – note that QuartzSchedulerExtension is scoped to that ActorSystem and there will only ever be one instance of it per ActorSystem.

The primary external method on the scheduler instance is schedule, used for scheduling a job:

def schedule(name: String, receiver: ActorRef, msg: AnyRef, startDate: Option[Date]): java.util.Date

OR

def schedule(name: String, receiver: ActorSelection, msg: AnyRef, startDate: Option[Date]): java.util.Date

The arguments to schedule are:

  • name: A String identifying the name of this schedule. This must match a schedule present in the configuration
  • receiver: An ActorRef or ActorSelection, who will be sent msg each time the schedule fires
  • msg: An AnyRef, representing a message instance which will be sent to receiver each time the schedule fires
  • startDate: An optional Date, for postponed start of a job. Defaults to now.

Invoking schedule returns an instance of java.util.Date, representing the first time the newly setup schedule will fire.

Each time the Quartz schedule trigger fires, Quartz will send a copy of msg to your receiver actor.

Here is an example, using a schedule called Every30Seconds, which sends a Tick message to a CleanupActor (which does hand wavy cleanup things):

case object Tick

val cleaner = system.actorOf(Props[CleanupActor])

QuartzSchedulerExtension(system).schedule("Every30Seconds", cleaner, Tick)

Where the Tick message is handled normally inside the Actor's message loop. If one wanted to ensure that schedule messages were dealt with more immediately than "normal" actor messages, they could utilize Priority Mailboxes.

The details on the configuration of a job is outlined below in the section 'Schedule Configuration'.

Returning scheduled Fire Time

There are situations where the fire time is helpful. For example, when an error occurs, we know which job trigger is being processed and can be recovered.

Here is an example using the case class MessageRequireFireTime wrapping the Tick message. This will send a MessageWithFireTime(Tick, previousFireTime, scheduledFireTime, nextFireTime) message to a WorkerActor:

case object Tick

val worker = system.actorOf(Props[WorkerActor])

QuartzSchedulerExtension(system).schedule("Every30Seconds", worker, MessageRequireFireTime(Tick))

Configuration of Quartz Scheduler

All configuration of akka-quartz-scheduler is done inside of the Akka configuration file in an akka.quartz config block. Like Akka's configuration file, this follows the HOCON Configuration Format. Thus, any entries specified as foo.bar.baz = x can also be expressed as foo { bar { baz = x } }.

At the top level of the configuration, optional values may be set which override the defaults for:

  • defaultTimezone - [String] represents the timezone to configure all jobs to run in. DEFAULTS TO UTC must be parseable by java.util.TimeZone.getTimeZone(),
  • threadPool.threadCount - [Int] The number of threads to allocate to the internal Quartz threadpool. DEFAULTS TO 1 - you may wish to up this number if you have a large number of schedules being executed. With only 1 thread, each trigger will queue up and you may not get responsive schedule notifications.
  • threadPool.threadPriority - [Int] A number, between 1 (Lowest priority) and 10 (Highest priority), specifying the priority to assign to Quartz' threads DEFAULTS TO 5
  • threadPool.daemonThreads - [Boolean] A boolean indicating whether the threads Quartz creates should execute as Daemon Threads or not. DEFAULTS TO TRUE

There are two 'primary' sub-blocks of the akka.quartz configuration, which are schedules and calendars.

Schedule Configuration

Schedules are our abstraction over Quartz' Job & Trigger concepts. They allow you to define a named schedule, which will fire a schedule event (sending a message to an actor, as specified in code) each time the Quartz trigger fires.

Currently, you can only specify "Cron" schedules, which follow Quartz' CronExpression Language, which is designed to match the standard Unix cron syntax with a few nice additions.

The schedule name in the configuration will be used to match it up with a requested job when schedule is invoked; case does not matter as the "Is there a matching job?" configuration lookup is case insensitive.

The configuration block for schedules is in akka.quartz.schedules, with sub-entries being specified inside of a named block, such that the configuration for a schedule named Every30Seconds would have its configuration values specified inside the configuration block akka.quartz.schedules.Every30Seconds.

The entries that can be placed inside of a schedule configuration are:

  • expression - [String] [required] a valid Quartz' CronExpression, which describes when this job should trigger. e.g. expression = "*/30 * * ? * *" would fire every 30 seconds, on every date (however, the firing schedule created by this expression is modified by the calendars variable, defined below)
  • timezone - [String] [optional] the timezone in which to execute the schedule, DEFAULTS TO akka.quartz.defaultTimezone, WHICH DEFAULTS TO UTC must be parseable by java.util.TimeZone.getTimeZone()
  • description - [String] [optional] a description of the job. DEFAULTS TO null. Mostly for human friendliness when they read your configuration aka "what this schedule is for", but set in Quartz as well for if you dump the scheduler contents for debug.
  • calendar - [String] [optional] An option String which is the name of a configured Calendar. This Calendar is applied to this schedule as "exemptions" (Any times/dates falling in the Calendar will be excluded from the schedule firing - i.e. a Calendar that excludes all Mondays would keep a schedule configured to trigger every hour, from triggering at all on Mondays. NOTE: In versions 1.3.x and prior, this property was "calendars" and supported a list of Strings. However, Quartz, and by proxy, this library never actually supported multiple calendars for one schedule. Therefore, in versions 1.4.x and beyond this property has been renamed to "calendar" and is an optional String. DEFAULTS TO None[String]

An example schedule called Every30Seconds which, aptly, fires off every 30 seconds:

akka {
  quartz {
    schedules {
      Every30Seconds {
        description = "A cron job that fires off every 30 seconds"
        expression = "*/30 * * ? * *"
        calendar = "OnlyBusinessHours"
      }
    }
  }
}

This Schedule specifies a Cron Expression which executes every 30 seconds of every day, but is modified by the calendar "OnlyBusinessHours", which excludes triggers from firing outside of between 8am and 6pm (and is detailed below).

Calendar Configuration

Calendars in the akka-quartz-scheduler mirror the concept of Quartz' Calendars – most specifically, they allow you to specify exclusions that override a schedule.

Calendars are configured globally, in the akka.quartz.calendars configuration block. The definition of a calendar and what it excludes is made within this block. By default, no Calendars are applied to a Schedule. Instead, you must reference a named Calendar inside the calendars array of a Schedule's configuration, as outlined above.

The configuration block for calendars is in akka.quartz.calendars, with sub-entries being specified inside of a named block, such that the configuration for a calendar named OnlyBusinessHours would have it's configuration values specified inside the configuration block akka.quartz.calendars.OnlyBusinessHours.

There are several types of Calendar, each with its own specific configurations. The configuration values which are common to all types of Calendar are:

  • type - [String] [required] a valid type of Calendar. Currently either: Annual, Holiday, Daily, Monthly, Weekly, and Cron
  • timezone - [String] [optional] the timezone in which to execute the calendar, DEFAULTS TO akka.quartz.defaultTimezone, WHICH DEFAULTS TO UTC must be parseable by java.util.TimeZone.getTimeZone()
  • description - [String] [optional] a description of the calendar. DEFAULTS TO null. Mostly for human friendliness when they read your configuration aka "what this calendar is for", but set in Quartz as well for if you dump the scheduler contents for debug.

Each specific Calendar type and its particular configuration entries are...

'Annual' Calendar

An annual calendar excludes specific days of a given year, e.g. bank holidays which fall on the same date every year (Christmas and Gregorian New Year's for example) This calendar does not take year into account, and will apply to all years.

It has only one configuration entry:

  • excludeDates - [Seq[String]] [required] This is a list of strings which are dates in the MM-DD format, representing which dates to exclude. For example, "Exclude Christmas and New Years" would read as excludeDates = ["12-25", "01-01"]

An example:

WinterClosings {
  type = Annual
  description = "Major holiday dates that occur in the winter time every year, non-moveable (The year doesn't matter)"
  excludeDates = ["12-25", "01-01"]
}
'Holiday' Calendar

A holiday calendar excludes specific dates, with a fully month, day, year taken into account. It is mostly useful for moving Bank Holidays (e.g. President's Day) and Moveable Feasts (e.g. Easter, which is based on a Lunar calendar).

It has only one configuration entry:

  • excludeDates - [Seq[String]] [required] This is a list of strings in the ISO-8601 date format (YYYY-MM-DD), representing which dates (with year taken into account) to exclude. For example, excluding the the next 5 years' Easter holidays would read as excludeDates = ["2013-03-31", "2014-04-20", "2015-04-05", "2016-03-27", "2017-04-16"]

An example:

Easter {
  type = Holiday
  description = "The easter holiday (a moveable feast) for the next five years"
  excludeDates = ["2013-03-31", "2014-04-20", "2015-04-05", "2016-03-27", "2017-04-16"]
}
'Daily' Calendar

A daily calendar excludes a specified time range each day. It may not cross daily boundaries, and Quartz will enforce this. i.e. You cannot specify "11PM to 1AM" – to do that you'll need to specify two separate daily calendars.

Exclusions in a Daily calendar are specified in a exclude with a startTime and endTime entry. Each of these fields follows a time format of HH:MM[:SS[:mmm]] where: - HH is the hour of the specified time using military (24-hour) time, and must be in the range 0-23 - MM is the minute of the specified time, and must be in the range 0-59 - SS is the optional second of the specified time, and must be in the range 0-59 - mmm is the optional millisecond of the specified time, and must be in the range 0-999

An example, which doesn't allow jobs to run between 3AM and 5AM during the PST Timezone:

HourOfTheWolf {
  type = Daily
  description = "A period every day in which cron jobs are quiesced, during night hours"
  exclude {
    startTime = "03:00"
    endTime   = "05:00:00"
  }
  timezone = PST
}
'Monthly' Calendar

A monthly calendar excludes a set of days of the month, i.e. "Don't run a job on the 1st or 15th days of the month"

It has only one configuration entry:

  • excludeDays - [Seq[Int]] [required] This is a list of Ints, between 1 and 31, representing a day of the month.

An example:

FirstAndLastOfMonth {
  type = Monthly
  description = "A thinly veiled example to test monthly exclusions"
  excludeDays = [1, 31]
}
'Weekly' Calendar

A weekly calendar excludes a set of days of the week. By default, Saturday and Sunday are always excluded

The configuration entries:

  • excludeDays - [Seq[Int]] [required] This is a list of Ints, between 1 and 7 – where 1 is Sunday and 7 is Saturday – representing days of the week to exclude.
  • excludeWeekends - Boolean defaults to TRUE Whether weekends should be excluded automatically by this scheduler or not. Note that excludeWeekends is overriden by excludeDays – if you specify excludeWeekends = false but excludeDays includes Sunday (1) or Saturday (7), then a configuration error will be thrown.

An example, which excludes jobs from running on any Monday:

MondaysSuck {
  type = Weekly
  description = "Everyone, including this calendar, hates mondays as an integer"
  excludeDays = [2]
  excludeWeekends = false
}

Note that by default, excludeWeekends would be true and thus excludeDays would implicitly be [1, 2, 7]

'Cron' Calendar

A cron calendar excludes the set of times expressed by a given Quartz CronExpression.

It has only one configuration entry:

  • excludeExpression - [String] [required] A valid Quartz CronExpression, which will be used to specify what times a job cannot run in (the opposite of a Cron Schedule).

An example Calendar, which specifies an exclusion set of 00:00 - 07:59 and 18:00 - 23:59 (thereby only allowing jobs to run from 08:00 - 17:59):

OnlyBusinessHours {
  type = Cron
  excludeExpression = "* * 0-7,18-23 ? * *"
}

Dynamic create, update, delete JobSchedule operations

These JobSchedule operations let you programatically manage job and job scheduling all at once. For working examples please check test section: "The Quartz Scheduling Extension with Dynamic create, update, delete JobSchedule operations" in com.typesafe.akka.extension.quartz.QuartzSchedulerFunctionalSpec

Create JobSchedule

createJobSchedule let you create a new job and schedule it all at once:

val scheduleJobName : String = "myJobName_1"
val messageReceiverActor: ActorRef = myActorRef
val messageSentToReceiver : AnyRef = myCaseClassMessage 
val scheduleCronExpression: String = "*/10 * * ? * *" // Will fire every ten seconds

try { 
  scheduler.createJobSchedule(
  	name = scheduleJobName, 
  	receiver = messageReceiverActor, 
  	msg = messageSentToReceiver, 
  	cronExpression = scheduleCronExpression)
} catch {
  case iae: IllegalArgumentException => iae // Do something useful with it.
}	

In addition you can specify the following optional description, calendar and timezone parameters:

val scheduleJobDescriptionOpt : Option[String] = Some("Scheduled job for test purposes.")
val aCalendarName: Option[String] = Some("HourOfTheWolf")
val aTimeZone: java.util.TimeZone = java.util.TimeZone.getTimeZone("UTC")

try { 
  scheduler.createJobSchedule(
  	name = scheduleJobName, 
  	receiver = messageReceiverActor, 
  	msg = messageSentToReceiver, 
  	cronExpression = scheduleCronExpression, 
  	description = Some(job.description), 
  	calendar = aCalendarName, 
  	timezone = aTimeZone
  )
} catch {
  case iae: IllegalArgumentException => iae // Do something useful with it.
}	

Update JobSchedule

updateJobSchedule has exactely the same signature as create JobSchedule but tries to perform an update of an existing scheduleJobName

try { 
  scheduler.updateJobSchedule(
  	name = scheduleJobName, 
  	receiver = messageReceiverActor, 
  	msg = messageSentToReceiver, 
  	cronExpression = scheduleCronExpression, 
  	description = Some(job.description), 
  	calendar = aCalendarName, 
  	timezone = aTimeZone
  )
} catch {
  case iae: IllegalArgumentException => iae // Do something useful with it.
}	

Delete JobSchedule

try {
  if (scheduler.deleteJobSchedule(name = scheduleJobName)) { 
    // Do something if deletion succeeded
  } else {
    // Do something else if deletion failed
  }
} catch {
  case e: Exception =>
    // Take action in case an exception is thrown 
}

Mass operations suspendAll, resumeAll, deleteAll

These mass operations let you manage many JobSchedules at once. For working examples please check test section: "The Quartz Scheduling Extension with Dynamic mass methods" in com.typesafe.akka.extension.quartz.QuartzSchedulerFunctionalSpec

Suspend All Schedules

Suspends (pauses) all jobs in the scheduler.

try {
  scheduler.suspendAll()
} catch {
  case e: SchedulerException =>
    // Take action in case an exception is thrown 
}

Resume All Schedules

Unpauses all paused jobs in the scheduler.

try {
  scheduler.resumeAll()
} catch {
  case e: SchedulerException =>
    // Take action in case an exception is thrown 
}

Delete All Schedules

Deletes all jobs in the scheduler without shutting down the scheduler.

try {
  scheduler.deleteAll()
} catch {
  case e: SchedulerException =>
    // Take action in case an exception is thrown 
}

akka-quartz-scheduler's People

Contributors

akirarat avatar amdelamar avatar benwaffle avatar bwmcadams avatar camilosampedro avatar ceilican avatar enragedginger avatar erikwj avatar felipebonezi avatar gabrywu avatar jhulten avatar jilen avatar ktoso avatar kvma avatar maxsel avatar migmruiz avatar mtrna avatar patriknw avatar pawelkaczor avatar rbarazzutti avatar refond avatar rkuhn avatar rohanjamkhedkar avatar sjednac avatar takezoe avatar tanacasino avatar timothyklim avatar vinayakpathak avatar xai3 avatar yoshinorin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

akka-quartz-scheduler's Issues

incorrect artifact name in repo

from readme:
libraryDependencies += "com.typesafe.akka" %% "akka-quartz-scheduler" % "1.2.0-akka-2.2.x"

in fact:
libraryDependencies += "com.typesafe.akka" %% "akka-quartz-scheduler_2.10" % "1.2.0-akka-2.2.x"

at least for Gradle build tool

Custom calendars

Shouldn't it be possible to add custom calendars? I mean, actually calendars are just configurations with no possibility to "customization", like exclude weekends in monthly calendars(it's useful to pick the first business day of a month), because it's all inside QuartzCalendars and QuartzCalendars is accessed directly by QuartzSchedulerExtension, although it's possible to create custom calendars if extends QuartzSchedulerExtension and access scheduler.addCalendar internally, i don't think it's a bad practice, or is it?

Enhancement to support Akka-2.4.0

Hi Guys, first of all i would like to thank you all for this amazing library. Since one of my app is depends heavily on this scheduler, i would like to know whether there will be an enhancement to support Akka-2.4.0? The reason is i need to implement Akka Persistence which is based on Akka-2.4.0 and there is no documentation mentioning that this library can work properly with Akka-2.4.0.

Injecting class in Actor invoked by Akka-quartz-scheduler

I have the following actor in Play for Scala that injects a class with Guice:

class MainEtl extends Actor {

  @Inject val me2 : MainEtl2 = null

  def receive = {
    case option: String => {         
        val x = me2.run(option)
        // ... more code
        }
     } 
  }

When I try to schedule it I get an error as me2 is null:

[error] a.a.OneForOneStrategy - null
java.lang.NullPointerException: null
at tasks.etl.MainEtl$$anonfun$receive$1.applyOrElse(MainEtl.scala:17)
at akka.actor.Actor$class.aroundReceive(Actor.scala:484)
at tasks.etl.MainEtl.aroundReceive(MainEtl.scala:8)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526)
at akka.actor.ActorCell.invoke(ActorCell.scala:495)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
at akka.dispatch.Mailbox.run(Mailbox.scala:224)
at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)

This is how I invoke it:

         val scheduler = QuartzSchedulerExtension(system)
         val receiver = system.actorOf(Props[MainEtl])
         val d = scheduler.schedule("mycron", receiver, "abc", None)

How to get a reference to an injected object when the Actor is invoked from Akka-Quartz-Scheduler? I also tried injecting with @Inject as class parameters but that doesn't work either.

This is class MainEtl2 code:

class MainEtl2 @Inject() (ic: injectedClass) {
    def run (option: String) = {
      ic.method1() 
      // ... some code
    }
}

Messages firing at wrong time

I have a cron job scheduled with

akka.quartz.schedules {
  work {
    description = "Do something every hour on business hours"
    expression = "0 0 8-17 ? * MON-FRI"
  }
}

Instead of triggering on the hour, it's doing so at half past. It is possible that my country's timezone has something to do with this, because we are at -04:30 UTC, meaning we are displaced half an hour from what is usually expected.

Clearly I could adjust the time in the cron expression, but that would cause confusion to anyone trying to figure out when things are supposed to happen. Any help would be appreciated.

akka-quartz-scheduler for Akka 2.3 and Scala 2.10

We have an existing project that is using Scala 2.10, and I would like to use Akka 2.3 and also akka-quartz-scheduler. I see that akka-quartz-scheduler for Akka 2.3 is only compiled for Scala 2.11. Since Akka 2.3 also supports Scala 2.10, can you please publish a version for Scala 2.10? Thanks!

How to put two actors on the same schedule?

Hi,

I have a scheduleconfigured that's named "EveryMinuteDuringWeekdays". I want two distinct actors to receive a Tick-message on that named schedule. If I schedule the ticket message for only one actor, it works fine. If I want to schedule it for the other actor as well, I get an exception.

Exception:
org.quartz.ObjectAlreadyExistsException: Unable to store Job : 'DEFAULT.EveryMinuteDuringWeekdays_Job', because one already exists with this identification.

Code:
val scheduler = QuartzSchedulerExtension(system = context.system) scheduler.schedule("EveryMinuteDuringWeekdays", self, Tick) scheduler.schedule("EveryMinuteDuringWeekdays", receiver, Tick)

Looking at the source of akka-quartz-scheduler I cannot seem to find the correct way on how I'd make sure that more than one actor can be on a schedule. Could you point me to the right direction?

Is this project dead?

Hi, I am currently using this tools in my own project. Is the maintainer still here? If not, can I help with maintain the project? I saw a PR has not yet been merge for 7 months and I myself have some code to push...

Copy of message is send while invoking schedule method

Hi All,

I am using this scheduler in my application and found that whenever the schedule method is invoked then the copy of the message is being send down to the the sender class. example :-

schedule("EveryDayAt6AM", , new Date)

In the above example, I am passing new Date as the message to the actor. whenever the scheduler is invoked again then I was expecting the new Date but instead I am always getting the copy of the date object that was first send to the sender when the schedule method was invoked.

Is there a way to always send the new Date object to the sender using the quartz scheduler??

Using JDBC store instead of RAMStore

Hi,
Is there a way I can configure akka-quartz-scheduler to use JDBC store instead of RAMStore. Where can i specify JDBC data source details ?

Allow dynamic creation of schedules

If i'm not mistaken, for the moment, the only way to create schedules is to define them in a typesafe config file (application.conf or other).

In the scenario where a end-user would be able to create scheduled tasks from a UI, how could that be achieved?
Is it possible to do as such, or do we need to add a method to add schedules in QuartzSchedules.scala?

Can't restart a job put on standby

After suspending the scheduler, it can no longer be resumed.

val scheduler = PatchedQuartzSchedulerExtension(system)
scheduler.standby()
scheduler.start() // this line logs a warning saying it's already started

This is because the start method only checks the value of the isStarted field, but not the isInStandbyMode field.

Proposed patch:

  def start(): Boolean =
    if(isStarted && !isInStandbyMode) {
      log.warning("Cannot start scheduler, already started.")
      false
    } else {
      scheduler.start()
      true
    }

Scheduler triggers job on start

Hi there,

I'm seeing an issue where a job is triggered on initialization.

  val scheduler = QuartzSchedulerExtension(system)
  scheduler.schedule("EverySunday", treatmentRunner, Run)
  scheduler.schedule("EveryNight",
                     lotteryNotificationRunner,
                     Run,
                     startDate = Some(new DateTime("2017-05-26T00:00").toDate))

  scheduler.start()

This is what the scheduling looks like:

  quartz {
    schedules {
      EverySunday {
        description = "a job that fires every Sunday"
        expression = "0 0 17 ? * TUE" // 5 PM on sunday
        timezone = "Africa/Nairobi"
      }
      EveryNight {
        description = "Every night at 7pm"
        expression = "0 0 19 * * ?"
        timezone = "Africa/Nairobi"
      }
    }

There's no other place that could be sending this message to this actor. I'm a little confused as to why the "LotteryNotificationRunner" is executing on startup.

Looking for a new maintainer

This project is looking for a new maintainer! Please notify us in this issue if you would like to take over this project. It will be deleted in a few months unless we find a new owner.

Thread safety

Hi,

Should QuartzSchedulerExtension be made thread-safe?

My understanding is that Akka extensions must normally manage thread-safety internally. At the moment, I think that it is possible for concurrent access to createSchedule to result in a created schedule being lost if the reads, updates and writes occurring in schedules += (name.toUpperCase -> quartzSchedule) are interleaved - causing a subsequent call to schedule to fail.

Thanks,
-Dan

How to recover fail scheduled job?

I am using akka-actor system, and send message to my actor with in specific time. akka-quartz-scheduler is amazing library for schedule chron jobs easily. But if my scheduler node goes down, how can i recover my scheduler? because my scheduling job is really important. I know, for this, we need a clustering, but is there any way using akka-quartz-scheduler for recover scheduled jobs?

akka-quartz-scheduler with java

Hi, I just wanted to use your lib with playframework-java app.
I created sample project - https://github.com/sleski/play-akka-quartz-example
I created two actors which should be triggered by cron scheduler every 10seconds.
But this does not work. App starts, from log looks like it should be triggered:

[INFO] from com.typesafe.akka.extension.quartz.QuartzSchedulerExtension in application-akka.actor.default-dispatcher-2 - Setting up scheduled job 'HELLO_ACTOR', with 'com.typesafe.akka.extension.quartz.QuartzCronSchedule@746cb637'

[INFO] from com.typesafe.akka.extension.quartz.QuartzSchedulerExtension in application-akka.actor.default-dispatcher-2 - Setting up scheduled job 'CLEANUP_ACTOR', with 'com.typesafe.akka.extension.quartz.QuartzCronSchedule@34d78b1c'

I did not find any informations how to configure it in play java app, may some configuration is missing?!

I will be grateful for any tip/help.

Publish akka 2.5.x scala 2.11 version

Could you please publish a Scala 2.11 and akka 2.5.x compatible version of this library? In my project I can't upgrade to Scala 2.12 yet due to a dependency on Apache Spark.

How to unload the scheduler when Play is stopped/reloaded

Using the scheduler in Play for Scala, I initiate the scheduler on startup like so:

     val scheduler = QuartzSchedulerExtension(system)
     val d = scheduler.schedule("dailyproc", mainEtl, "abc", None)

Problem is that I load a table using Hibernate in the scheduler task, and when Play is reloaded due to code change, I get an error saying that classes "cannot be cast" where the class is the same. This happens because the classloaders are different.

One solution is to unload the scheduler when Play is reloaded, how can this be achieved? I could not find a method to unload the scheduler when Play is stopped/reloaded.

I tried with

scheduler.shutdown(true)

but it doesn't seem to unload the classes

Please see more details here

Schedule job for only once or with dynamic timer

Is it possible to schedule jobs which will be executed only once after a particular amount of time? Or schedule jobs which for which the time hasn't been specified in a strict configuration?

Need scheduler version of 1.2.0-akka-2.2.x

Hi,
Our product is using the play framework and akka with version 2.2.2. I would like to try this scheduler with our product. We are not planning to upgrade our akka version any time soon. Can you please publish 1.2.0-akka-2.2.x version of the scheduler.

RescheduleJob only accepts ActorRef

Why does the rescheduleJob in QuartzSchedulerExtension only accepts ActorRef in its parameters?I prefer to use ActorSelection over ActorRef. That way if the actor dies, you can get the new path from the ActorSelection. Can you make it also accept ActorSelection?

Add possibility to define misfire instructions for schedules

This is already on your TODO list.

I desperately need MISFIRE_INSTRUCTION_DO_NOTHING. Can I do anything to apply it in current (1.5.0) version? trait QuartzSchedule is sealed and class QuartzCronSchedule is final.

Is there a way to call withMisfireHandlingInstructionDoNothing() method on schedules?

Scheduler stops after 8 repetitions

I made some tests with the following cron expression
akka {
quartz {
schedules {
Every30Seconds {
description = "A cron job that fires off every 30 seconds"
expression = "*/30 * * * * ?"
}
}
}
}
I played around with different values for the expression but it always stops after 8 repetitions.

I'm importing this version of the library:
"com.enragedginger" %% "akka-quartz-scheduler" % "1.6.0-akka-2.4.x"
Scala version 2.11.6 and play version 2.5.12

Share schedule between multiple jobs

It would be nice to be able to reference a schedule from multiple jobs so one does not have to replicate the schedule for jobs with the same scheduling.

Can't remove schedule from QuartzSchedulerExtension directly.

I've problem to recreate schedule with different cron expression. I can use QuartzSchedulerExtension(system).createSchedule(xxxx) then I can use QuartzSchedulerExtension(system).schedule(xxxx) for the first time. However, I've to handle it in different way to recreate it by using QuartzSchedulerExtension(context.system).rescheduleJob(xxx).

Should cancelJob also call removeSchedule so that we can recreate it again later?

Another use of the scheduler

Hello,

In my projects I am currently using akka-quartz.

I would love to have all the benefits you are describing (especially the singleton-ity).

But I need to dynamically add jobs with custom schedules.

E.g. a message like this:

case OrderWithExpiry(order: Order, goodTill: Long) => {
    enqueueOrder(payload)
    val dt = new DateTime(goodTill)
    val cronString = s"${dt.getSecondOfMinute} ${dt.getMinuteOfHour} ${dt.getHourOfDay} ${dt.getDayOfMonth} ${dt.getMonthOfYear} ? ${dt.getYear}"
    quartz ! AddCronSchedule(self, cronString, ExpireOrder(order), false)
}

IMHO a quite basic use case is that some messages received by the system contain the definition of the cron schedule.

From what I understand, you explicitly ban this scenario - but maybe there is another way I could achieve my results assuming your approach? Rewriting textfile configuration would be very ineffective.

Best,

Jacek

Can't get a schedule to work with a weekly calendar

I'm using quartz scheduling in a scala project. Scheduling works fine unless a calendar is specified for a schedule. In that case, the task is never triggered by the scheduler. Example:

akka { quartz { defaultTimezone = "America/New_York" schedules { WeeklyEmailSchedule { description = "7:00 am every Friday" expression = "0 16 11 ? * FRI" } DailyEmailSchedule { description = "7:00 am every day" expression = "0 0 7 ? * *" calendar = "DailyCalendar" } } calendars { DailyCalendar { type = Weekly description = "Daily excluding friday" excludeDays = [6] excludeWeekends = false } } } }

If I comment out the line: calendar = "DailyCalendar" then everything works as expected. What am I doing wrong? Is my calendars prop invalid in any way?
Library version:
"com.enragedginger" % "akka-quartz-scheduler_2.11" % "1.4.0-akka-2.3.x"

Thanks so much!

Date doesn't change after Friday.

So we are using akka-quartz-scheduler for creating csv as part of a scheduled job which kicks off very 10 minutes (timing will change once application goes to prod).

My akka config looks like following :

akka {
	quartz {
  	  schedules {
  	    Every10Minutes {
  	      description = "A cron job that fires off every 10 minutes"
  	      expression = "0 0/10 * * * ?"
  	    }
  	  }
  	}
}

My scala code looks like following :

@PostConstruct
  def initMessageListener(): Unit = {
    val system = actorSystem
    //noinspection ScalaStyle
    val myManagerActor = system.actorOf(SpringExtension(system, ctx).props(senderManager), sender

Manager)
     QuartzSchedulerExtension(system).schedule("Every10Minutes", myManagerActor, getCurrentDate)  
  }

def getCurrentDate() : String = {
    val sdf = new SimpleDateFormat( "yyyy-MM-dd" );
    sdf.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
    sdf.format(new Date())    
  }

When my csv job is kicked off every 10 minutes, I am logging the message as following :
Received request to load json documents with date 2017-02-01 ",

QUERY

Assume that I started my application on Monday morning. The problem is that everything works fine till friday 11:59:59 PM. However the moment the day changes after Friday, the date parameter passed to scheduler expression never changes to Saturday's date and application continues invoke job with Friday's date.

We've observed this on two consecutive weeks and everything works fine on weekday but issue only comes after Fridays. Initially we thought it must be some random issue, however second time we realized that something is definitely not right and we have no idea why this is happening.

Need help on this and quick response is really appreciated.

delete a job which is not running

I am wondering if there is any way to delete a job which is not running~
After review the code, I found that I can access it by using
QuartzSchedulerExtension. schedules -= (key)
However, the key is not what I have created by
QuartzSchedulerExtension.createSchedule(key, description....)
I have to uppercased the key. (As well as some other operations related to the key, as follows)

 if (scheduler.schedules.contains(jobName)){
      if (scheduler.runningJobs.contains(jobName))
        scheduler.cancelJob(jobName)
      else
        scheduler.schedules -= (jobName) //delete
    }

Hope that you can giving some explanation.

Akka-quartz-scheduler not invoking multiple actors

I am using play 2.5.x with Akka-quartz-scheduler - 1.5.0-akka-2.4.x

quartz configuration in application.conf :
defaultTimezone = "India"
schedules {
NowAndThen {
description ="Delete temp files now and then, eg every hour"
expression = "*/1 * * * * ?"
calendars = ["MINIMAL"]
}
TestCalender {
description = "Test calender"
expression = "0 52 13 1/1 * ? *"
calendars = ["TESTTIME"]
}
}
calendars {
MINIMAL {
type = Daily
exclude {
startTime = "19:02:00"
endTime = "19:02:01"
}
}
TESTTIME {
type = Daily
exclude {
startTime = "19:02:00"
endTime = "19:02:01"
}
}
}

In my quartz mapping :
QuartzSchedulerExtension scheduler =(QuartzSchedulerExtension) QuartzSchedulerExtension.get(system);
//Logger.debug("scheduler created");
scheduler.schedule("NowAndThen",cleanupRef,"Clean");
scheduler.schedule("TestCalender", testJob, "Test");

1st actor is invoked but not the second actor.

I tried with single actor with message check but that also not worked for calling the second actor.

Please check this issue.

Default timezone

Hello,

Just a quick question ... Don't you think that timezone should be set automaticaly to the system timezone?

I spent 2 hours figuring out why my job wasn't triggered ;)

Thanks for this great extension !

Ignoring the first message

Hi

I'm using to schedule daily cron jobs (run at midnight), but I want to somehow ignore the first message (when apps starts). Is there a way to add this?

Is it possible to use with Java?

I have an akka project written in Java. So, is it possible to use akka-quartz-scheduler in a java project? Or should I build and create a package to use in my project?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.