Cronut-Javax provides a data-first Clojure wrapper
for Quartz Scheduler version 2.4.0
, compatible
with Javax.
Cronut supports in-memory scheduling of jobs within a single JVM. JDBC and distributed jobstore are not supported.
Project | Desription | Clojars Project |
---|---|---|
cronut | Cronut with Jakarta support | |
cronut-integrant | Integrant bindings for Cronut |
A quartz scheduler
runs a job
on a schedule defined by a trigger
.
Cronut provides access to the Quartz Scheduler, exposed via the cronut/scheduler
function.
Create a scheduler with the following configuration:
:concurrent-execution-disallowed?
: (optional, default false) - run all jobs with @DisableConcurrentExecution:update-check?
: (optional, default false) - check for Quartz updates on system startup.(cronut/scheduler {:concurrent-execution-disallowed? true
:update-check? false})
Once created, you can:
cronut/start
: start the schedulercronut/start-delayed
: start the scheduler with a delaycronut/standy
: temporarily halt the firing of triggers by the schedulercronut/shutdown
: stop the schedulercronut/pause-all
: pause all triggerscronut/resume-all
: resume all triggerscronut/clear
: clear all scheduling data of jobs and triggersTo schedule jobs, you can
cronut/schedule-job
: schedule a single jobcronut/schedule-jobs
: schedule multiple jobs at oncecronut/pause-job
: pause a jobcronut/resume-job
: resume a paused jobcronut/delete-job
: remove a job from the schedulercronut/pause-trigger
: pause a triggercronut/resume-trigger
: resume a paused triggercronut/unschedule-trigger
: remove a trigger from the schedulerEach cronut job must implement the org.quartz.Job
interface.
The expectation being that every job will reify that interface either directly via reify
or by returning a defrecord
that implements the interface.
Cronut supports further Quartz configuration of jobs (identity, description, recovery, and durability) by expecting
those values to be assoc'd onto your job. You do not have to set them (in fact in most cases you can likely ignore
them), however if you do want that control you will likely use the defrecord
approach as opposed to reify
.
Concurrent execution can be controlled on a per-job bases with the disallow-concurrent-execution?
flag.
(defrecord TestDefrecordJobImpl [identity description recover? durable?]
Job
(execute [this _job-context]
(log/info "Defrecord Impl:" this)))
(let [scheduler (cronut/scheduler {:concurrent-execution-disallowed? true
:update-check? false})
defrecord-job (map->TestDefrecordJobImpl {:identity ["name1" "group2"]
:description "test job"
:recover? true
:durable? false})
reify-job (reify Job
(execute [_this _job-context]
(let [rand-id (str (UUID/randomUUID))]
(log/info rand-id "Reified Impl"))))]
(cronut/schedule-job scheduler (trigger/interval 1000) defrecord-job)
(cronut/schedule-job scheduler
(trigger/builder {:type :cron
:cron "*/5 * * * * ?"
:misfire :do-nothing})
reify-job))
Cronut triggers are of type org.quartz.Trigger
, the following functions are provided to simplify trigger creation:
cronut.trigger/cron
: Simple Cron SchedulingA job is scheduled to run on a cron by using the cronut.trigger/cron
function with a valid cron expression.
The job will start immediately when the system is initialized, and runs in the default system time-zone
(cronut.trigger/cron "*/8 * * * * ?")
cronut.trigger/interval
: Simple Interval SchedulingA job is scheduled to run periodically by using the cronut.trigger/interval
function with a milliseconds value
(cronut.trigger/interval 3500)
cronut.trigger/builder
: Full trigger definitionBoth cronut.trigger/cron
and cronut.trigger/interval
are effectively shortcuts to full trigger definition with
sensible defaults.
The cronut.trigger/builder
function supports the full set of Quartz configuration triggers:
;; interval
(cronut.trigger/builder {:type :simple
:interval 3000
:repeat :forever
:identity ["trigger-two" "test"]
:description "sample simple trigger"
:start #inst "2019-01-01T00:00:00.000-00:00"
:end #inst "2019-02-01T00:00:00.000-00:00"
:misfire :ignore
:priority 5})
;;cron
(cronut.trigger/builder {:type :cron
:cron "*/6 * * * * ?"
:identity ["trigger-five" "test"]
:description "sample cron trigger"
:start #inst "2018-01-01T00:00:00.000-00:00"
:end #inst "2029-02-01T00:00:00.000-00:00"
:time-zone "Australia/Melbourne"
:misfire :fire-and-proceed
:priority 4})
Set :concurrent-execution-disallowed?
on the scheduler to disable concurrent execution of all jobs.
Set :disallow-concurrent-execution?
on a specific job to disable concurrent execution of that job only.
If you disable concurrent job execution ensure you understand Quartz Misfire options and remember to set
org.quartz.jobStore.misfireThreshold=[some ms value]
in your quartz.properties file. See Quartz documentation for more
information.
See our test-resources/config.edn and test-resources/org/quartz/quartz.properties for examples of misfire threshold and behaviour configuration.
See: integration test source: test/cronut/integration-test.clj.
(ns cronut.integration-test
(:require [clojure.core.async :as async]
[clojure.tools.logging :as log]
[cronut :as cronut]
[cronut.trigger :as trigger])
(:import (java.util UUID)
(org.quartz Job)))
(defrecord TestDefrecordJobImpl [identity description recover? durable? test-dep disallowConcurrentExecution?]
Job
(execute [this _job-context]
(log/info "Defrecord Impl:" this)))
(def reify-job (reify Job
(execute [_this _job-context]
(let [rand-id (str (UUID/randomUUID))]
(log/info rand-id "Reified Impl (Job Delay 7s)")
(async/<!! (async/timeout 7000))
(log/info rand-id "Finished")))))
;(do (require '[cronut.integration-test :as it])
; (it/test-system))
(defn test-system
[]
(let [scheduler (cronut/scheduler {:concurrent-execution-disallowed? true})]
(cronut/clear scheduler)
(async/<!! (async/timeout 2000))
(log/info "scheduling defrecord job on 1s interval")
(cronut/schedule-job scheduler
(trigger/interval 1000)
(map->TestDefrecordJobImpl {:identity ["name1" "group2"]
:description "test job"
:recover? true
:durable? false}))
;; demonstrate scheduler can start with jobs, and jobs can start after scheduler
(cronut/start scheduler)
(async/<!! (async/timeout 2000))
;; demonstrates concurrency disallowed (every second job runs, 10s interval between jobs that should run every 5s)
(log/info "scheduling reify/7s/no-misfire job on 5s interval")
(cronut/schedule-job scheduler
(trigger/builder {:type :cron
:cron "*/5 * * * * ?"
:misfire :do-nothing})
reify-job)
(async/<!! (async/timeout 15000))
(log/info "deleting job group2.name1")
(cronut/delete-job scheduler "name1" "group2")
(async/<!! (async/timeout 15000))
(cronut/shutdown scheduler)))
Distributed under the Apache 2.0 License.
Copyright (c) Factor House
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
Ctrl+k | Jump to recent docs |
← | Move to previous article |
→ | Move to next article |
Ctrl+/ | Jump to the search field |