Daydreaming in Brookline, MA

Pythonスクリプトをcronから定期実行する

1 はじめに

PythonのスクリプトをLinuxマシン上で定期実行することを考えます。Linuxにはジョブスケジューラーのcronがありますが、必要ライブラリをpipでインストール済みのvenv環境を使うには少し工夫が必要です。

2 venv環境を使う

venv環境をactivateしてPythonスクリプトを実行するためには、cronから

python <script>.py

のように直接Pythonを呼んでスクリプトを実行するのではなく、ヘルパーのシェルスクリプトに頼ります。

しかし、venv環境をactivateするsourceコマンドは普通のshにはなく、bashを使わなくてはいけません。そこで、例えば次のようなスクリプトを作ります。

#!/usr/bin/bash
cd </path/to/venv/folder>
source bin/activate
bin/python <python_script>.py

よく目にする #!/bin/sh でなくbashを指定することと、 </path/to/venv/folder>/bin/python を使うところがポイントです。

これをrun_script.sh としてセーブし、実行可能にします。

chmod a+x run_script.sh

3 crontabに登録する

crontabに登録してcron実行するために、

sudo crontab -e

を実行します。すると、viでcrontabが開かれるので、

0 */4 * * * </path/to/venv/folder>/run_script.sh

のような行を追加します。上記は4時間毎の実行です。 0 は(毎時)ゼロ分を、 */4 は4時間毎を意味します。

左端の5個のフィールドは以下のフォーマットになっています。

* * * * *
| | | | +--- 曜日(0-6; 日曜が0)
| | | +----- 月(1-12)
| | +------- 日(1-31)
| +--------- 時(0-23)
+----------- 分(0-59)

きちんと登録されたかどうかは以下のコマンドで表示、確認できます。

sudo crontab -l

デバッグのためには、もっと頻繁に、例えば2分に1回の実行とし、print文やエラーをファイルに出力させるといいと思います。

*/2 * * * * </path/to/venv/folder>/run_script.sh >> /tmp/out.txt 2>&1

上記において、 2>&1 の部分は、エラーを標準出力にリダイレクトしています。

実際にこれが実行されたかどうかはログを見ます。

sudo tail -f /var/log/cron

次の実行が出力されたら、/tmp/out.txtを見に行きます。

  • そもそも/tmp/out.txtが作成されているか
  • out.txtにエラーが出ていないか

といったことを見ます。2回目以降は、実行される前に/tmp/out.txtを消しておくと、切り分けが少し楽になります。

4 終わりに

上記のテクニックを使って、オフィスのラボにあるサーバーがダウンしていないかを自動で定期的に確認し、ダウンしていたらSlackにメッセージをポストするようにしました。更に、サーバーにインストール済みのバージョンよりも新しいバージョンが無いか、Jenkinsをチェックして比較しています。

このように、社内システムのAPIを使って「退屈なこと(boring stuff)」を自動化するのに、手軽に使えて高機能なPythonは向いていると思います。