cronexec - 指定秒「間隔」毎にコマンド実行

schedexec - 指定時間にコマンド実行

current revision: 0.90


1.cronexec とは何か?

cronexec は、指定した秒「間隔」毎に、コマンドを実行する、ただそれだけのプログラムです。
2.schedexec とは何か?
schedexec は、指定した時間、「何曜日何月何日何時何分0秒」に、コマンドを実行する、ただそれだけのプログラムです。
3.なぜこの様なモノを作ったのか?。
cronexec(schedexec) は、いわゆる UNIX システム標準にある、cron デーモンのシンプルな置換えを考えたモノです。
私は、普段は Linux を使っていますが、cron デーモンは、 と言うのがあり、出来るだけシンプルに、また、cron デーモンに出来ない事を実装させた「つもり」です ^_^;;;;。
4.特徴
cronexec と schedexec は、以下の特徴があります。 ただし、現時点では、テスト版であるので、上記の機能全てを網羅していますが、不具合があるかも知れません。
5.インストール
  1. http://www.netfort.gr.jp/~tosihisa/cronexec/cronexec-0.90.tar.gz をダウンロード
  2. tar -zxvf cronexec-0.90.tar.gz
  3. make ; make install
/usr/local/bin に cronexec と schedexec インストールされます。

Slackware Linux で動作確認しています。

6.コマンド書式
cronexec , schedexec のコマンド書式は以下の通りです。

cronexec [-aTLlWvh] [-C count] [-c count] [-i init-sec] [-e exitcode] -- wait-sec arg(s)...

schedexec [-LlGvh]  [-C count] [-c count] [-e exitcode] -- "CRONTAB-STRING" arg(s)...

-a

(cronexec のみ)
「先ず初めに」指定したコマンドを実行し、時間待ちに入る。
このオプションを省略した場合、「先ず指定された時間待ってから」コマンドを実行する。
-i オプションと併用することは出来ない。
-T
(cronexec のみ)
5秒ごとに起動し、現在時刻を所得して、wait-sec 秒経過したか調べる。
このオプションを省略した場合、指定した時間になるまで単純に sleepする。
-L
cronexec は、標準出力にログメッセージを出力します。
このオプションを指定した場合、そのログメッセージの先頭に、GMT を付加します。
-l
-L と同様ですが、ログメッセージの先頭に、ローカル時間を付加します。
-L 及び -l が省略された場合、ログメッセージの先頭に時間は付加されません。
なお、ログメッセージは、必ず表示します。これを省略するオプションはありません。
-C count
count 回数コマンドを実行すると、終了コード0で終了します。
-c count
count 回数コマンドを実行すると、永遠に眠り続けます。
永遠に眠り続けている状態で、HUP シグナルを受信すると、1回、指定されたコマンドを実行し、再度、永遠に眠り続けます。
-W
(cronexec のみ)
プロセス実行時間を、次回のコマンド実行時間に加味する。例えば、

cronexec -- 10 /bin/sh -c "sleep 3"

と実行した場合、10秒ごとに、/bin/sh -c "sleep 3" が実行されますが、この場合、プロセス実行時間は、最低でも3秒経過しているはずです。

-W オプションを指定した場合、cronexec はプロセス実行を監視し、プロセスの処理時間を求め、プロセス処理時間を、次回のコマンド実行時間に加味します。上記の場合、/bin/sh -c "sleep 3" 実行後、7秒後に、再度コマンドを実行します。

図示すると以下の様になります。

<--10s --><--10s --><--10s -->  <- 指定秒間隔
*---------*===------*===------*
           <->       <->
           3s        3s  <- プロセス実行時間

本オプション省略時は、プロセス実行時間は加味されません。従って、以下のタイミングでコマンドが実行されます。

<--10s -->    <--10s -->    <--10s -->  <- 指定秒間隔
*---------*===----------*===----------*
           <->           <->
           3s            3s  <- プロセス実行時間

-v
バージョン表示後、終了します。
-h
コマンドラインオプションの表示後、終了します。
-i  init-sec
(cronexec のみ)
1回目の処理開始時間を指定する。「時間間隔」では無く、「開始する時間」である事に注意。
ここで設定するのは、time(2) の戻り値であるが、GNU 拡張の date コマンドがあれば、

