async_status
A poll: 0 task starts something and moves on without waiting — which raises an obvious question: how do you ever find out whether it actually finished, and how it went? This chapter covers checking back in, and a genuinely practical pattern built around it.
Capturing The Job ID
A poll: 0 task’s registered result includes a job ID, needed to check on it later:
- name: Start a long job
ansible.builtin.command: /usr/local/bin/long-running-task.sh
async: 3600
poll: 0
register: job_resultasync_status: Checking In Later
- name: Check whether the job has finished
ansible.builtin.async_status:
jid: "{{ job_result.ansible_job_id }}"
register: job_status
until: job_status.finished
retries: 30
delay: 10until/retries/delay, exactly from the loops section’s retry pattern, applied here to poll a fire-and-forget job’s completion rather than a health-check endpoint — the same underlying idea, a genuinely different use case.
A Realistic Pattern: Multiple Independent Jobs, Checked Together
The real payoff of poll: 0 — starting several genuinely independent long jobs across different hosts, doing other useful work in the meantime, then circling back to confirm they all finished:
- name: Start long jobs on every host
ansible.builtin.command: /usr/local/bin/long-running-task.sh
async: 3600
poll: 0
register: job_result
- name: Do other unrelated work while those jobs run
ansible.builtin.debug:
msg: "Doing other setup work in the meantime"
- name: Wait for every host's job to finish
ansible.builtin.async_status:
jid: "{{ job_result.ansible_job_id }}"
register: job_status
until: job_status.finished
retries: 30
delay: 10Every host’s long job runs concurrently, in the background, while the play moves on to genuinely unrelated work — only circling back to actually wait once there’s nothing else productive left to do in the meantime.
A Gotcha: Not Every Module Supports async
Some modules — particularly ones involving interactive prompts, or certain connection-plugin-specific behaviors — don’t support async at all, and using it against one either has no effect or produces a confusing error rather than the behavior you’d expect. If a module you’re trying to run asynchronously doesn’t seem to be behaving as documented here, checking that module’s own documentation for async support is the first thing worth confirming, before assuming something else is wrong.
Best Practices
- Always register a
poll: 0task’s result — without the job ID it captures, there’s no way to check on that job again later at all. - Use
async_statuswithuntil/retries/delay, exactly the loops section’s retry pattern, rather than a single one-shot status check that might catch the job mid-run. - Use the fire-and-forget pattern specifically when there’s genuinely other useful work to do while a long job runs — starting several jobs and immediately waiting on all of them one at a time defeats the purpose; the benefit comes from doing something else productive in between.
- Confirm a module actually supports
asyncbefore relying on it, rather than assuming universal support.