こんにちは。Treasure Dataサポートチームの今村です。
ローカルで実行(テスト)するとエラーとならなかったPythonのスクリプトをTreasure Workflow(Treasure DataがホストしているDigdag)上で実行すると、No such file or directory
(digdagのファイルが存在しない)というエラーが発生する場合があります。Custom Scriptsでディレクトリ操作を行った時に起こりうるエラーとなりますが、本日はこのエラーへの対処方法をご紹介します。
事例
ワークフローからmain関数を実行する事例でご紹介します。 下記のように1つのdigファイル(ファイル名wf.dig)とPythonのスクリプトファイル(py_scriptsフォルダ内にファイル名ch_dir.py)があるとします。
Pythonで記述されたmain関数にはカレントディレクトリを変更する処理が入っています。
import os def main(): print("hello") os.mkdir('tmp') # ディレクトリを作成する os.chdir('tmp') # 作成したディレクトリに移動する print("world")
このmain関数の実行結果としてはhelloとworldの2行が書き出され、エラーは発生せずに正常に実行されます。ローカル環境での実行例は次のとおりです。
% python -c "from py_scripts import ch_dir; ch_dir.main()" hello world
Treasure Workflowでpy>:
オペレータを使い、先ほどのmain関数を実行します。
+task1: py>: py_scripts.ch_dir.main docker: image: "digdag/digdag-python:3.9"
このワークフローを実行するとエラーが発生してしまいます。WORKFLOW LOGSタブでエラーの詳細を確認してみます。
詳細を見てみると、No such file or directory
(digdagのファイルが存在しない)というエラーであることがわかります。
: with open(out_file, 'w') as f: FileNotFoundError: [Errno 2] No such file or directory: '.digdag/tmp/digdag-py-1159889021-1708980813522031538/output.json' 2022-09-20 07:05:39.634 +0000 [ERROR] (0288@[10452:hi_custom_test:96874279:509925422]+hi_custom_test+task1) io.digdag.core.agent.OperatorManager: Task failed with unexpected error: Python command failed with code 1 Error messages from CommandExecutor: No container information java.lang.RuntimeException: Python command failed with code 1 Error messages from CommandExecutor: No container information at io.digdag.standards.operator.PyOperatorFactory$PyOperator.runCode(PyOperatorFactory.java:181) at io.digdag.standards.operator.PyOperatorFactory$PyOperator.runTask(PyOperatorFactory.java:121) :
原因
このエラーの原因は、Custom Scriptsで実行している関数でカレントディレクトリを変更したことにあります。しかし、なぜカレントディレクトリを変更すると、エラーが発生してしまうのでしょうか。
py>:
オペレータを使ってワークフローからPythonのスクリプトを実行すると、作成した関数の実行だけではなく、その関数の実行に関するログ出力の処理が内部で行われます。ログの出力先はワークフローの実行の度に変わりますが、今回の例の場合は.digdag/digdag-py-1159889021-1708980813522031538/output.json
となります。関数の処理中にカレントディレクトリが変更され、元のディレクトリに戻ることなく関数の処理が終了すると、終了後のログ出力処理でログの出力先は.digdag/tmp/digdag-py-1159889021-1708980813522031538/output.json
となります。関数内で作成し、移動したtmp
フォルダにログファイルが存在するものとして、ログ出力処理を行おうとしてしまうのです。しかし、そこには出力先となるログファイルは存在しないため、No such file or directory
というエラーが発生します。
解決方法
Custom Scriptsではカレントディレクトリを変更しないようにしてください。
import os def output_arg(arg1): print("hello") os.mkdir('tmp') # ディレクトリを作成 ※ カレントディレクトリは変更しない print("world")
やむを得ず変更した場合は必ず元のディレクトリに戻る処理を入れるようにしてください。
いかがでしたでしょうか。手元で実行した時に問題なかったスクリプトでエラーが起こると驚いてしまうと思いますが、ディレクトリ操作をしている際はこの記事を参考に対応いただければ幸いです。