date -d "Thu May 17 00:03:00 JST 2001" +%s

で、2001年5月17日午前0時3分0秒の、time(2) の戻り値を取得できる(詳しくは man date)。従って、

-i `date -d "Thu May 17 00:03:00 JST 2001" +%s`

と指定すれば、2001年5月17日午前0時3分0秒 に1回目のコマンドを実行し、以後は時間間隔に従ってコマンドを実行する。
もし、cronexec 実行時に、システムの時間がこのオプションで指定された時間以降であるなら、このオプションは無視される。
-a オプションと併用することは出来ない。

-e  exitcode
実行したコマンドの終了コードを調べ、exitcode と一致しない場合、カレントディレクトリに、.cronexec_pause ファイルを作成します。
schedexec の場合、.schedexec_pause ファイルを作成します。
cronexec と schedexec は、指定時間が経過し、コマンドを実行する際、.cronexec_pause(.schedexec_pause) ファイルが存在する(cronexec がそのファイルを読み出せる)状態にある場合、そのコマンドを実行しません。
cronexec は、.cronexec_pause を消去しませんので、.cronexec_pause ファイルは、(問題解決後)手動で消去する必要があります。schedexec についても同じです。
-G
(schedexec のみ)(未テスト)
schedexec は、「毎分0秒」に動作する仕組みですが、このオプションを指定した場合、「毎分0秒」の判断に、GMT を使用します。このオプションを省略した場合(Default 時)は、「毎分0秒」の判断に、ローカル時間を使用します。
--
これ以上オプション検索を行わない所で指定します。
cronexec と schedexec は、出来る限りオプション検索を行い、場合によっては、実行したいコマンドのコマンドラインオプションを、cronexec(schedexec) のオプションとして扱ってしまう場合があるので、その時に指定します。
wait-sec
(cronexec のみ)
起動時間間隔を指定します。秒単位で指定します。
また、

1m : 1分(60秒)毎
1h : 1時間(3600秒)毎
1d : 1日(86400秒)毎
1w : 1週間(604800秒)毎

と表記することも可能です。

 "CRONTAB-STRING"
(schedexec のみ)
起動時間を指定します。内容は、crond に与える時間パラメータと同じです。',' による列挙、'-' による範囲指定、'/' によるレンジ指定もサポートしています。ただし、月と曜日に、文字列(Sun,Jul 等)を指定する事は出来ません。

crond(schedexec) に与える時間パラメータは、5項目に分けられます。詳しくは、man crontab(man 5 crontab)を参照いただくとして、簡単に記載すると、

項目             有効設定値
------------------
分                 0-59
時                 0-23
日                 1-31
月                 1-12
曜日             0-7  (0 と 7):日曜日

の各項目を、空白文字で区切って指定します。

各項目は、ワイルドカード '*' で、必ず該当する様になります。また、"1,3,5,7" と、',' で続けて設定することが出来、"1-4" とすると、1,2,3,4 を指定した事と同じになります。また、"0-10/5" とするとレンジ指定する事になり、0,5,10 が該当します。

arg(s)
実行したいコマンド及びオプションを指定します。
コマンドは、絶対パスで指定する必要があります。
7.シグナル
cronexec と schedexec は、TERM シグナルを受信すると終了します。また、HUP シグナルを受信すると、指定時間でなくても、指定時間に達したものとして、コマンドを実行します。
8.ファイル
cronexec は、指定時間経過による、コマンド実行の際、カレントディレクトリに .cronexec_pause ファイルが存在する(cronexec が読み出せる)か調べ、存在する場合、コマンド実行の一時停止の指示がされたものと見なし、そのコマンドを実行しません。これは、HUP シグナルを受信した事によるコマンド実行時も同様です。
.cronexec_pause ファイルが存在する事により、コマンド実行がスキップされた場合は、-C(-c)オプションによるコマンド回数は、スキップされた分はカウントしません。
セキュリティを考慮する場合、cronexec を動作させるディレクトリのパーミッションを適切に設定して下さい。
schedexec の場合、.schedexec_pause が存在するか調べます。それ以外は cronexec の動作と同じです。
9.使用例
例1)5分おきに、/usr/local/bin/age-smtp を実行する。その時、5秒毎に経過時間を調べ(-T)、プロセス処理時間を加味し(-W)、標準出力のログメッセージにローカル時間を付加する(-l)。また、終了コードが0であるかどうか調べます(-e0)。

