aboutsummaryrefslogtreecommitdiffstats

crore

crore is a lightweight cron daemon written in less than 1400 lines of pure Hare. It started as a fun way for me to learn Hare and has become my primary cron daemon on Linux.

Design Priorities

crore is designed to be:

  • Run without a filesystem
  • Fast
  • As light on system resources as possible

In that order.

crore is single-threaded, stays off the heap as much as it can, only reads the filesystem at init to load the crontab (and even this is optional) and then never again touches the disk. It only keeps enough in memory to know what and when to execute, and it only ever has one child process executing at a time. Its method of resolving the next execution time of a task avoids exhaustively iterating through upcoming datetimes (except in some edge cases regarding weekday resolution, for now) in an effort to reduce the load required when tasks are rescheduled.

On performance, it benefits from being written entirely with the Hare standard library. At the moment, regexes are not used, but that may change in the future depending on performance relative to the current technique of splitting strings in various ways to parse expressions.

Of course, if a spawned process is intensive on system resources, crore is unable to address that.

Current Features

  • Validates every cron expression at init and shows you next trigger time
  • Tells you at init how long it'll be sleeping until the next scheduled job
  • Sleeps until the next job must run and does not wake every minute
  • Logs in a sensible, observable way about what it's doing
  • Clear, intuitive way to set environment variables and optional verification they have been understood
  • Supports all major cron syntax features (e.g. ranges, steps, wildcards)
  • All functionality is available via command line arguments, so filesystem access is optional; alternatively, all functionality can be configured from a config file if you prefer

crore also supports hooks, which are commands automatically run before and/or after each cronjob executes. Using hooks, highly customized cron setups are possible.

Differences From Other Cron Implementations

  • Executes jobs in one thread, sequentially, to minimize its footprint
  • All times are in UTC all the time
  • It functions from an in-memory copy of its crontab that it holds from when it inits. It doesn't check again. This is deliberate to minimize interaction with the filesystem.
  • It looks in the current user's home directory ($HOME/.config/crore/tab) for its crontab by default. You can make it look anywhere, though, or just feed it expressions from the command line.

For those who want a more standard cron experience, there is a commented conf.trad.example example config in the repo.

Build

You'll need Hare installed.

make sudo make install

Note: If you use my Makefile, this installs to /usr/bin by default so the default runit configuration can see it. Adjust PREFIX if you don't want that.

You'll need to daemonize this yourself, however you prefer. On Void Linux I use a simple runit config which is in the repo. If you use an applicable runit setup with an /etc/sv directory, you can run make install-runit to put that in place for you.

There is also a default OpenRC configuration for use with applicable systems.

See crore(1).

Benchmarking

This section is as of v0.1.2.

By my own tests conducted via valgrind(1), on my x86_64 Linux computer on 13 Dec 2023, crore wants about 9.5 KiB plus ~0.5 KiB per expression, depending on the length of the commands in each expression. At init, it allocates about three times that on the heap before freeing it. Rescheduling a cronjob after it executes causes a ~3KiB alloc which is then freed almost immediately. As expected, the volume of cronjobs doesn't make that worse because the rescheduling is done sequentially.

The steady-state footprint is therefore a max of, conservatively, 13 KiB plus <1KiB per expression. Pretty nice!

For reference, this is about a 10x bigger footprint than cronie, but that's the price we have to pay to run from memory. It's still vanishingly small! (The price is also paid because of being able to report the next execution time of things; without that, there'd be no reason to do anything but wake every minute and execute whatever was applicable. There's certainly a performance trade-off there, but I think it's worth it.)

Contributing

I welcome patches or direct emails. Check out my lists or profile here on sourcehut.