Call Clojure function on a timer
In Clojure, I didn't see a nice way to simply call a function on a timer (e.g. to poll for changes in another service).
I didn't find something in clojure.core
to achieve this readily (but clojure.core
is quite big, so I may have missed something obvious — let me know), so I whipped up the following to put in my project's util.clj
file:
(defn tick
"Call f with args every ms. First call will be after ms"
[ms f & args]
(future
(doseq [f (repeatedly #(apply f args))]
(Thread/sleep ms)
(f))))
(defn tick-now
"Call f with args every ms. First call will be immediately (and blocking)"
[ms f & args]
(apply f args)
(apply tick ms f args)
There are two variants. tick
waits ms
milliseconds and then calls f
with args
and repeats indefinitely. tick-now
does the same thing except it calls f
with args
before starting the timer.
They are simple to use:
user=> (tick 500 #(println "hi"))
; 500ms delay
hi
; 500ms delay
hi
; 500ms delay
hi
...
In my project, I'm using them like so:
(defn start-fetchers
[api-token]
(future
(let [minutes (partial * 60 1000)]
(tick-now (minutes 60)
update-project-list!
api-token)
(tick-now (minutes 5)
fetch-milestones!
api-token
projects-to-fetch
milestones-by-project))))