はじめに
決まった時刻に何かをやらせたいとき cron を使うが,cron の設定(crontab)を書くのは非常にめんどくさい。
Ruby の whenever という gem を使えば,いつ何をやらせたいかが Ruby で記述でき,簡単なコマンドでそれを crontab に反映させることができる。
Rails と組み合わせることも多いが,Rails とは無関係に使うこともできる。
本記事は,whenever の設定を置いたディレクトリー名が妥当でなかったために不可解な現象が起こった,という話。
whenever の手順
まず最初に whenever の使い方を振り返ってみる。
本節ではトラブルは起こらない。
準備
まずは gem のインストール:
gem install whenever
設定を置くディレクトリーが /Users/nemo/hoge であるとする:
cd /Users/nemo/hoge
whenever 設定ファイルの雛形を作る:
wheneverize
べつに手作業でファイルを置いてもいいのだが,このコマンドを使えば簡便。
/Users/nemo/hoge/config/schedule.rb というファイルができる(config ディレクトリーも自動的に作られる)。
このファイルに「いつ何をやらせるか」を書く。
書き方の例が入っているがコメントアウトされているので,実質は空だ。
タスクを記述
試しに schedule.rb に何か書いてみよう。
Linux や macOS ではコマンドラインで
date +%R
と打てば現在時刻を 18:24 といった形式で表示してくれる。これをファイル now.txt に書き出す,ということを 1 分ごとにやらせてみよう。
以下のように書く:
every 1.minutes do
command "date +%R > /Users/nemo/hoge/now.txt"
end
crontab に
カレントディレクトリーが /users/nemo/hoge であることを確認のうえ,
whenever -i
と打つ。
そうすると毎分,now.txt が更新される。
crontab の内容を確認するため
crontab -l
と打つと,以下のように表示される:
# Begin Whenever generated tasks for: /Users/nemo/hoge/config/schedule.rb at: 2025-05-13 18:32:18 +0900
* * * * * /bin/bash -l -c 'date +\%R > /Users/nemo/hoge/now.txt'
# End Whenever generated tasks for: /Users/nemo/hoge/config/schedule.rb at: 2025-05-13 18:32:18 +0900
コメントの # Begin ...
と # End ...
で挟まれた中に実質的な内容が書かれている。
このコメントに,whenever の設定ファイルの絶対パス
/Users/nemo/hoge/config/schedule.rb
が書かれているが,これが重要だ。
パス名の書かれたコメントで囲まれていることにより,複数の whenever 設定を crontab に突っ込むこともできるし,あとで特定の whenever 設定を更新する,削除する,といったことが可能になる。パス名が識別子になっているわけだ。
この仕様が本記事の核心に関わってくる。
止める
さて,止めるには
whenever -c
と打つ。
この状態で
crontab -l
と打つと,crontab が空になったことが分かる。
now.txt はもはや更新されない。
パスを指定
whenever コマンドのオプション -i
や -c
には,設定ファイルの絶対パスを渡すこともできる。
デフォルトはカレントディレクトリーの config/schedule.rb である。
トラブル
ここから本題に入る。
私は,さる事情で whenever の設定ファイルを置くディレクトリーを一時的に hoge+ という名前にした。
設定ファイルのパスは
/Users/nemo/hoge+/config/schedule.rb
のようになる。
このようにしても,whenever -i
で crontab を更新することはできる。
ところが,whenever -c
で消すことができない。
また,whenever -i
で更新しようとしても,更新ではなく追記になってしまう。
まさか設定ファイルのパスに問題があるとは思わず,数時間を溶かした。
どうやらパス名の中に +
が入っていると crontab の中から当該の設定を見つけ出すことができないようなのだ。
whenever のコードを調べてはいないが,こういうケースを想定してないのだろう。
おおかた +
が正規表現のメタ文字と解釈されちゃって……といったところではないだろうか。
蛇足
whenever は最新版(1.0.0)のリリースが 2019 年 6 月であり,まもなく 6 年が経つ。
Issues も Pull requests も溜まっている。
大丈夫なんだろうか。