👺

cron で exponential backoff するツール作った

2023/12/23に公開

はじめに

cron を使うと繰り返しコマンドを実行するのが便利です。

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

crontab でこの様に指定すると1分毎に実行されます。

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

この様に指定すると3分毎に実行されます。

とても便利ではあるのですがコマンドの実行が失敗すると、冗長なコマンド実行となり得ます。cron ではコマンドの実行が失敗し続けるとメールが運営者に繰り返し送信され続けます。
crontab にコマンドが1分毎に実行される様に投入してひとまず正常起動を確認、仕事を終えて家に返ってビールでも飲んで、さぁ寝ようかなと思った頃にコマンドが失敗し始めると、朝までメールが飛び続けます。

またウェブサービスの API を呼び出す cron ジョブを投入していたらそのウェブサービスがメンテナンスに入った、なんて事もあると思います。メンテナンス中にも関わらず無限に失敗し続ける API 呼び出しはもしかしたら BAN の対象になってしまうかもしれません。

全ては cron に exponential backoff する機能がないのが問題です。

systemd timer で解決する

systemd の timer を使うとそれに近い exponential backoff を実現できます。

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

moriwaka さんありがとうございます。ただ、今まで crontab で運用してきたものは、なかなか簡単に移行できる物ではありません。(少なくとも僕は)

backoff コマンドを作った

https://github.com/mattn/backoff

使い方は簡単。crontab でコマンドの前に backoff と書くだけです。

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

こう書くだけで前回の失敗から連続で失敗した場合の、次回起動間隔が長くなってくれます。

経過 結果 backoff
0分後 成功
1分後 成功
2分後 失敗 1分
3分後 失敗 2分
4分後 実行なし
5分後 失敗 4分
7分後 実行なし
8分後 実行なし
9分後 実行なし
10分後 成功 0分
11分後 成功 0分

仕組みは簡単で、この backoff コマンドがカレントディレクトリに .backoff という leveldb のデータベースを保存し、失敗のたびに backoff を増やしていくというものです。

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

.backoff ディレクトリのディレクトリは変更できる様にしてあります。また上記の例では1分毎ですが

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

この例の様に3分毎の実行であれば、3分,6分,9分 と増えて欲しいものです。そういう場合には -off 3m と指定できる様にしてあります。

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

また backoff はどんどん増えますがその最大値も指定できる様になっています。最大は 1 時間ですが -max 0 を指定すると無制限に増え続けます。

おわりに

cron をなかなか捨てられない人の為の backoff コマンドを作りました。まだ出来たてですしバグもあるかもしれません。何か問題を見付けたらコントリビュートして下さい。

Discussion