Treasure Data - Support Engineering Team blog

トレジャーデータのサポートエンジニアリングチームのブログです。

CustomScriptsの実行中、No such file or directory(digdagのファイルが存在しない)エラーが生じる

こんにちは。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タブでエラーの詳細を確認してみます。

WORKFLOW LOGSタブのエラー出力例(画像)
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")

やむを得ず変更した場合は必ず元のディレクトリに戻る処理を入れるようにしてください。

いかがでしたでしょうか。手元で実行した時に問題なかったスクリプトでエラーが起こると驚いてしまうと思いますが、ディレクトリ操作をしている際はこの記事を参考に対応いただければ幸いです。 success_image