pyenv + cron で Python スクリプトが動かない構成をレビューでどう指摘するか
Python スクリプトが cron で動かない「見えないエラー」
開発環境では何の問題もなく動いていた Python スクリプトが、cron で定期実行しようとすると失敗する──
しかもログにもエラーが残らず、失敗に気づかないという現象は、実務で頻繁に発生します。
line 3: python: command not found
この構成ミスは表面的には "python がない"
というだけに見えますが、レビューの立場から見れば、環境構築と運用設計の分離ができていない構造的問題です。
コードの品質が高くても、実行環境の構成に問題があると全体が破綻します。本稿では pyenv + cron
による構成トラブルを題材に、レビューアーがどう指摘・補助すべきかを詳述します。
なぜ pyenv 環境で cron は Python を見失うのか
pyenv はユーザー毎にインストールされる Python バージョン管理ツールです。
インストールされた Python は以下のようなユーザー領域に存在します:
~/.pyenv/versions/3.10.4/bin/python
しかし cron
は以下のような簡素な実行環境で動作するため、これらのパスを認識できません:
環境変数 | cron の実行時値(例) |
---|---|
PATH |
/usr/bin:/bin |
HOME |
/root または非ログインユーザー |
SHELL |
/bin/sh |
したがって、pyenv
により設定された python
は cron から見れば「存在しない」コマンドです。
which python
で解決しない理由
多くの開発者は次のように考えます:
which python
# /home/user/.pyenv/versions/3.10.4/bin/python
ではこれを cron に直接書けばよいのではないか──と。
しかし、これは根本的に誤りです。なぜなら which
が返す値はログインシェルが pyenv のフックを通して構成した PATH を元に解決された値であり、cron ではその PATH が使われないからです。
さらに、pyenv の実態は shims
ディレクトリを使ったシンボリックな中継構成であり、直接呼び出すことすらサポート外です。
レビューアーは「which python
の出力をそのまま使えば安全」という誤解を構造的に指摘すべきです。
pyenv と cron を共存させるラッパースクリプト
pyenv を cron から使用する場合は、非対話環境で pyenv の初期化処理を明示的に呼び出す必要があります。
#!/bin/bash
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
# pyenv 初期化
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
pyenv shell 3.10.4
cd /home/user/project || exit 1
python batch.py
この構成でようやく cron
から pyenv
環境が再現されます。
レビューアーとして確認すべき点は:
pyenv init
をeval
しているかpyenv shell
でバージョンを明示しているかPATH
に pyenv/bin が明示的に追加されているか
@Reviewer: pyenv 環境の初期化が不足しています。`pyenv init` および `pyenv shell` を使ってバージョンを明示してください。cron は非対話環境であるため `.bashrc` が読み込まれません。
root の crontab では動作しない理由
pyenv はあくまでユーザーごとの環境です。よって sudo crontab -e
のように root の crontab に登録されたジョブは、たとえスクリプトに pyenv
初期化処理が書かれていても失敗します。
/root/.pyenv/ などは存在せず、pyenv.sh も見つからないため初期化に失敗
cron に登録する際は、必ず 対象ユーザー自身の crontab に登録しなければなりません。
@Reviewer: このジョブは pyenv を使用しており、root の crontab に登録されていると失敗します。該当ユーザーの `crontab -e` に移してください。
systemd.timer による代替提案
cron 以外の選択肢として、systemd を利用できる環境であれば systemd.timer
による定期実行の方が安定します。
[Service]
Type=oneshot
WorkingDirectory=/home/user/project
ExecStart=/home/user/.pyenv/versions/3.10.4/bin/python batch.py
[Timer]
OnCalendar=*-*-* 01:00:00
Persistent=true
[Install]
WantedBy=timers.target
この方法では:
- 実行ユーザーを明示可能(User=指定)
Environment=
により仮想環境の変数も渡せるjournalctl
によるログ記録が可能
@Reviewer: 非対話環境の依存が強いため、cron ではなく systemd.timer での実行を検討してください。PATHやユーザー権限を明示でき、ログも管理しやすくなります。
レビュー時のチェックリスト
以下は、pyenv + cron
の構成をレビューする際のチェックポイントです。
結論:Pythonコードだけではレビューは不十分
pyenv + cron
のような構成では、コードそのものは正常でも実行基盤の不備によって全体が破綻するというケースが多くあります。
レビューアーの仕事は、コードロジックだけを見ることではありません。
そのコードが「いつ、どこで、誰の環境で、どのように実行されるのか」を含めて指摘できてこそ、構造的なレビューが成立します。
静的なコードレビューでは見逃されがちな「実行環境に潜む前提依存」は、
pyenv + cron に限らず nvm、rbenv、Docker、systemd、CI/CD すべてに潜在しています。
レビューとは「コードを見ること」ではなく、「構成と運用を設計通りに動かす責任の共有」であることを忘れてはいけません。