Reputation: 1174
While one can use threads and set a timeout to run a function at set intervals from the time a new Thread has been started, how to make it so that the function runs at 00:00:00 starting from the next midnight?
Upvotes: 1
Views: 869
Reputation: 1976
You can interop to any Java library like Quartz, cron4j or Java Timer itself. To make it more idiomatic to Clojure, you can also write a macro (or couple functions) to simplify things. For example, using a roll-your-own macro:
(deftask my-midnight-task
"0 0 * * 2-6"
(println "start to work")
(do-something))
where "0 0 * * 2-6" is a cron like pattern used in cron4j. Implementation in here is using mount to take care of scheduling and descheduling:
(defonce ^Scheduler scheduler (doto (Scheduler.)
(.setDaemon true)
(.start)))
(defmacro deftask [name cron & body]
`(defstate ~name
:start (.schedule scheduler ~cron (fn [] ~@body))
:stop (.deschedule scheduler ~name)))
Upvotes: 1
Reputation: 1989
You could also take a look at chime library.
I did not test this code, but something like this.
(ns my.example
(:require [chime :refer [chime-at]])
(:import [java.time Instant LocalTime ZonedDateTime ZoneId Period]))
(defn my-task []
(println "Executing a task"))
(defn periodic-seq [^Instant start duration-or-period]
(iterate #(.addTo duration-or-period %) start)) ;; produces a lazy-seq of Instants
;; generates infinite sequence of days. Change the time zone to the one you need.
(def days
(periodic-seq (-> (LocalTime/of 23 0 0)
(.adjustInto (ZonedDateTime/now (ZoneId/of "America/New_York")))
.toInstant)
(Period/ofDays 1)))
(chime-at days (fn [time] (my-task)))
chime-at returns a zero arg function, that you can call to cancel the schedule. So you need to start the schedule like this.
(def cancel (chime-at days (fn [time] my-task)))
(cancel)
Again, I haven't tested this code.
Upvotes: 2
Reputation: 29958
Just use a java.util.Timer
: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Timer.html#schedule(java.util.TimerTask,java.util.Date)
public void schedule(TimerTask task, Date time)
Schedules the specified task for execution at the specified time. If the time is in the past, the task is scheduled for immediate execution.
Parameters:
task - task to be scheduled.
time - time at which task is to be executed.
It looks like ScheduledThreadPoolExecutor is a bit newer and has some improvements. Esp see
scheduleAtFixedRate(Runnable command, long initialDelay,
long period, TimeUnit unit)
Submits a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is, executions will commence after initialDelay, then initialDelay + period, then initialDelay + 2 * period, and so on.
You may also be interested in at-at
library: https://github.com/overtone/at-at
Upvotes: 2