Giter Site home page Giter Site logo

runcron's Introduction

runcron - simple, safe, container-friendly cron alternative

SYNOPSIS

runcron [options] crontab expression command arg ...

DESCRIPTION

runcron is a minimal cron running as part of a process supervision tree for automated environments. runcron is intended to be simple, safe and container-friendly.

runcron runs under a supervisor like daemontools and exits after task completion. The supervisor restarts runcron, taking any action based on the task exit status:

svscan,17276,17276 service/
  |-supervise,17277,17276 date17
  |   `-runcron,17308,17276 */17 * * * * * sh -c echo 17: $(date)
  |-supervise,17279,17276 date33
  |   `-runcron,17303,17276 */33 * * * * * sh -c echo 33: $(date)
  `-supervise,17280,17276 sleep
      `-runcron,17282,17276 @reboot sleep inf
          `-sleep,17288,17288 inf

runcron supervises tasks:

  • only allows a single instance of a job to run

  • job runtime is limited to the next cron interval

  • when the task is complete, exits with value set to the task exit status

  • periodically retries the job if it exits non-0

  • if the tasks succeeds (exits 0), when restarted, sleeps until the next cron interval

  • terminates any background subprocesses when the foreground process exits

  • attempts to prevent running unkillable (setuid) subprocesses

  • standard input is forwarded to the task

cron expressions are parsed using ccronexpr.

The standard crontab(5) expressions (and some additional expressions) are supported. The seconds field is optional:

			field          allowed values
			-----          --------------
			second         0-59 (optional)
			minute         0-59
			hour           0-23
			day of month   1-31
			month          1-12 (or names, see below)
			day of week    0-7 (0 or 7 is Sun, or use names)

crontab(5) aliases pseudorandomly assign a run time from the alias interval. To run exactly at the start of the interval, use the "=" alias variant:

			string         meaning
			------         -------
			@reboot        Run once, at startup (see below).
			@yearly        Run once a year, "0~59 0~59 0~23 1~28 1~12 *".
			@annually      (same as @yearly)
			@monthly       Run once a month, "0~59 0~59 0~23 1~28 * *".
			@weekly        Run once a week, "0~59 0~59 0~23 * * 1~7".
			@daily         Run once a day, "0~59 0~59 0~23 * * *".
			@midnight      (same as =daily)
			@hourly        Run once an hour, "0~59 0~59 * * * *".

			=reboot        (same as @reboot)
			=yearly        Run once a year, "0 0 1 1 *".
			=annually      (same as =yearly)
			=monthly       Run once a month, "0 0 1 * *".
			=weekly        Run once a week, "0 0 * * 0".
			=daily         Run once a day, "0 0 * * *".
			=midnight      (same as =daily)
			=hourly        Run once an hour, "0 * * * *".

Handling stdin

Standard input is forwarded to the subprocess:

$ echo test | runcron '0~59 * * * * *' sed 's/e/3/g'
t3st

crontab Expressions

Randomized Intervals

runcron supports random values in intervals inspired by OpenBSD crontab.

The ~ character in an interval field will pseudorandomly choose an offset:

# run once, from Monday to Friday, between 12am and 8am
0 0~8 * * 1~5

The random offset is predictable, using the system hostname as the seed by default. Use the -t option to change the seed or set it to an empty string ("") to use the current time as the seed.

# runs: Tuesday at 7am
runcron -t "www1.example.com" -vvv -p -n '0 0~8 * * 1~5' echo test

# runs: Friday at 5am
runcron -t "www2.example.com" -vvv -p -n '0 0~8 * * 1~5' echo test

@reboot

The @reboot alias runs the task immediately. The behaviour of subsequent attempts to run the task depends on the exit status of the previous run:

  • 0: runcron will not run the task and sleep indefinitely
  • non-0: runcron will rerun the task after --retry-interval seconds (default: 3600)

Since the runcron state is written to a file (see -f option), the state can persist between reboots.

umask 077
mkdir -p /tmp/reboot
runcron -f /tmp/reboot/runcron.lock ...

EXAMPLES

    # Attempt to connect to google daily
    # If the connection fails, the task will be retried hourly.
    runcron "43 7 * * *" nc -z google.com 80

    # Run at 9:03am on the 20th of each month.
    # After the first run, the job will be terminated before the
    # next scheduled run.
    runcron "3 9 20 * *" sleep inf

    # schedule a task randomly between nodes from Monday-Sunday
    # each node will choose the same offset based on the hostname
    runcron "11 * * * 1~7" echo test

    # specify a string to use as a seed
    runcron -t "foo.example.com" "11 * * * 1~7" echo test

    # or non-deterministically based on the time
    #
    # Since the next run interval will be randomly chosen, manually
    # set a timeout
    runcron -t "" -T 3600 "11 * * * 1~7" echo test

daemontools run script

    #!/bin/sh

    # Run daily at 8:15am
    exec runcron "15 8 * * *" echo Running job

OPTIONS

-f, --file : lock file path (default: .runcron.lock)

-C, --chdir : change working directory before running command

-T, --timeout : specify command timeout in seconds (-1 to disable, default: next cron interval)

-R, --retry-interval : interval to retry failed commands (default: 3600s)

-n, --dryrun : do nothing

-p, --print : output seconds to next timespec

-s, --signal : signal sent on command timeout

The signal is also sent on job completion to clean up any background tasks (use --disable-signal-on-exit to disable).

Default: 15 (SIGTERM)

-t, --tag : Seed used for for generating a pseudorandom offset for cron expressions with random intervals. The offset used in a job is constant between runs.

Setting the tag to an empty string ("") will cause the offset to be pseudorandomly chosen based on the current time. The job timeout will also be random.

Default: hostname (see RUNCRON_TAG)

-v, --verbose : verbose mode

--timestamp YY-MM-DD hh-mm-ss|@epoch : provide an initial time

--limit-cpu : restrict cpu usage of cron expression parsing (default: 10 seconds)

--limit-as : restrict memory (address space) of cron expression parsing (default: 1 Mb)

--allow-setuid-subprocess : allow running potentially unkillable subprocesses

--disable-process-restrictions : do not fork cron expression processing

--disable-signal-on-exit : By default, any background subprocesses are terminated when the foreground process is terminated. Use this option to disable signalling background jobs on exit.

SIGNALS

Waiting for Job

While the task is waiting to run, signals sent to runcron are ignored except for:

SIGUSR1/SIGALRM : Run the job immediately

SIGUSR2 : Print the remaining number of seconds to stderr

SIGINT : Exit with status 111

SIGTERM : Exit with status 111

Running Job

When the task is running, signals (excluding SIGKILL, SIGALRM, SIGUSR1 and SIGUSR2) received by runcron are forwarded to the task process group.

ENVIRONMENT VARIABLES

RUNCRON_TAG : Sets the default value for the -t/--tag option: if unset, the hostname is used

Read-only

runcron sets these values before executing the subprocess:

RUNCRON_EXITSTATUS : Task exit status of previous run

RUNCRON_TIMEOUT : Number of seconds before task is terminated

BUILDING

Quick Install

make

# to run tests: requires bats(1)
make clean all test

# selecting method for restricting cron expression parsing
RESTRICT_PROCESS=seccomp make

#### using musl
# sudo apt install musl-dev musl-tools

RESTRICT_PROCESS=rlimit ./musl-make clean all test

## linux seccomp sandbox: requires kernel headers

# clone the kernel headers somewhere
cd /path/to/dir
git clone https://github.com/sabotage-linux/kernel-headers.git

# then compile
MUSL_INCLUDE=/path/to/dir ./musl-make clean all test

ALTERNATIVES

SEE ALSO

crontab(5)

runcron's People

Contributors

msantos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

binrick

runcron's Issues

runcron exited after first success task run

this is not work as expected like crond:

the job should runs at every minute, not once and exted

❯ ./runcron  -v '*/1 * * * *' bash -c 'echo $(date)'
now[1585568711]=Mon Mar 30 19:45:11 2020
next[1585568760]=Mon Mar 30 19:46:00 2020
now[1585568760]=Mon Mar 30 19:46:00 2020
next[1585568820]=Mon Mar 30 19:47:00 2020
last exit status was 0, sleep interval is 49s, command timeout is 60s
running command: timeout is set to 60s
Mon 30 Mar 2020 07:46:00 PM CST
# now runcron exited 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.