iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
👺

I built a tool for exponential backoff in cron

に公開

Introduction

cron is very convenient for executing commands repeatedly.

* * * * * /path/to/the/command

Specifying it like this in crontab will execute it every minute.

*/3 * * * * /path/to/the/command

Specifying it like this will execute it every 3 minutes.

While it is very convenient, if command execution fails, it can result in redundant command runs. In cron, if a command continues to fail, emails will be repeatedly sent to the administrator.
You put a command into crontab to run every minute, confirm it starts correctly for the time being, finish your work, go home, have a beer, and just when you're thinking about going to bed, if the command starts failing, emails will keep flying until morning.

Also, if you've set up a cron job that calls a web service API and that service goes into maintenance, you might have issues. Calling an API that fails indefinitely despite being under maintenance might even lead to being banned.

The whole problem is that cron doesn't have an exponential backoff feature.

Solving it with systemd timer

You can achieve something close to exponential backoff by using systemd timers.

https://x.com/moriwaka/status/1737993103129366882?s=20

Thank you, moriwaka-san. However, things that have been operated with crontab until now are not easily migrated. (At least for me.)

I created a backoff command

https://github.com/mattn/backoff

Usage is simple. Just write backoff before the command in crontab.

* * * * * backoff /path/to/the/command

Just by writing this, the interval for the next startup will become longer when consecutive failures occur following a previous failure.

Elapsed Result backoff
0 min later Success
1 min later Success
2 min later Failure 1 min
3 min later Failure 2 min
4 min later No execution
5 min later Failure 4 min
7 min later No execution
8 min later No execution
9 min later No execution
10 min later Success 0 min
11 min later Success 0 min

The mechanism is simple: this backoff command saves a leveldb database called .backoff in the current directory and increases the backoff value with each failure.

Usage of ./backoff:
  -V	verbose
  -f string
    	storage file (default ".backoff")
  -k string
    	key (default is command-line)
  -max duration
    	max wait (default 1h0m0s)
  -off duration
    	offset (default 1m0s)
  -v	show version

The directory for the .backoff directory can be changed. Also, while the above example is for every minute,

*/3 * * * * /path/to/the/command

In a case like this where it runs every 3 minutes, you would want it to increase as 3 minutes, 6 minutes, 9 minutes, and so on. In such cases, you can specify -off 3m.

*/3 * * * * backoff -off 3m /path/to/the/command

Furthermore, while the backoff increases steadily, you can also specify its maximum value. The default maximum is 1 hour, but specifying -max 0 allows it to keep increasing indefinitely.

Conclusion

I created the backoff command for those who find it difficult to move away from cron. It's still brand new, so there might be bugs. If you find any issues, please feel free to contribute.

Discussion