top | item 37879027

Fcron Is the Best Cron

100 points| networked | 2 years ago |dbohdan.com | reply

62 comments

order
[+] tremon|2 years ago|reply
For my own use cases, I've found that traditional cron timing specs don't match what I need from scheduled operations. I mainly care about two things: time window and periodicity -- and while it's possible to express both in the same cron timestamp, it's both too specific and not specific enough. I don't see this post making a clear argument about their functional requirements, just that fcron satisfies more technical requirements than Vixie cron.

But going in full "I want a pony"-mode: over the years, I've needed the following features from a job scheduling system:

  1) time window (e.g. only run between 1am and 3am on weekdays)
  2) periodicity (if job was successful, next run is X time away)
  3) retry period (if job failed, retry after X time)
  4) job timeout (if job is still running after X time, kill it)
  5) start randomization (randomize start up to X time in window)
  6) job dependencies (don't run job Y until job Z has finished successfully)
  7) job anti-dependencies (don't run job Y while job Z is active)
FAFAIK, Vixie cron only allows 1 and 2; 4 can be done with coreutils' timeout (don't know if it's a POSIX command or only GNU), and 5 can be done with something like sleep $RANDOM, but the time spent waiting is added to the job's runtime -- which means that you no longer can create useful reports about job processing times. Of this list, fcron only adds nicer syntax, and 5 is built-in. It can kinda do 7, but serial is a global exclusion. If it were possible to make exclusion groups (e.g. job Y and Z have serial(1), job X has serial(2), and user's fcrontab has serial($UID)), that would be much nicer.

I acknowledge that Cron was never meant to solve 6 and 7, but it's still a feature that I require regularly in my systems. But I don't understand why 3 (explicit retries) was never implemented in any cron replacement, even systemd timers don't have it, at least I'm not aware of it (RestartSec is for services only).

[+] 9dev|2 years ago|reply
Sounds like systemd timers tick many of your boxes, maybe not all, but that’s the system I’d be most optimistic for to a as actually implement these…
[+] tannhaeuser|2 years ago|reply
5 is an odd requirement potentially better implemented outside cron, such as with a single line of shell code involving the "at" command (and "expr" to scale a /dev/random value).

4, 6, 7 gets you into "enterprise" (not the StarTrek thing;) territory. Think about it: how to represent that a job has or hasn't finished successfully? Using a process return status, or maybe something more persistent, restartable, or federated and independent of a PID eg. a state stored in a database, which involves further design trade offs such as transactional isolation, locking, eventual consistency, etc.

[+] maio|2 years ago|reply
Not a Cron but tools like Jenkins or TeamCity will probably handle most if not all of these requirements.
[+] simpaticoder|2 years ago|reply
Sounds like a local LLM, coupled with a periodic wake up signal, will be your pony. Presumably even a small one could run a schedule under those (very reasonable) constraints. Maybe not general pathological cases, but ordinary cases. You'd probably want things to run in one big prompt over time and the tricky part would be finding the minimum size required to properly execute the schedule. Too small, and it loses knowledge of the past. Too large, and it won't function at all.

EDIT: I believe in sysadmin llms and think they will become common and obvious in the next few years. I will look back at the downvotes on this comment with great pride. So, thanks and keep them coming!

[+] karlicoss|2 years ago|reply
I was annoyed by cron/fcron limitations and figured systemd is the way go because of its flexibility and power, but also was annoyed about manually managing tons of unit files. So I wrote a tool with a config that looks kinda like a crontab, but uses systemd (or launchd on mac) behind the scenes: https://github.com/karlicoss/dron#what-does-it-do

E.g. a simplest job definition looks like this

  job(every(mins=10), 'ping https://beepb00p.xyz', unit_name='ping-beepb00p')
But also it's possible to add more properties, e.g. arbirary systemd properties, or custom notification backends (e.g. telegram message or desktop notification)

Since it's python, I can reuse variables, use for loops, import jobs from other files (e.g. if there are shared jobs between machines), and check if it's valid with mypy.

Been using this for years now, and very happy, one of the most useful tools I wrote.

It's a bit undocumented and messy but if you are interested in trying it out, just let me know, I'm happy to help :)

[+] dale_glass|2 years ago|reply
systemd requiring two files for timers is quite intentional.

A timer runs a unit. Which means that you can test any timer easily by just starting the unit itself whenever needed. With cron, to test things you need to fiddle with the configuration and schedule it to run in the next minute or two, wait, check the logs, adjust, rinse and repeat.

[+] tetha|2 years ago|reply
This is also pretty useful if you use parametrized unit files. For example, most of our long term archiving is implemented in a parametrized systemd unit `push-to-archive@`. So in order to backup a new dataset, you deploy the config for it, add a simple systemd timer triggering `push-to-archive@newdataset` and that's it. Simple and even readable in the systemd timer status.
[+] networked|2 years ago|reply
Fcron's approach is to provide a shell where you can examine, run, renice, and kill cron jobs: http://fcron.free.fr/doc/en/fcrondyn.1.html. (You can run a job either independently or instead of the next scheduled run.) I think this is competitive with what systemd provides by separating the service from the timer. (Edit: I mean in this area. As a sibling comment points out, the separation also enables parametrization.) An advantage that systemd has is that you can refer to a service by a meaningful name instead of a numeric job identifier.

What I would like to have in fcron is the ability to direct the job's output to the console when running a job immediately.

[+] c7DJTLrn|2 years ago|reply
The complaints about systemd timers seem strange. To me, they're a sysadmin's dream to work with. I can see exactly when the last trigger was, when the next one will be, and I can test that the unit will work properly when it fires. And I don't have to remember cron syntax.

As for them not supporting email, if you really need to you can add an OnFailure= to the service unit to send one.

[+] e12e|2 years ago|reply
> A timer runs a unit. Which means that you can test any timer easily by just starting the unit itself whenever needed. With cron, to test things you need to fiddle with the configuration and schedule it to run in the next minute or two, wait, check the logs, adjust, rinse and repeat.

Not sure if I understand - a Cron "unit" is just a command that runs in a clean environment - you can test that without Cron.

SystemD require a "unit" wrapper around your command line - and is tricky to test without systemD? (No copy paste of the command and arguments - you would have to manually parse the ini file back into a command line).

[+] MatthiasPortzel|2 years ago|reply
I’m a systemd fan, but managing unit files is definitely a pain. The units and timers I’ve written get thrown in `/lib/systemd/system` (or `/etc/systemd/system/`, who knows) along with a ton of the OS’s unit files.
[+] twic|2 years ago|reply
systemd could just support the Timer section in unit files. You could then still start the unit file manually.
[+] e12e|2 years ago|reply
For use inside containers, a nice Cron is Superchronic:

https://github.com/aptible/supercronic

Beware! It explicitly does not run jobs in an empty environment - it's not a great candidate for system level Cron. But for its intended usecase it is very nice.

[+] ape4|2 years ago|reply
My favorite is

    /etc/cron.monthly/
    /etc/cron.daily/
    /etc/cron.hourly/
    /etc/cron.weekly/
Super simple to use - no remembering the order of numbers. Only one job runs at a time (so you don't need to pick times that don't overlap) Of course, it doesn't handle every case. I don't know if all Linux's have it.
[+] Denvercoder9|2 years ago|reply
> Only one job runs at a time

At least on Debian, this is not true. If your hourly cronjobs take longer than an hour, it'll happily start a second instance of them in parallel.

[+] eterps|2 years ago|reply
Too bad this isn't directly supported in ~/.config/ it would make it very easy in combination with GNU stow or another dotfiles manager.
[+] its-summertime|2 years ago|reply
My 2||3 "needs" from a cron:

Timezones (fcron has this!!)

Offsets (e.g. the day before the first friday of each month) (this can be implemented via multiple rules but I don't want that)

Programmable times (expands on the prior, would like to shell out to something else to get the next X times, so I can have any scheme I want for times!)

[+] CraigJPerry|2 years ago|reply
I mostly live in RHEL land so vixie cron was replaced around a decade ago and these days i use systemd, but, i think all of these can be achieved without changing your cron impl:

1. Timezones

    CRON_TZ=Europe/CEST
    0 10 * * * env TZ=America/New York echo “I run at 10am eastern”
    0 10 * * * echo “I run at 10am Central European”
2. Offsets

    0 10 * * 4 [[ date -d "tomorrow" +\%u -lt 8 ]] && echo “I run on the day before the first Friday”
This one is a bit gnarly for a few reasons:

The 4 in the cron spec means Thursday, 0 and 7 mean Sunday.

You can’t use the day of month and day of week fields here as you might (entirely reasonably!) expect. In cron, the other fields are AND together, but day of month and day of week are OR. There are 2 types of people in this world. Those who have been bitten by this and now have this rule tattooed on their brain and those who have yet to be bitten. There isn’t a 3rd type that just read the systemV spec docs… :-)

The % is escaped in the GNU date command because % means new line in cron. Ouch.

3. GNU date shenanigans has you covered here I think.

EDIT: nope, I just tested #1 and this idea doesn’t work. It doesn’t affect the run schedule, it would only impact the timezone of the echo commands here

[+] noduerme|2 years ago|reply
admittedly, cron emailing you by default every time it runs a job seems now like a ridiculous decision. But I take a certain pleasure in my morning ritual of fast scrolling through a hundred cron emails from different servers just in case there's an error.
[+] viraptor|2 years ago|reply
You can avoid it with `cronic`. It ignores the output of the command if the exit is successful. Only results in emails if there's a failure.
[+] cb321|2 years ago|reply
Maybe instead of demons with config files that have more and more bespoke syntax, it's better to go all the way to a library that provides the basic loop functionality? Like https://github.com/c-blake/cron or something similar in C or whatever.

Maybe not, but it's an idea worth considering...

[+] imtringued|2 years ago|reply
The fact that the timer and the job are separate in systemd is actually a blessing, because now you can start your jobs manually and actually test that they work.
[+] ei8ths|2 years ago|reply
i cant say much about cron, i use it for simple scripts on systems. When i have a lot of jobs that need to be scheduled routinely and i need alerts if they dont, i use jenkins, it works really well.
[+] dalore|2 years ago|reply
Cron that uses RRules would be nice.
[+] AbuAssar|2 years ago|reply
fcron is very similar to facroun which means turtle
[+] askiiart|2 years ago|reply
This comment is completely unrelated to any discussion here, and I love it.