cronexec -T -W -l -e0 5m /usr/local/bin/age-smtp

例2)45秒おきに、3回、/usr/local/bin/netchk -laを実行する。その時、単純に指定時間まで待ち、プロセス時間は加味しない。標準出力のログメッセージに時間は付加しない。3回処理を実行した後、終了する(-C 3)。-la オプションを誤認識させないために、-- オプションを置き、オプション検索をそれ以上行わないようにする。

cronexec -C 3 -- 45 /usr/local/bin/netchk -la

例3)2001年5月17日の午前0時0分0秒から、1時間おきに、/usr/local/bin/clockchk を実行する。

cronexec -WTli `date -d "Thu May 17 00:00:00 JST 2001" +%s` -- 1h /usr/local/bin/clockchk

例4)毎月10日の13時0分に、/usr/local/bin/syschk を実行する。標準出力のログメッセージにローカル時間を付加する(-l)。

schedexec -l -- "0 13 10 * *" /usr/local/bin/syschk

例5)毎週火曜日の10時0分に、/usr/local/bin/syschk を実行する。

schedexec -- "0 10 * * 2" /usr/local/bin/syschk

例6)毎月1〜10日、12日、20日の0時0分に /usr/local/bin/logchk を実行する。20回実行し、終了する(-C 20)

schedexec -C 20 -- "0 0 1-10,12,20 * *" /usr/local/bin/syschk

まずはシステム上支障の無いコマンド等を利用して、cronexec と schedexec の動作を見て下さい。

10. schedexec の動作タイミングと「閏秒」対応について
schedexec は、「毎分0秒」に、コマンドを実行すべきかどうかを調べます。

これは、多くの Linux ディストリビューションに搭載されている crond とは、明らかに異なる動作です。多くの Linux ディストリビューションに搭載されている crond は、一見、「毎分0秒」に動作している様に見えますが、実際は、「60秒毎」に動作し、コマンドを実行すべきかどうかを調べています。

「60秒毎」の場合、途中で時間が変更されたり、閏秒が設定されているシステムの場合、正しくその時間(毎分0秒)に動作しません(もちろん、crond は秒単位での動作を保証している訳ではないので、この動作はバグではありません)。

schedexec は、libc のライブラリ関数である、localtime()(gmtime())を「毎分0秒」の判定に使用するので、libc の localtime()(gmtime())が閏秒に対応していれば、schedexecは、そのまま閏秒に対応し、閏秒対応システムにおいても、「毎分0秒」に処理を行います。

ただし、schedexec は、例えば、6月17日、午前2時0分にコマンドを実行するとして(schedexec "0 2 17 6 *")、6月17日の午前1時59分30秒の時点で、各種方法で45秒システム時間を進めた(6月17日の午前2時0分15秒)場合、「毎分0秒」を取得できなかったので、コマンドは実行されません。

schedexec で確実に(毎分0秒に)処理を行わせたい場合は、schedexec で指定した時間の前後1分間に、システム時間の補正をしない事を推奨します。

11. schedexec の「時間」の考え方について
schedexec は、「時間は過去に遡らないもの」として実装しています。具体的には、前回のコマンド実行時の時間を記憶し、次の(今回の)コマンド実行を判断する時(毎分0秒を判断する時)、前回のコマンド実行時の時間+5秒以上経過していないと、コマンド実行の判断(毎分0秒の判断)を行いません。
12.応用
cronexec と schedexec を、Bernsteinさん作の daemontools を組み合わせて使用すると良いカモ。
(って言うか、元々それ向けに作ったのですが...)
13.各種権利
cronexec は、配布ライセンスは GPL2 に基づき、配布します。
このプログラムを使用した事によるいかなる責任も、私(たなかとしひさ)が負うものではありません。
14.連絡先
このプログラムに対するお問い合わせは、たなかとしひさ(tosihisa@netfort.gr.jp)まで御連絡下さい。基本的に必ずお返事しますが、多忙な場合、お返事が遅れる事をご了承下さい。
ではこれにて :-)