[It's about time!]

We've always supported scheduling jobs using a cron-style syntax. We've now extended that to support a finer-grained at-style syntax:

(require '[immutant.jobs :as jobs])

(jobs/schedule "my-at-job"
                #(println "I fire 4 times with a 10ms delay between each, starting in 500ms.")
                :in 500   
                :every 10 
                :repeat 3)

This functionality is available in recent incremental builds, and will be in 0.9.0, which should be released todaytomorrow.

The Details

Instead of a specification string, at-style jobs are controlled by a set of options that are passed to the immutant.jobs/schedule function, and can be mixed and matched.

We won't go through all of the permutations of the options here - you can see the details in the docs. Instead, we'll look at a few examples of usage.

If you specify a job without a cron specification or any at options, it will fire once, immediately:

(jobs/schedule "fire-now"  
               #(println "I'll fire right now, once."))

Specifying a job with just a start option (either :at or :in) will still only fire once, but at the specified time:

;; you can specify :at as a Date
(jobs/schedule "fire-later"  
               #(println "I'll fire at a-java-util-date, once.")
               :at a-java-util-date)

#inst "2013-02-27T18:29:35.222-00:00" 1361989775222

;; or as ms since the epoch
(jobs/schedule "fire-later2"  
               #(println "I'll fire at 2013-02-27T18:29:35.222, once.")
               :at 1361989775222)

;; :in signifies "ms from now"
(jobs/schedule "fire-in"  
               #(println "I'll fire in 500 ms, once.")
               :in 500)

You can control repetition of the jobs with :every, :repeat, and :until:

;; fire every 500 ms, forever
(jobs/schedule "fire-forever"  
               #(println "I'll fire every 500 ms, forever.")
               :every 500)

;; fire every 500 ms until a time in the future
(jobs/schedule "fire-for-a-while"  
               #(println "I'll fire every 500 ms, until a-java-util-date-or-ms-since-epoch.")
               :every 500
               :until a-java-util-date-or-ms-since-epoch)

;; fire 6 times, every 500 ms
(jobs/schedule "fire-repeat"  
               #(println "I'll fire 6 times (:repeat + 1) on a 500 ms interval.")
               :every 500
               :repeat 5)

;; all of the above work with an :at or :in
(jobs/schedule "fire-forever-in-a-bit"  
               #(println "I'll fire every 500 ms, forever, starting in 2500 ms.")
               :every 500
               :in 2500)

At-style jobs can be unscheduled just like cron-style jobs by passing the name to immutant.jobs/unschedule, which will be called on your behalf when the application is undeployed if you don't do it. They can also be rescheduled by calling schedule again with the same name. So "forever" in the examples really means "until undeployed, unscheduled, or rescheduled".

Can I still use the cron syntax?

Absolutely! The only change that will affect you is the order of arguments to the schedule function have changed (the old order still works for now, but is deprecated, and will be removed in 1.0.0.Beta1):

(require '[immutant.jobs :as job])
;; the deprecated signature
(jobs/schedule "old-api-cron-job"  
                   "*/5 * * * * ?"
                   #(println "I fire every 5s, forever."))

;; the new signature
(jobs/schedule "new-api-cron-job"  
                   #(println "I fire every 5s, forever.")
                   "*/5 * * * * ?")

At-style jobs are fairly new - please give it a try and let us know if you have any issues or questions.

Image credit: quinnums