1 ## snooze: run a command at a particular time
3 `snooze` is a new tool for waiting until a particular time and then
4 running a command. Together with a service supervision system such as
5 runit, this can be used to replace cron(8).
7 `snooze` has been tested on Linux 4.2.
8 It will likely work on other Unix-like systems with C99.
14 - no overlapping job runs possible
15 - filtering by ISO week and day of year
16 - due to supervision, no centralized daemon required
17 - due to supervision, can easily disable jobs or force their
19 - due to supervision, have custom logs
20 - due to no centralized daemon, no fuzzing with multiple users/permissions
21 - very robust with respect to external time changes
22 - can use a file timestamp to ensure minimum waiting time between two
23 runs, even across reboots
24 - randomized delays (some cron have that)
25 - variable slack (no need for anacron)
26 - ad-hoc usage possible, just run the program from command line
29 - less confusing usage (I hope)
30 - filtering by ISO week and day of year
34 - due to supervision, no centralized daemon required
35 - filtering by ISO week and day of year
39 - less complexity for jobs, no need for a `<job>.timer` file distinct
40 from the `<job>.service` file,
41 - can use a file timestamp to ensure minimum waiting time between two
42 runs, even across reboots
43 - very robust with respect to external time changes
46 - ad-hoc usage possible, just run the program from command line
50 * run five minutes after midnight, every day:
53 * run at 2:15pm on the first of every month:
55 snooze: `-d1 -H14 -M15`
56 * run at 10 pm on weekdays:
59 * run 23 minutes after midnight, 2am, 4am ..., everyday:
60 cron: `23 0-23/2 * * *`
62 * run every second week:
69 snooze [-nv] [-t timefile] [-T timewait] [-R randdelay] [-s slack] [-d mday] [-m mon] [-w wday] [-D yday] [-W yweek] [-H hour] [-M min] [-S sec] COMMAND...
71 * `-n`: dry-run, print the next 5 times the command would run.
72 * `-v`: verbose, print scheduled (and rescheduled) times.
73 * `-t`, `-T`: see below timefiles
74 * `-R`: add between 0 and RANDDELAY seconds to the start of the scheduled time.
75 * `-J`: add between 0 and JITTER seconds to scheduled execution time.
76 * `-s`: commands are executed even if they are SLACK (default: 60) seconds late.
78 The durations RANDDELAY and JITTER and SLACK and TIMEWAIT are parsed as seconds,
79 unless a postfix of `m` for minutes, `h` for hours, or `d` for days is used.
81 The remaining arguments are patterns for the time fields:
85 * `-w`: weekday (0-7, sunday is 0 and 7)
87 * `-W`: ISO week of year (0..53)
92 The following syntax is used for these options:
94 * exact match: `-d 3`, run on the 3rd
95 * alternation: `-d 3,10,27`, run on 3rd, 10th, 27th
96 * range: `-d 1-5`, run on 1st, 2nd, 3rd, 4th, 5th
97 * star: `-d '*'`, run every day
98 * repetition: `-d /5`, run on 5th, 10th, 15th, 20th, 25th, 30th day
99 * shifted repetition: `-d 2/5`, run on 7th, 12th, 17th, 22nd, 27th day
101 and combinations of those, e.g. `-d 1-10,15/5,28`.
103 The defaults are `-d* -m* -w* -D* -W* -H0 -M0 -S0`, that is, every midnight.
105 Note that *all* patterns need to match (contrary to cron where either
106 day of month *or* day of week matches), so `-w5 -d13` only runs on
111 Optionally, you can keep track of runs in time files, using `-t` and
114 When `-T` is passed, execution will not start earlier than the mtime
115 of TIMEFILE plus TIMEWAIT seconds.
117 When `-T` is *not* passed, snooze will start finding the first matching time
118 starting from the mtime of TIMEFILE, and taking SLACK into account.
119 (E.g. `-H0 -s 1d -t timefile` will start an instant
120 execution when timefile has not been touched today, whereas without `-t`
121 this would always wait until next midnight.)
123 If TIMEFILE does not exist, it will be assumed outdated enough to
124 ensure earliest execution.
126 snooze does not update the timefiles, your job needs to do that!
127 Only mtime is looked at, so touch(1) is good.
131 * snooze parses the option flags and computes the first time the
132 date pattern matches, as a symbolic date
133 * if a timefile is specified, the time is upped to timefile + timewait seconds
134 * if a random delay is requested, it is added
135 * snooze computes how far this event is in the future
136 * snooze sleeps that long, but at most 5 minutes
137 * after waking, snooze recomputes how far the event is in the future
138 * if the event is in the past, but fewer than SLACK seconds, snooze
139 execs the command. You need to ensure (by setting up supervision)
140 snooze runs again after that!
141 * if we woke due to a SIGALRM, the command is executed immediately as well
142 * if we notice time moved backwards, recompute the time until the event
143 * if the event is in the future, recompute the time it takes, possibly
144 considering shifting of the system time or timezone changes
145 (timezone reload only tested on glibc)
146 * If no command was given, just return with status 0
151 Run a job like cron, every day at 7am and 7pm:
153 exec snooze -H7,19 rdumpfs / /data/dump/mybox 2>&1
155 Run a job daily, never twice a day:
157 exec snooze -H0 -s 1d -t timefile \
158 sh -c 'run-parts /etc/cron.daily; touch timefile'
160 Use snooze inline, run a mirror script every hour at 30 minutes past,
161 but ensure there are at least 20 minutes in between.
164 snooze -H'*' -M30 -t timefile -T 20m
165 touch timefile # remove this if instantly retrying on failure were ok
169 Use snooze inline, cron-style mail:
173 actualjob >output 2>&1 ||
174 mail -s "$(hostname): snooze job failed with status $?" root <output
176 Snooze for rate-limiting a general purpose runit service: don't
177 restart faster than every two minutes. (Note that after a crash with a
178 daemon runtime of more than two minutes, it will be restarted
182 snooze -H'*' -M'*' -S'*' -t timefile -T 2m
188 Use `make all` to build, `make install` to install relative to `PREFIX`
189 (`/usr/local` by default). The `DESTDIR` convention is respected.
190 You can also just copy the binary into your `PATH`.
194 snooze is in the public domain.
196 To the extent possible under law, Leah Neukirchen <leah@vuxu.org>
197 has waived all copyright and related or neighboring rights to this work.
199 http://creativecommons.org/publicdomain/zero/1.0/