6.2.901.900
Deferred: a simple library for doing things later
Link to this document with
@other-doc['(lib "deferred/deferred.scrbl")]
Link to this document with
@other-doc['(lib "deferred/deferred.scrbl")]
Deferred allows you to run things at a specified time or after a specified
elapsed time. It’s sort of like a less complete cron, usable from
within racket.
The central notion within deferred is that of the task queue: a central place
where tasks go to wait. (This is in fact a misnomer: it’s actually just a set,
and tasks handle their own scheduling independently of each other, but I found
it helpful to think about it in this way.) There’s a default queue that
requires no setup, but if you want a bunch of separate taskqueues, you can
achieve this with parameterization.
1 Adding a task to a taskqueue
Link to this section with
@secref["adding" #:doc '(lib "deferred/deferred.scrbl")]
Link to this section with
@secref["adding" #:doc '(lib "deferred/deferred.scrbl")]
In deferred, a "task" is just a zero-argument function to be run (which is
internally wrapped into its own thread. There are several ways to add a
function to a taskqueue, with various levels of convenience.
For running a function at a specified date, use defer:
Runs the provided function at a later date (defaulting to now). Providing a
date in the past will run the function immediately. Blocks until the task has
been added to the current taskqueue (which is the value of the
queue-manager parameter). If the taskqueue is no longer accepting
tasks, returns immediately.
For running a function after a specified interval, use after:
(after num kw body ...)
|
|
| kw | | : | | (one-of/c #:seconds #:minutes #:hours #:days) |
|
Run the specified body expressions after a given delay. Only one of the
timing keywords may be provided (this may change in the future). Uses
defer internally, so its specific behaviors apply here as well.
For convenience, there are shortcuts for running something at a specific hour
and minute today or tomorrow:
Run the specified body expressions at the given time today (or tomorrow). If
the time has already passed, runs the body expressions immediately. Uses
defer internally, so its specific behaviors apply here as well.
2 Interacting with task queues
Link to this section with
@secref["queue-interaction" #:doc '(lib "deferred/deferred.scrbl")]
Link to this section with
@secref["queue-interaction" #:doc '(lib "deferred/deferred.scrbl")]
Most of the time, it shouldn’t really be necessary to interact with the task
queues directly. Nonetheless, if you want to inspect the contents of a queue,
or override the default queueing behavior in defer, there are
functions to do so.
Add the specified thread to the tasks tracked by the taskqueue. (The thread
should already be running.)
Return #t if the enqueue message was sent successfully, #f
otherwise.
Remove the specified thread from the tasks tracked by the taskqueue.
Return nothing if the dequeue message was sent successfully, #f if the
queue is not running. Fails silently if the thread is not in the queue.
displayln each of the items in the current queue. (Each item is a
thread.)
Apply the provided function to the set of threads in the current queue for
side-effects.
Apply the provided function to the set of threads in the current queue.
Immediately return a promise that when forced gives the return value of the
function.
3 Shutting down a queue
Link to this section with
@secref["queue-shutdown" #:doc '(lib "deferred/deferred.scrbl")]
Link to this section with
@secref["queue-shutdown" #:doc '(lib "deferred/deferred.scrbl")]
When you’re done with a queue, you can shut it down to remove any pending
tasks, and prevent enqueueing any additional ones.
Waits for all tasks in the current queue at the time of the call to finish,
then returns. Does not prevent additional tasks from being added while
waiting.
Purges the current queue, immediately killing all tasks that haven’t yet
marked themselves as running. (There’s no guard against race conditions. Don’t
assume that all tasks that were killed did not run.)
Returns nothing if the purge message was successfully sent or #f if
the queue is not running.
Shuts down the current queue, immediately killing all tasks and preventing the
queue from accepting any new ones. As for
purge-queue, there’s no
guarantee about what has and has not yet run.
Returns nothing if the shutdown message was successfully sent or #f if
the queue is not running.
4 Making your own task queues
Link to this section with
@secref["custom-queues" #:doc '(lib "deferred/deferred.scrbl")]
Link to this section with
@secref["custom-queues" #:doc '(lib "deferred/deferred.scrbl")]
If you need multiple separate queues, or your own custom queues, you can accomplish this by parameterizing queue-manager:
The current task queue used for all other operations. Basic add/remove
operations are accomplished by sending message '(add item) and
'(remove item). For inspecting the queue and applying a function the
message '(inspect callback-fn) is used. For purging and shutting
down, the messages 'purge and 'shutdown are used. Custom
queue implementations should somehow handle (or ignore) these messages.
A basic queue manager loop, repsonding to 'add, 'remove,
'inspect, 'purge, and 'shutdown. Tracks enqueued
items with an immutable set. This particular function is agnostic about what
the enqueued items are, though the purge function used for purging/shutting
down will assume they are threads.
5 Utility functions
Link to this section with
@secref["util" #:doc '(lib "deferred/deferred.scrbl")]
Link to this section with
@secref["util" #:doc '(lib "deferred/deferred.scrbl")]
Get a date corresponding to the suppled offset in seconds, minutes, hours, and
days from now.