Asynchronous Operations
Asynchronous operations and polling can be set using <span>async</span> and <span>poll</span>.
Ansible Ad-Hoc Asynchronous, Concurrent, and Querying
Starting Asynchronous Tasks
[root@awx-1 ansible]# ansible localhost -B 3600 -P 5 -a "sleep 30"
localhost | CHANGED => {
"ansible_job_id": "j445703768934.50473",
"changed": true,
"cmd": [
"sleep",
"30"
],
"delta": "0:00:30.003839",
"end": "2025-04-21 23:31:02.617454",
"finished": 1,
"msg": "",
"rc": 0,
"results_file": "/root/.ansible_async/j445703768934.50473",
"start": "2025-04-21 23:30:32.613615",
"started": 1,
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
- •
<span>-B</span>: Sets the timeout duration - •
<span>-P</span>: Polling interval for background task execution - • When the value is not 0, the task runs in the background, but the foreground does not exit, periodically checking the results
- • When the value is 0, the foreground will also exit, and the subsequent status can be queried using
<span>ansible.builtin.async_status</span>module
Ansible executes synchronously by default. The following table compares synchronous and asynchronous execution:
| Feature | Default (Foreground Connection) | Async Mode (Background Running) |
| Is SSH connection maintained | ✅ Always maintained | ❌ Disconnects immediately after executing the command |
| Does the control node block | ✅ Yes | ❌ Does not block, returns immediately |
| Does it occupy connection resources | ✅ Yes | ❌ No |
| Is it suitable for long tasks | ❌ Prone to timeout and failure | ✅ Very suitable |
| Can status be queried midway | ❌ No | ✅ Can query using <span>async_status</span> |
When using asynchronous task execution, you can increase the number of concurrently executed hosts by using
<span>--forks</span>.
Starting Concurrent Tasks
<span>-p</span> set to 0 makes the task a concurrent task.
[root@awx-1 ansible]# ansible localhost -B 3600 -P 0 -a "sleep 30"
localhost | CHANGED => {
"ansible_job_id": "j100035338039.50544",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/j100035338039.50544",
"started": 1
}
Querying Asynchronous Task Information
When the <span>-P</span> parameter is 0, the task runs completely in the background, and you need to query using the <span>ansible.builtin.async_status</span> module:
<span>ansible.builtin.async_status</span>is introduced later.
# Start an asynchronous task
[root@awx-1 ansible]# ansible localhost -B 3600 -P 0 -a "sleep 30"
localhost | CHANGED => {
"ansible_job_id": "j594674720907.50900",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/j594674720907.50900",
"started": 1
}
# Query results
[root@awx-1 ansible]# ansible localhost -m ansible.builtin.async_status -a "jid=j594674720907.50900"
localhost | CHANGED => {
"ansible_job_id": "j594674720907.50900",
"changed": true,
"cmd": [
"sleep",
"30"
],
"delta": "0:00:30.004651",
"end": "2025-04-21 23:54:24.838790",
"finished": 1,
"msg": "",
"rc": 0,
"results_file": "/root/.ansible_async/j594674720907.50900",
"start": "2025-04-21 23:53:54.834139",
"started": 1,
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
# Clean up cache files
[root@awx-1 ansible]# ansible localhost -m ansible.builtin.async_status -a "jid=j594674720907.50900 mode=cleanup"
localhost | SUCCESS => {
"ansible_job_id": "j594674720907.50900",
"changed": false,
"erased": "/root/.ansible_async/j594674720907.50900",
"finished": 0,
"started": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
Asynchronous, Concurrent, and Polling in Playbooks
Asynchronous Playbook Tasks
To set tasks for asynchronous execution, add <span>async</span> and <span>poll</span> in the corresponding Play (note the timeout duration)
- name: sleep 30
ansible.builtin.command: sleep 30
poll: 5
async: 300
Partial execution results:
TASK [sleep 30] **********************************************************************
ASYNC POLL on localhost: jid=j503432663133.51123 started=1 finished=0
ASYNC POLL on localhost: jid=j503432663133.51123 started=1 finished=0
ASYNC POLL on localhost: jid=j503432663133.51123 started=1 finished=0
ASYNC POLL on localhost: jid=j503432663133.51123 started=1 finished=0
ASYNC POLL on localhost: jid=j503432663133.51123 started=1 finished=0
ASYNC OK on localhost: jid=j503432663133.51123
changed: [localhost]
<span>async</span>has no default value, while<span>poll</span>defaults to 15s.
Concurrent Playbook Tasks
When <span>poll</span> is set to 0, the task is a concurrent task:
- name: sleep 30
ansible.builtin.command: sleep 30
poll: 0
async: 300
Here is an example:
root@awx-1 ansible]# ansible-playbook test.yml
PLAY [test] *******************************************************************************************************************
TASK [sleep 30] ***************************************************************************************************************
changed: [localhost]
PLAY RECAP ********************************************************************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@awx-1 ansible]# ps -ef | grep sleep
root 51246 51245 0 00:02 ? 00:00:00 sleep 30
root 51248 46905 0 00:02 pts/2 00:00:00 grep --color=auto sleep
You can see that the Playbook has already finished, but the <span>sleep 30</span> process is still running.
Polling for Concurrent Tasks
ansible.builtin.async_status
When discussing polling for concurrent tasks, we must mention the <span>ansible.builtin.async_status</span> module, which is used to query the status of tasks.
| Parameter Name | Type | Default Value | Description |
<span>jid</span> |
<span>str</span> |
None | Required Parameter. The job ID of the asynchronous task to query, obtained from the previous task result <span>.ansible_async</span>. |
<span>mode</span> |
<span>str</span> |
<span>status</span> |
Optional values:<span>status</span> or <span>cleanup</span>.– <span>status</span>: Default, queries task status;– <span>cleanup</span>: Used to clean up task status files. |
- name: Asynchronous yum task
ansible.builtin.yum:
name: docker-io
state: present
async: 1000
poll: 0
register: yum_sleeper
- name: Wait for asynchronous job to end
ansible.builtin.async_status:
jid: '{{ yum_sleeper.ansible_job_id }}'
register: job_result
until: job_result.finished
retries: 100
delay: 10
- name: Clean up async file
ansible.builtin.async_status:
jid: '{{ yum_sleeper.ansible_job_id }}'
mode: cleanup
- •
<span>async</span>: Asynchronous timeout duration - •
<span>poll</span>: Interval for querying task results; when set to 0, it does not query task results, meaning the task runs in the background, and the foreground result ends directly - •
<span>register</span>: Registers the current Play result as a variable for use in subsequent Plays - •
<span>until</span>: The task ends when the condition is met - •
<span>delay</span>: Task retry interval - •
<span>retries</span>: Number of task retries
Let’s discuss the logic of using this module:
- 1.
<span>Asynchronous yum task</span>Play is used to install the<span>docker-io</span>package, with a timeout of 1000s, executed concurrently. Finally, the task registers a variable named<span>yum_sleeper</span>, which has a sub-variable named<span>ansible_job_id</span>, which is the task ID; - 2.
<span>Wait for asynchronous job to end</span>Play uses the task ID obtained from the previously registered variable to query every 10s, with a maximum of 100 retries. It registers a variable named<span>job_result</span>, which has a sub-variable<span>finished</span>; when<span>finished</span>is 1, the task execution is complete; - 3.
<span>Clean up async file</span>Play is used to clean up cache files.
Note the value of
<span>async</span>; if the value is not high enough, it may cause the task to timeout and exit.If you want to set options like
<span>changed_when</span>or<span>creates</span>, you need to set them for the<span>ansible.builtin.async_status</span>.