Ansible 非同期タスクのタイムアウトを修正:"Timeout waiting for async task" と async_status が結果を返さない問題

intermediate🔧 Ansible2026-05-07| Ansible 2.9以降、Linux/Unixリモートホスト全般、長時間実行されるshell/command/yum/aptタスク

Error Message

FAILED! => {"msg": "Timeout (30s) waiting for async task to finish", "finished": 0, "started": 1}
#async#async_status#タイムアウト#poll#長時間タスク

エラーの内容

asyncpoll: 0 を使って長時間かかるタスクを起動し、その後 async_status で結果を収集しようとしました。ところが成功ではなく、次のようなエラーが返ってきます:

FAILED! => {"msg": "Timeout (30s) waiting for async task to finish", "finished": 0, "started": 1}

注目すべき点は "finished": 0 です — async_status が諦めた時点で、タスクはまだ実行中でした。タスク自体は正常に開始されています。ただ、指定した時間より多くの時間が必要だったというわけです。

原因

poll: 0 を指定すると、Ansible はタスクを起動してすぐに次の処理へ移ります。待機は一切しません。その後、async_statusretriesdelay によるループで結果をポーリングします。次のいずれかが発生するとタイムアウトになります:

  • タスクが完了する前に retries × delay の合計時間を使い切ってしまう。
  • async の値が小さすぎる — Ansible はその秒数が経過するとリモートプロセスを強制終了します。

多くのプレイブックで見かける、デフォルトのポーリングループはこちらです。計算してみましょう:10 回 × 3 秒 = 合計 30 秒。短いスクリプトなら問題ありませんが、パッケージのインストールやデータベースのマイグレーション、時間のかかる処理には対応できません。

- async_status:
    jid: "{{ async_result.ansible_job_id }}"
  register: job_result
  until: job_result.finished
  retries: 10
  delay: 3   # 10 × 3 = 合計 30 秒の待機

手順ごとの修正方法

手順 1 — タスクの実際の所要時間を計測する

リモートホストに SSH 接続して、直接時間を計測します:

time apt-get install -y some-large-package
# または
time ./long_migration_script.sh

その数値に 50〜100% のバッファを加えてください。高速なマシンで 3 分かかるタスクが、深夜 2 時の高負荷サーバーでは 6 分かかることもあります。最悪のケースを想定して余裕を持たせましょう。

手順 2 — async を十分に大きな値に設定する

async はリモートホスト上での強制終了タイマーです。指定した秒数が経過すると、Ansible は完了間近であってもプロセスを終了させます。最悪ケースの実行時間を大きく上回る値を設定してください:

- name: 長時間かかるデータベースマイグレーションを実行
  command: /opt/app/migrate.sh
  async: 600      # 最大 10 分を許容
  poll: 0
  register: migration_job

手順 3 — async_status のポーリングループを修正する

retriesdelay の積が async の値以上になるよう調整します:

- name: マイグレーションの完了を待つ
  async_status:
    jid: "{{ migration_job.ansible_job_id }}"
  register: job_result
  until: job_result.finished
  retries: 60     # 最大 60 回チェック
  delay: 10       # 10 秒ごと = 合計 600 秒

ルールはシンプルです:retries × delayasync 以上でなければなりません。ポーリングループが先にタイムアウトすると、リモートホスト上でタスクが正常に動いていてもタイムアウトエラーが発生します。

完全な動作例

---
- hosts: app_servers
  tasks:
    - name: パッケージのアップグレードを実行(長時間タスク)
      apt:
        upgrade: dist
      async: 900        # リモートへの 15 分のハードキャップ
      poll: 0
      register: apt_job

    - name: パッケージのアップグレード完了を待つ
      async_status:
        jid: "{{ apt_job.ansible_job_id }}"
      register: apt_result
      until: apt_result.finished
      retries: 90       # 90 × 10s = 900s — async の値と一致
      delay: 10

    - name: アップグレード結果を表示
      debug:
        var: apt_result

手順 4 — ファイア・アンド・フォーゲットが不要な場合はこれをスキップ

poll: 0 によるファイア・アンド・フォーゲットが有用なのは、複数の長時間タスクを並行して起動したい場合や、遅い処理の実行中に別の作業をしたい場合に限られます。単一の長時間タスクであれば、poll: 0 を削除して Ansible 自身にポーリングを任せましょう:

- name: 組み込みポーリングで長時間タスクを実行
  command: /opt/app/migrate.sh
  async: 600
  poll: 15      # Ansible が 15 秒ごとに確認。async_status は不要

構成がシンプルになり、同じ結果が得られます。

修正の確認

-v オプションを付けて実行すると、ポーリングの状況をリアルタイムで確認できます:

ansible-playbook site.yml -v

タスク実行中は次のような行が表示されます:

ASYNC POLL on host1: jid=..., started=1, finished=0
ASYNC POLL on host1: jid=..., started=1, finished=0
ASYNC OK on host1: jid=..., finished=1, rc=0

finished=1, rc=0 は成功を意味します。まだタイムアウトしている場合は retries を増やして再実行してください。即座にタイムアウトする場合は、async の値がボトルネックになっていないか確認しましょう。

リモートホスト上で直接ジョブを確認することもできます — Ansible は非同期ジョブファイルをここに書き込みます:

ls ~/.ansible_async/
cat ~/.ansible_async/<jid>

クイックリファレンス:async vs poll vs async_status

  • async: N — リモートホスト上の強制終了タイマー。完了の有無にかかわらず、N 秒後にプロセスが終了します。
  • poll: 0 — ファイア・アンド・フォーゲット。async_status を使って結果を収集する責任はユーザーにあります。
  • poll: N(N > 0) — Ansible が N 秒ごとに自動でポーリングします。async_status は不要です。
  • retries × delayasync 以上でなければなりません。そうでないとポーリングループが先にタイムアウトします。

Tips

  • poll: 0 を使うのは、複数の遅いタスクをホスト間で並行実行する場合や、待機中に別の作業をする場合など、本当に並行実行が必要な場面だけにしましょう。それ以外では、組み込みポーリングの方がすっきりします。
  • 非同期タスクを起動した直後にジョブ ID を保存しておきましょう。async_status が実行される前にプレイがクラッシュしても、~/.ansible_async/ の jid を使ってリモートホスト上でジョブを手動確認できます。
  • async_status から "failed": true が返ってきた場合、タイムアウトではありません — タスクは完了しましたが、終了コードがゼロ以外だったということです。実際のエラーは job_result.stderr を確認してください。
  • Ansible Tower / AWX ユーザーへ:Tower には async の値とは別に、Tower 独自のジョブタイムアウト設定があります。リモートの async タイマーが発動する前に Tower がタスクを終了させることがあります。両方とも十分な余裕を持って設定してください。

Related Error Notes