Ross Wolin - last updated 2016.07.12
I have some cron jobs on a Raspberry Pi running Raspbian I'd like to run each evening at 11pm with a random start delay of up to 2hrs. Some distros' crons have support for a RANDOM_DELAY variable in the crontab file; however the man page for Raspbian Jessie doesn't mention it, and a quick test showed setting RANDOM_DELAY in crontab did nothing.
When I Google'd this problem, I also found answers that involved using the $RANDOM variable with the sleep command. Unfortunately, $RANDOM is a Bash specific feature, and as the follow-up comments pointed out since cron jobs run in the Bource (sh) shell, $RANDOM is not set, so this solution doesn't work.
My quick and dirty solution was to write a Python script with accepts a time delay maximum, then generates the string 'sleep' followed by a random delay in seconds up to the specified maximum. The output from this command is prepended to the cron job entry using shell command substitution, with something like:
`~/bin/rndsleep.py 15m` && ~/bin/scrape.py
where the `` indicates to run the script output as a command via command substitution
The script takes one parameter, the maximum delay in seconds, minutes, or hours:
rowol@tesla$ ./rndsleep.py --help
usage: rndsleep.py [-h] max_delay
Generate sleep command of a random duration up to max_delay
positional arguments:
max_delay maxiumum time in N seconds (Ns or N), minutes (Nm), or hours (Nh) to sleep
optional arguments:
-h, --help show this help message and exit
The script converts the delay to seconds and generates a random number between 0 and the maximum for the duration, and outputs the corresponding sleep command to STDOUT. You may ask "why not just do the sleep in the Python script?" My thought was that piping the command back to the shell via command substitution allows the Python interpreter to exit, so it's not taking up memory during the sleep.
#! /usr/bin/python
#
# Generates command for a random sleep, given a max delay in seconds, minutes, or hours
# Useful for cron, as RANDOM_DELAY doesn't work on Raspian,
# and $RANDOM is a Bash shell thing (cron uses Bourne/sh shell)
#
# Install with 'crontab -e' to run every day at 11pm with 2 hour random start delay,
# with a command like:
# 0 23 * * * `~/bin/rndsleep.py 2h` && ~/bin/scrape.py
#
import argparse, random, re, sys
def main():
random.seed()
p = argparse.ArgumentParser(description='Generate sleep command for random amount of time')
p.add_argument("time", help="time in N seconds (Ns or N), minutes (Nm), or hours (Nh)");
args = p.parse_args()
# Parse lowercase time arg against N, Ns, Nm, and Nh
args.time = args.time.lower()
m = re.match("(\d+)(s?|m|h)$", args.time)
if not m:
sys.stderr.write("ERR - Unable to parse the time parameter (%s)\n"), % args.time)
sys.exit(-1)
# Grab the delay, and if it's hours or minutes, convert to seconds
maxDelay = int(m.group(1))
if m.group(2)=="m":
maxDelay *= 60
elif m.group(2)=="h":
maxDelay *= 60*60
# This goes between the ``
print "sleep %d" % random.randint(0, maxDelay),
sys.exit()
if __name__ == "__main__":
main()
Send comments, questions, money in large denominations, etc to eng at mysticengineering.com
If you enjoyed this article, please consider buying my products ...
ATX PS Adapter
Use an ATX PC power supply as a 5V, 3.3V, and +12V/-12V bench supply the easy way, without cutting the case or mounting external connectors, resistors, LEDs, switches, and fuses. Provides visual indication when supply is plugged in and turned on, also fuses the power voltage outputs for safety. Run USB powered development boards via the USB connectors on the 5V line. |
Ultimate Serial Port (Debug Buddy)
USB serial port with standard, 5V and 3V RS232, plus integrated null modem and gender changer. Implements TX/RX and RTS#/CTS# for optional hardware handshake. Also includes 3.3V<->5V level shifters, debug LEDs, and 13 clock sources. Valuable tool for hands on problem solving and hacking |