エラー内容
laravelでpythonを途中使うところがあり、ライブラリインポートのところでこんなエラーに遭遇した。
...
File "xxx/.pyenv/lib/python3.10/site-packages/pydub/audio_segment.py", line 163, in AudioSegment
converter = get_encoder_name() # either ffmpeg or avconv
File "xxx/.pyenv/lib/python3.10/site-packages/pydub/utils.py", line 164, in get_encoder_name
if which("avconv"):
File "xxx/.pyenv/lib/python3.10/site-packages/pydub/utils.py", line 152, in which
envdir_list = [os.curdir] + os.environ["PATH"].split(os.pathsep)
File "/usr/lib/python3.10/os.py", line 680, in __getitem__
raise KeyError(key) from None
KeyError: 'PATH'
しかも、sshでログインして直接スクリプトを叩くときはエラーがでない。
エラーの原因
エラー内容をちゃんと見てみると、os.environ["PATH"]
でPATHというキーがないというエラーということだった。
pythonのos.environは、OS の環境変数を反映する(コマンドのprintenv
とかで確認できる)ということなので確認してみたところ、コマンド上では数十個登録されていたが、laravelのスクリプトの途中でexec(printenv)
を行うと3つしか登録されていなかった。
環境の違い
sshからのログインシェルからスクリプトを叩くときと、リクエストからlaravelの処理を通ってスクリプトを叩くときの差が影響しているということになりそうだ。
リクエストでは、デーモンのnginxからのデーモンのphp-fpmで処理をするので、ここの環境変数の設定がログインシェルの時と違うことになる。
systemctlで設定(解決せず)
まずpythonを実行するのはphp-fpmじゃないかという当たり前のことに気が付く前の話。。
ubuntuのサービスの設定プロパティにEnvironmentFileというのが設定できるのでそれで解決できるのではないかと試していた。(備忘録として書いておく)
systemctl show nginx.service
というのでubuntuのサービスの設定プロパティを見ることができるのだが、独自の設定を以下のコマンドから追加することができるらしい
systemctl edit nginx.service
まずこのファイルの編集に時間をとられてしまったのだが、よく見ると「Lines below this comment will be discarded」と書いてあり、それ以降に何を書いても
Editing "/etc/systemd/system/nginx.service.d/override.conf" canceled: temporary file is empty.
と言われてしまって保存ができないので注意!!!
デフォルトで用意してくれる設定ファイル
### Editing /etc/systemd/system/nginx.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file
## ここに何か書かなくてはいけない
### Lines below this comment will be discarded
###これ以降に書いても何も保存できない
###
# [Unit]
...
# [Service]
# Type=forking
# PIDFile=/run/nginx.pid
...
PHP-FPMの設定 clear_env
PHP-FPMの方をなんとかしなくてはいけない、と気づいてから調べたところ、php-fpmの設定でclear_env=noを指定できるという記事を見た。
https://qiita.com/jkr_2255/items/51ef6112a11465ed5e6e
実際設定ファイルを見てみると、clear_env=noはデフォルトでコメントアウトされていた。
このコメントアウトを外すと、環境変数PATHは渡されるようになり(それでもログインシェルの時よりなんか少なかったけれど)、問題は解決された。。
終わりに
エラーはちゃんと根気強くエラー文をよく読んで根幹を直すように考えないと、こうして遠回りすることになってしまう…。(これ、定期的に反省してる気がする)
特にchatgptの使い方はちゃんと考えないとね🙄