🔥

Taskfileのwatchモードで複数コマンド実行が停止する問題の解決方法

この記事では、Taskfile のwatchモードで発生した、複数コマンド実行が途中で停止する問題と、その具体的な解決方法を紹介します。

はじめに

私たちのプロダクト開発(TROCCO/COMETA)では、Taskfileを導入しています。

Taskfileのwatchモードを使ってOpenAPIの定義変更を監視し、面倒なコマンドの手動実行無しでOpenAPIの関連ファイル生成ができるようにしています。

実際には、以下の順序でOpenAPIのファイル生成を自動化しています。

  1. openapi.jsonの生成(swagger-cli bundleコマンド)
  2. 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 bundleopenapi/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で指定したファイルが属するディレクトリ全体が監視対象になることを理解し、適切な設計を行いましょう。

株式会社primeNumber

Discussion