I have several jobs that require running at least once a day. What I do is start the scripts for these jobs every hour (or more often) and the scripts themselve check if they have already run by checking a status file on disc.
If the status file exists and is up-to-date then the script exits.
If that file is to old (i.e. last written the day before) or doesn't exists the script does run and on successful termination writes the status file.
If you cannot build this functionality into an existing program, it is simple to make wrapper script that checks if the program must run, calls the program if necessary, and on success (exit value, parsed output) writes the status file.
/usr/local/bin/catchup.simple:
#! /usr/bin/env python """ first parameter is a path to a file /..../daily/some_name That is a status/script file and the /daily/ indicates it needs to run at least once a day (after reboot, after midnight). The rest of the parameters is the command executed and its parameters. If there are no more parameters beyond the first the actual status file is /..../daily/some_name.status and is expected to be updated by calling the /....daily/some_name script (which has to be executable). That script doesn't need to know about the frequency and gets called with the status file as first (and only) argument. Valid directory names and their functioning: /daily/ run once a day (UTC) /hourly/ run once an hour The actual scheduling and frequency to check if running is necessary, is done using a crontab entry: CU=/usr/local/bin/catchup.simple CUD=/root/catchup # month, hour, day_of_month, month day_of_week command */5 * * * * $CU $CUD/daily/getlogs curl .... If mulitple days (or hours) have gone by, no runs are made for skipped days. If subprocess.check_output() fails the status file is not updated. """ import sys import datetime import subprocess verbose = False # set to True to debug def main(): if len(sys.argv) < 2: print 'not enough parameters for', sys.argv[0] return if len(sys.argv) == 2: status_file_name = sys.argv[1] + '.status' cmd = [sys.argv[1]] else: status_file_name = sys.argv[1] cmd = sys.argv[2:] freq = sys.argv[1].rsplit('/', 2)[-2] if verbose: print 'cmd', cmd print 'status', status_file_name print 'frequency', freq try: last_status = datetime.datetime.strptime( open(status_file_name).read().split('.')[0], "%Y-%m-%dT%H:%M:%S", ) except (IOError, ValueError): last_status = datetime.datetime(2000, 1, 1) now = datetime.datetime.utcnow().replace(microsecond=0) if verbose: print last_status print 'now', now.isoformat() if freq == 'daily': if last_status.date() < now.date(): subprocess.check_output(cmd) elif verbose: print 'already done today' elif freq == 'hourly': if last_status.date() < now.date() or \ last_status.date() == now.date() and \ last_status.hour < now.hour: subprocess.check_output(cmd) elif verbose: print 'already done this hour' with open(status_file_name, 'w') as fp: fp.write(now.isoformat()) if __name__ == "__main__": main()
asynchronouscron. Here's a list (easiest to hardest). I'm using the easiest one (cronie)/root/.jobstatus) and check that file the next time you run the script./root/.jobstatusyou'd have to check if time of modification|creation equal to scheduled time period or great.