Taskfileのwatchモードで複数コマンド実行が停止する問題の解決方法
この記事では、Taskfile のwatchモードで発生した、複数コマンド実行が途中で停止する問題と、その具体的な解決方法を紹介します。
はじめに
私たちのプロダクト開発(TROCCO/COMETA)では、Taskfileを導入しています。
Taskfileのwatchモードを使ってOpenAPIの定義変更を監視し、面倒なコマンドの手動実行無しでOpenAPIの関連ファイル生成ができるようにしています。
実際には、以下の順序でOpenAPIのファイル生成を自動化しています。
- openapi.jsonの生成(
swagger-cli bundle
コマンド) - TypeScriptのAPIファイル生成(
openapi-generator-cli generate
コマンド)
ディレクトリ構成は以下の通りです。
openapi/
└── internal/
├── openapi.yml # OpenAPIの定義ファイル
├── openapi.json # (1)で生成されるファイル
├── schemas/ # スキーマ定義ファイル
│ └── *.yml
└── paths/ # パス定義ファイル
└── *.yml
frontend/
└── api/
└── *.ts # (2)で生成されるTypeScriptのAPIファイル
実際のTaskfileの設定は以下です。
Taskfile.yml
openapi-internal:
desc: OpenAPI internal tasks
sources:
- openapi/internal/openapi.yml
- openapi/internal/schemas/**
- openapi/internal/paths/**
cmds:
- yarn swagger-cli bundle -r -o internal/openapi.json internal/openapi.yml
- yarn openapi-generator-cli generate
watchモードについての詳細は公式ドキュメントをご覧ください。
以下のように --watch
オプションを付けて実行すると、sources
に指定されたファイル変更を検知してcmdsを自動的に実行します。
$ task openapi-internal --watch
発生していた問題
Taskfileのwatchモードで、最初のコマンド(openapi.jsonの生成)が完了した直後に次のコマンドが突然停止してしまう問題が発生しました。
task: [openapi-internal] yarn swagger-cli validate internal/openapi.json
# ここで停止して進まない...
デバッグモードで原因を調査したところ、以下のログが出力されました。
task: received watch event: WRITE "/home/ubuntu/dev/primenumber-dev/n-transfer-ui/openapi/internal/openapi.json"
task: skipped for file not in sources: openapi/internal/openapi.json
sources
に指定していないファイル(openapi.json)の変更が検知され、処理が中断してしまう状況でした。
問題の原因
Taskfileのwatchモードは、sources
に指定したファイルだけでなく、そのファイルがあるディレクトリ全体を監視しています。そのため、ディレクトリ内での変更を検知すると、即座に現在のタスクを中断してしまう仕様となっています。
詳しくは公式リポジトリの以下の箇所をご覧ください。
今回の問題では、swagger-cli bundle
が openapi/internal/openapi.json
を更新したことで、ディレクトリの変更イベントが発生し、次のコマンドが中断されました。
解決方法
この問題を解決するためには以下の方法が考えられます。
- 一時ファイルを別のディレクトリで生成し、最終成果物のみを監視対象ディレクトリへ移動する。
- 生成ファイルを監視対象外のディレクトリに保存する。
- watch対象ディレクトリをより細かく分割して管理する。
- コマンドを複数並べるのではなく、個別にタスクを分割する。
私たちは最終的に以下のようにタスクを分割することで、問題を回避しました。
openapi-internal-generate-json:
desc: Generate internal openapi.json
sources:
- openapi/internal/openapi.yml
- openapi/internal/schemas/**
- openapi/internal/paths/**
cmds:
- yarn swagger-cli bundle -r -o internal/openapi.json internal/openapi.yml
openapi-internal-codegen:
desc: Generate TypeScript API from openapi.json
sources:
- openapi/internal/openapi.json
cmds:
- yarn openapi-codegen
このようにタスクを明確に分けることで、各タスクが独立し、watchモードが安定して動作します。
おわりに
Taskfileのwatchモードを利用する場合は、sources
で指定したファイルが属するディレクトリ全体が監視対象になることを理解し、適切な設計を行いましょう。
Discussion