Periodically calling a function in Clojure

If you want very simple

(defn set-interval [callback ms] 
  (future (while true (do (Thread/sleep ms) (callback)))))

(def job (set-interval #(println "hello") 1000))
 =>hello
   hello
   ...

(future-cancel job)
 =>true

Good-bye.


There's also quite a few scheduling libraries for Clojure: (from simple to very advanced)

  • at-at
  • chime (core.async integration)
  • monotony
  • quartzite

Straight from the examples of the github homepage of at-at:

(use 'overtone.at-at)
(def my-pool (mk-pool))
(let [schedule (every 1000 #(println "I am cool!") my-pool)]
  (do stuff while schedule runs)
  (stop schedule))

Use (every 1000 #(println "I am cool!") my-pool :fixed-delay true) if you want a delay of a second between end of task and start of next, instead of between two starts.


The simplest approach would be to just have a loop in a separate thread.

(defn periodically
  [f interval]
  (doto (Thread.
          #(try
             (while (not (.isInterrupted (Thread/currentThread)))
               (Thread/sleep interval)
               (f))
             (catch InterruptedException _)))
    (.start)))

You can cancel execution using Thread.interrupt():

(def t (periodically #(println "Hello!") 1000))
;; prints "Hello!" every second
(.interrupt t)

You could even just use future to wrap the loop and future-cancel to stop it.


This is how I would do the core.async version with stop channel.

(defn set-interval
  [f time-in-ms]
  (let [stop (chan)]
    (go-loop []
      (alt!
        (timeout time-in-ms) (do (<! (thread (f)))
                                 (recur))
        stop :stop))
    stop))

And the usage

(def job (set-interval #(println "Howdy") 2000))
; Howdy
; Howdy
(close! job)