Although the older version (v1) is available on Quicklisp, the current version (v2) may not yet be listed. To use this program, download it to your local-projects directory and evaluate the form in Lisp:
(ql:quickload :cl-schedule)
(in-package :cl-schedule)
To run the test cases, evaluate the form
(ql:quickload :cl-schedule.test)
To run a function on every minute
(defun hello () (format t "Hello!") (terpri))
(schedule! :func #'hello
:time '(:second 0))
A more complicated time-spec that replicates */25 5-6,10 4 7 1-3
(cron-style) is
(defun 25-multi (n) (= 0 (mod n 25)))
(schedule! :func #'hello
:time '(:second 0
:minute (satisfies 25-multi)
:hour (or (integer 5 6)
(member 10))
:date 4
:month 7
;; day (0 1 2 3 4 5 6) means (Mon Tue Wed Thu Fri Sat Sun)
;; so instead of 1-3, we use 0-2.
:day (integer 0 2)))
The keywords satisfies
, or
, integer
, and member
are integral
components of Common Lisp’s type system domain-specific language.
Our time-spec language extends this functionality to support a
broader range of use cases.
If a time-spec becomes too complex, you can use the #'dry-run
function to obtain a list of all universal times that satisfy the
specified time range. This utility can be invaluable when
debugging or testing the behavior of your program. For instance,
consider the following example:
(assert
(equal- (mapcar #'local-time:universal-to-timestamp
(dry-run '(:second 0 ; time-spec
:minute 0
:hour (8 20))
:init '(2020 1 1 12 59 59)
:range (* 3 86400) ; search for 3 days
))
'(@2020-01-01T20:00:00.000000+08:00
@2020-01-02T08:00:00.000000+08:00
@2020-01-02T20:00:00.000000+08:00
@2020-01-03T08:00:00.000000+08:00
@2020-01-03T20:00:00.000000+08:00
@2020-01-04T08:00:00.000000+08:00)))
We support very general time-specs (e.g. any function). For
details, please refer to doc/time-spec.org
. More examples for
#'schedule!
can be found in doc/examples.org
.
The system includes two background threads: the scheduler and the
dispatcher. The scheduler periodically wakes up and schedules
each task in the *schedules*
list to the *actions*
hash table.
This hash table uses universal time as keys and stores lists of
schedules as values. Meanwhile, the dispatcher wakes up every
second to check the current universal time and invoke the
function associated with each enabled schedule stored in the
corresponding list.
By default, any conditions are automatically passed and relevant
information is printed to *standard-output*
. However, the
behavior of the system can be modified by adjusting the
definition of the #'wrap-with-simple-condition-handler
function.
- Q: How can I contribute?
- A: To make a contribution, please refer to the documentation at
doc/todo.org
. - Q: What happens if a schedule is missed, such as when the operating system is in sleep mode during a scheduled task?
- A: The
cl-schedule
library does not have built-in support for re-running missed schedules or checking the schedule’s status. However, it should be possible to achieve this functionality by implementing functions that remember relevant information. - Q: Is it possible to view the schedule’s history?
- A: We are currently working on adding this feature. Soon, users
will be able to view a list of past schedule calls made by
cl-schedule
. - Q: What is the relationship between v1 and v2?
- A: Version 2 of
cl-schedule
is a complete rewrite of version 1. Unlike v1, which relied onigorpikman/clon
, v2 is independent of any external dependencies. Additionally, v2 uses more functions than macros, making it more transparent and easier to inspect. V2 also provides a flexible sub-language for specifying times (time-spec), which enables users to programmatically define schedules with greater precision.