]> git.netwichtig.de Git - user/henk/code/snooze.git/blob - README.md
Adds "over systemd timers" section to README
[user/henk/code/snooze.git] / README.md
1 ## snooze: run a command at a particular time
2
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).
6
7 `snooze` has been tested on Linux 4.2.
8 It will likely work on other Unix-like systems with C99.
9
10 ## Benefits
11
12 Over cron:
13 - mnemonic syntax
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
18   execution instantly
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
27
28 Over runwhen:
29 - less confusing usage (I hope)
30 - filtering by ISO week and day of year
31 - zero dependencies
32
33 Over uschedule:
34 - due to supervision, no centralized daemon required
35 - filtering by ISO week and day of year
36
37 Over systemd timers:
38 - mnemonic syntax
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
44 - randomized delays
45 - variable slack
46 - ad-hoc usage possible, just run the program from command line
47
48 ## Rosetta stone
49
50 * run five minutes after midnight, every day:
51   cron: `5 0 * * *`
52   snooze: `-M5`
53 * run at 2:15pm on the first of every month:
54   cron: `15 14 1 * *`
55   snooze: `-d1 -H2 -M15`
56 * run at 10 pm on weekdays:
57   cron: `0 22 * * 1-5`
58   snooze: `-w1-5 -H22`
59 * run 23 minutes after midnight, 2am, 4am ..., everyday:
60   cron: `23 0-23/2 * * *`
61   snooze: `-H/2 -M23`
62 * run every second week:
63   snooze: `-W/2`
64 * run every 10 days:
65   snooze: `-D/10`
66
67 ## Usage:
68
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...
70
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 scheduled time.
75 * `-s`: commands are executed even if they are SLACK (default: 60) seconds late.
76
77 The durations RANDDELAY and SLACK and TIMEWAIT are parsed as seconds,
78 unless a postfix of `m` for minutes, `h` for hours, or `d` for days is used.
79
80 The remaining arguments are patterns for the time fields:
81
82 * `-d`: day of month
83 * `-m`: month
84 * `-w`: weekday (0-7, sunday is 0 and 7)
85 * `-D`: day of year
86 * `-W`: ISO week of year (0..53)
87 * `-H`: hour
88 * `-M`: minute
89 * `-S`: second
90
91 The following syntax is used for these options:
92
93 * exact match: `-d 3`, run on the 3rd
94 * alternation: `-d 3,10,27`, run on 3rd, 10th, 27th
95 * range: `-d 1-5`, run on 1st, 2nd, 3rd, 4th, 5th
96 * star: `-d '*'`, run every day
97 * repetition: `-d /5`, run on 5th, 10th, 15th, 20th, 25th, 30th day
98 * shifted repetition: `-d 2/5`, run on 7th, 12th, 17th, 22nd, 27th day
99
100 and combinations of those, e.g. `-d 1-10,15/5,28`.
101
102 The defaults are `-d* -m* -w* -D* -W* -H0 -M0 -S0`, that is, every midnight.
103
104 Note that *all* patterns need to match (contrary to cron where either
105 day of month *or* day of week matches), so `-w5 -d13` only runs on
106 Friday the 13th.
107
108 ## Timefiles
109
110 Optionally, you can keep track of runs in time files, using `-t` and
111 optionally `-T`.
112
113 When `-T` is passed, execution will not start earlier than the mtime
114 of TIMEFILE plus TIMEWAIT seconds.
115
116 When `-T` is *not* passed, snooze will start finding the first matching time
117 starting from the mtime of TIMEFILE, and taking SLACK into account.
118 (E.g. `-H0 -s 1d -t timefile` will start an instant
119 execution when timefile has not been touched today, whereas without `-t`
120 this would always wait until next midnight.)
121
122 If TIMEFILE does not exist, it will be assumed outdated enough to
123 ensure earliest execution.
124
125 snooze does not update the timefiles, your job needs to do that!
126 Only mtime is looked at, so touch(1) is good.
127
128 ## Exact behavior
129
130 * snooze parses the option flags and computes the first time the
131   date pattern matches, as a symbolic date
132 * if a timefile is specified, the time is upped to timefile + timewait seconds
133 * if a random delay is requested, it is added
134 * snooze computes how far this event is in the future
135 * snooze sleeps that long, but at most 5 minutes
136 * after waking, snooze recomputes how far the event is in the future
137 * if the event is in the past, but fewer than SLACK seconds, snooze
138   execs the command.  You need to ensure (by setting up supervision)
139   snooze runs again after that!
140 * if we woke due to a SIGALRM, the command is executed immediately as well
141 * if we notice time moved backwards, recompute the time until the event
142 * if the event is in the future, recompute the time it takes, possibly
143   considering shifting of the system time or timezone changes
144   (timezone reload only tested on glibc)
145 * If no command was given, just return with status 0
146 * and so on...
147
148 ## Common usages
149
150 Run a job like cron, every day at 7am and 7pm:
151
152         exec snooze -H7,19 rdumpfs / /data/dump/mybox 2>&1
153
154 Run a job daily, never twice a day:
155
156         exec snooze -H0 -s 1d -t timefile \
157                 sh -c 'run-parts /etc/cron.daily; touch timefile'
158
159 Use snooze inline, run a mirror script every hour at 30 minutes past,
160 but ensure there are at least 20 minutes in between.
161
162         set -e
163         snooze -H'*' -M30 -t timefile -T 20m
164         touch timefile  # remove this if instantly retrying on failure were ok
165         mirrorallthethings
166         touch timefile
167
168 Use snooze inline, cron-style mail:
169
170         set -e
171         snooze ...
172         actualjob >output 2>&1 ||
173                 mail -s "$(hostname): snooze job failed with status $?" root <output
174
175 Snooze for rate-limiting a general purpose runit service: don't
176 restart faster than every two minutes. (Note that after a crash with a
177 daemon runtime of more than two minutes, it will be restarted
178 immediately):
179
180         set -e
181         snooze -H'*' -M'*' -S'*' -t timefile -T 2m
182         touch timefile
183         exec mydaemond
184
185 ## Installation
186
187 Use `make all` to build, `make install` to install relative to `PREFIX`
188 (`/usr/local` by default).  The `DESTDIR` convention is respected.
189 You can also just copy the binary into your `PATH`.
190
191 ## Copyright
192
193 snooze is in the public domain.
194
195 To the extent possible under law, Leah Neukirchen <leah@vuxu.org>
196 has waived all copyright and related or neighboring rights to this work.
197
198 http://creativecommons.org/publicdomain/zero/1.0/