⏲️

Cronにsub-minuts(一分未満の頻度、解像度、秒単位)がほしい

2024/04/22に公開

古来から人間はCronを一分未満でもうごかしたいと願っていました。

しかし、残念ながらCronは1分毎にしか動かすことができません。

sleep術

悪いやり方として、Sleepを入れると言うテクがありました。

* * * * * index.sh
* * * * * sleep 10; index.sh
* * * * * sleep 20; index.sh
* * * * * sleep 30; index.sh
# ...

これの長所は「とにかく動くには動く」です

欠点として、Cronの見栄えが悪くてつらい(???)です。

(シェルスクリプトでループする方法もありますが、見栄えはどっこいどっこいかな…)

余談、ロックは必須

Cronは起動しかしてくれません、多重起動については責任範囲外です。よって短い時間で実行するとバッチが突き抜ける(次の実行開始までに終わらない)可能性があります。

なので、同時実行は内部でmutexを持ったり、setlockなどでブロックしましょう。

ここは省略しますがググるとみつかるかなとおもいます。

デーモン化(?)

無限ループするシェルをつくり、それから起動します

#!/bin/bash

while true
do
    ./child.sh # これが処理の本体です
    sleep 10
done

これの長所はシンプルさです。多重起動について考える必要もありません(これ自体を多重起動するとダメですが)。

欠点は

  • このシェルスクリプトが途中で終了してしまう可能性がある
  • ループを安全に終了する方法がない(親をkillすると、子もkillされてしまう)
  • N時M分30秒に起動、という指定はむずかしい
  • これ自体を起動し、生かし続けるためになんらかが必要となる(Supervisorなり、systemdなりなんなり)

等です。

screenとかnohupでこれをうごかしつづけるのは自作のちょっとしたプログラムを動かすには良いですが、可用性が必要とされるサービスだと微妙だと思います。(再起動でもどらないし)

systemdのrestartを活用

systemdにはcron的に使えるものがあります、以下のようにserviceをつくり、Enableし、Startすることで一つ前のデーモンのようなことができます

[Unit]
Description=Something worker

[Service]
Type=simple
ExecStart=/path/to/script
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

このようにすることで、終了した後、再起動(つまりは次の実行)が10秒まってから行われます。プロセスの終了がSystemdによって監視されるので多重起動管理は通常不要です。

また、cronだと出力ログの扱いが少々面倒ですが(Cronの設定にもよりますが)、systemdのServiceとして動くなら、journalctlで簡単に参照することもできます。

これの欠点についてはN時M分30秒みたいな指定ができないことや、systemdをみんなが好きではないことです。

systemdのtimerを使う方法

# somthing.serviceとする
[Unit]
Description=Something worker

[Service]
Type=oneshot
ExecStart=/path/to/script
RemainAfterExit=no

[Install]
WantedBy=multi-user.target
# run_something.timerとする
[Unit]
Description=Run Something at every half minutes

[Timer]
OnCalendar=*:*:0,*:*:30
Unit=somthing.service

[Install]
WantedBy=timers.target

これの欠点は結構複雑なことです。

長所としては、Timerをdisableすることでより安全に停止できる(Gracefull stop)ことや、Timerをとめておきながら一発動かすこともできます。

Cronか、Systemdか。あるいは…

個人的には、Cronは皆が手なれていて楽ではあるものの、IaC時代には面倒な場面もふえてきています。(まあ、できない事はないんですけど)

Systemdならば、スケジュールがファイル単位に分割されている事や、コマンドで取り扱えることが多いのがメリットかなと思います。

しかし、そもそもプログラムがデーモン化されていて内部にジョブキューをもっていたり、コンテナ時代においてはそもそもCronとかSystemdもどうなん???という話もあり…、このような工夫自体が大分時代錯誤かもしれませんね。ただまあ、知っていると便利ではあります。

こちらからは以上です。

番外編

cron、systemd以外にもat,batch(atd)というものがあり、物知り博士になりたい人はみてみると面白いです。

Discussion