Summary
When the target host experiences slow disk IO (>2.5s), async tasks fail with a 30-minute timeout instead of a clear error. The root cause is a race condition in async_wrapper.py involving three defects:
- IPC pipe timeout is hardcoded to 2.5s (25 × 0.1s), insufficient for slow IO environments
- ipc_notifier.send(True) in _run_module() is not protected by try-except, causing BrokenPipeError crash when the grandparent exits
- Watcher does not write failure result when worker crashes, leaving job file with finished:0 forever
Issue Type
Bug Report
Component Name
!component lib/ansible/plugins/action/async_wrapper.py
Ansible Version
ansible [core 2.15.13]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/opt/ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /opt/ansible/lib64/python3.11/site-packages/ansible
ansible collection location = /opt/ansible/collections:/usr/share/ansible/collections
executable location = /opt/ansible/bin/ansible
python version = 3.11.6 (main, Aug 1 2026, 13:00:29) [GCC 12.3.1 (openEuler 12.3.1-62.r4.hce3)] (/opt/ansible/bin/python)
jinja version = 3.1.3
libyaml = True
Configuration
ansible-config dump --only-changed -t all
ANSIBLE_HOME(env: ANSIBLE_HOME) = /opt/ansible
CACHE_PLUGIN(/etc/ansible/ansible.cfg) = memory
CONFIG_FILE() = /etc/ansible/ansible.cfg
DEFAULT_FORKS(/etc/ansible/ansible.cfg) = 10
DEFAULT_GATHERING(/etc/ansible/ansible.cfg) = smart
DEFAULT_HOST_LIST(/etc/ansible/ansible.cfg) = ['/etc/ansible/hosts']
DEFAULT_LOG_FILTER(/etc/ansible/ansible.cfg) = ['paramiko.transport']
DEFAULT_MANAGED_STR(/etc/ansible/ansible.cfg) = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}
DEFAULT_NO_TARGET_SYSLOG(/etc/ansible/ansible.cfg) = True
DEFAULT_POLL_INTERVAL(/etc/ansible/ansible.cfg) = 15
DEFAULT_TIMEOUT(/etc/ansible/ansible.cfg) = 60
DEFAULT_TRANSPORT(/etc/ansible/ansible.cfg) = paramiko
DEPRECATION_WARNINGS(/etc/ansible/ansible.cfg) = False
HOST_KEY_CHECKING(/etc/ansible/ansible.cfg) = False
INTERPRETER_PYTHON(/etc/ansible/ansible.cfg) = auto_legacy_silent
PARAMIKO_HOST_KEY_AUTO_ADD(/etc/ansible/ansible.cfg) = True
PARAMIKO_LOOK_FOR_KEYS(/etc/ansible/ansible.cfg) = False
RETRY_FILES_ENABLED(/etc/ansible/ansible.cfg) = True
SYSTEM_WARNINGS(/etc/ansible/ansible.cfg) = False
CONNECTION:
==========
maglev:
______
timeout(/etc/ansible/ansible.cfg) = 60
paramiko_ssh:
____________
host_key_auto_add(/etc/ansible/ansible.cfg) = True
host_key_checking(/etc/ansible/ansible.cfg) = False
look_for_keys(/etc/ansible/ansible.cfg) = False
ssh_args(/etc/ansible/ansible.cfg) = -C -o ControlMaster=auto -o ControlPersist=1800s
timeout(/etc/ansible/ansible.cfg) = 60
ssh:
___
host_key_checking(/etc/ansible/ansible.cfg) = False
pipelining(/etc/ansible/ansible.cfg) = True
scp_if_ssh(/etc/ansible/ansible.cfg) = smart
ssh_args(/etc/ansible/ansible.cfg) = -C -o ControlMaster=auto -o ControlPersist=1800s
timeout(/etc/ansible/ansible.cfg) = 60
SHELL:
=====
sh:
__
remote_tmp(/etc/ansible/ansible.cfg) = ~/.ansible/tmp
OS / Environment
Euerle R13 x86
Steps to Reproduce
-
On the target host, create heavy IO load to simulate slow disk: dd if=/dev/zero of=/tmp/bigfile bs=1M count=4096 oflag=dsync &
-
Run an async task playbook:
- name: test async task
command: sleep 5
async: 1800
poll: 30
-
Under slow IO condition, the async task may time out after 1800 seconds instead of completing normally.
This is a race condition that is hard to reproduce reliably. However,the root cause can be verified by code analysis of async_wrapper.py (see the three defects described in the issue body).
Production log evidence is provided in the issue body showing the exact sequence: grandparent IPC timeout → worker BrokenPipeError → watcher not writing failure result → 30-minute poll timeout.
Expected Results
Even when slow IO occurs, the async task should:
- Worker continues to execute the module regardless of whether the IPC signal was sent successfully
- If worker crashes, watcher should write a failure result to the job file so that poll can detect the failure promptly
- Poll should not blindly wait until the async timeout (1800s) when the worker has already exited abnormally
Actual Results
The async task timed out after 1800 seconds with no clear error.
Production logs from the target host:
19:02:18 ansible-async_wrapper.py[198128]: Invoked with j7332449673 1800 /root/.ansible/tmp/ansible-tmp-xxx/AnsiballZ_command.py _
19:02:18 ansible-async_wrapper.py[198132]: Starting module and watcher
19:02:18 ansible-async_wrapper.py[198132]: Start watching [198133] (1800)
19:02:18 ansible-async_wrapper.py[198133]: Start module [198133]
19:02:21 ansible-async_wrapper.py[198128]: Return async_wrapper task started.
19:02:23 kernel: Slow IO detected: python3.11-198133 vda stage bio RM 16795136 + 0 cgroup /system.slice/crond.service started 4672 ms ago threshold 1000 ms
19:02:23 ansible-async_wrapper.py[198133]: error: [Errno 32] Broken pipe
19:02:23 ansible-async_wrapper.py[198132]: Done in kid B.
The job file stayed at {"started":1, "finished":0} and poll
kept waiting until the 1800s async timeout.
Code of Conduct
Summary
When the target host experiences slow disk IO (>2.5s), async tasks fail with a 30-minute timeout instead of a clear error. The root cause is a race condition in async_wrapper.py involving three defects:
Issue Type
Bug Report
Component Name
!component lib/ansible/plugins/action/async_wrapper.py
Ansible Version
Configuration
OS / Environment
Euerle R13 x86
Steps to Reproduce
On the target host, create heavy IO load to simulate slow disk: dd if=/dev/zero of=/tmp/bigfile bs=1M count=4096 oflag=dsync &
Run an async task playbook:
command: sleep 5
async: 1800
poll: 30
Under slow IO condition, the async task may time out after 1800 seconds instead of completing normally.
This is a race condition that is hard to reproduce reliably. However,the root cause can be verified by code analysis of async_wrapper.py (see the three defects described in the issue body).
Production log evidence is provided in the issue body showing the exact sequence: grandparent IPC timeout → worker BrokenPipeError → watcher not writing failure result → 30-minute poll timeout.
Expected Results
Even when slow IO occurs, the async task should:
Actual Results
Code of Conduct