AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible Async: Run Long-Running Tasks in Background (Complete Guide)

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

Complete guide to Ansible async and poll. Run long-running tasks in the background, implement fire-and-forget patterns, parallel execution, check job status.

The async keyword runs Ansible tasks in the background, allowing long-running operations to continue without blocking the playbook. Combined with poll, it enables fire-and-forget patterns, parallel execution, and timeout control.

How Async Works

- name: Long-running task
  ansible.builtin.command: /opt/scripts/build.sh
  async: 3600    # Maximum runtime in seconds (1 hour)
  poll: 10       # Check every 10 seconds
async: N — Maximum allowed runtime in seconds. Task fails if it exceeds this. • poll: N — How often (seconds) to check if the task is done. • poll: 0 = Fire and forget (don't wait) • poll: N (N > 0) = Wait and check every N seconds

See also: Ansible Run Playbooks in Parallel: Async, Forks & Concurrent Execution

Basic Patterns

Wait with Polling (Default)

# Runs in background, checks every 30 seconds, max 1 hour
- name: Run database backup
  ansible.builtin.command: /opt/scripts/backup-database.sh
  async: 3600
  poll: 30

Fire and Forget

# Start task and move on immediately
- name: Start long-running data migration
  ansible.builtin.command: /opt/scripts/migrate-data.sh
  async: 7200
  poll: 0
  register: migration_job

# ... other tasks run while migration continues ...

# Check status later - name: Check migration status ansible.builtin.async_status: jid: "{{ migration_job.ansible_job_id }}" register: job_result until: job_result.finished retries: 120 delay: 60

Parallel Execution

Run Tasks on Multiple Hosts Simultaneously

# Fire and forget on all hosts, then wait for all to finish
- name: Start package update on all hosts
  ansible.builtin.yum:
    name: '*'
    state: latest
  async: 1800
  poll: 0
  register: yum_update

- name: Wait for updates to complete ansible.builtin.async_status: jid: "{{ yum_update.ansible_job_id }}" register: job_result until: job_result.finished retries: 60 delay: 30

Parallel Tasks on Same Host

# Start multiple independent tasks
- name: Download large file 1
  ansible.builtin.get_url:
    url: https://example.com/large-file-1.tar.gz
    dest: /tmp/file1.tar.gz
  async: 600
  poll: 0
  register: download1

- name: Download large file 2 ansible.builtin.get_url: url: https://example.com/large-file-2.tar.gz dest: /tmp/file2.tar.gz async: 600 poll: 0 register: download2

- name: Start compilation ansible.builtin.command: make -j4 args: chdir: /opt/source async: 1800 poll: 0 register: compile_job

# Wait for all to finish - name: Wait for downloads and compilation ansible.builtin.async_status: jid: "{{ item.ansible_job_id }}" register: async_results until: async_results.finished retries: 60 delay: 15 loop: - "{{ download1 }}" - "{{ download2 }}" - "{{ compile_job }}"

See also: Ansible async and poll: Run Long Tasks Without Timeout Complete Guide

async_status Module

Check on fire-and-forget jobs:

- name: Start background job
  ansible.builtin.command: /opt/scripts/process.sh
  async: 3600
  poll: 0
  register: bg_job

- name: Do other work ansible.builtin.debug: msg: "Doing other tasks while job runs..."

- name: Check job status ansible.builtin.async_status: jid: "{{ bg_job.ansible_job_id }}" register: job_status

- name: Show status ansible.builtin.debug: msg: | Finished: {{ job_status.finished }} Started: {{ job_status.started }} {% if job_status.finished %} Return code: {{ job_status.rc }} {% endif %}

# Wait until complete - name: Wait for job to finish ansible.builtin.async_status: jid: "{{ bg_job.ansible_job_id }}" register: job_result until: job_result.finished retries: 60 delay: 30 # Checks every 30 seconds, up to 30 minutes

Real-World Patterns

Long Package Updates Without SSH Timeout

# SSH connections may time out during long operations
# async keeps the task running server-side even if SSH disconnects
- name: Upgrade all packages (may take 30+ minutes)
  ansible.builtin.yum:
    name: '*'
    state: latest
  async: 3600    # Allow up to 1 hour
  poll: 60       # Check every minute

Parallel Service Restarts

- name: Restart services in parallel
  ansible.builtin.systemd:
    name: "{{ item }}"
    state: restarted
  async: 120
  poll: 0
  register: restart_jobs
  loop:
    - nginx
    - php-fpm
    - redis

- name: Wait for all restarts ansible.builtin.async_status: jid: "{{ item.ansible_job_id }}" register: restart_results until: restart_results.finished retries: 12 delay: 10 loop: "{{ restart_jobs.results }}"

Reboot and Reconnect

- name: Reboot the server
  ansible.builtin.command: shutdown -r now
  async: 1
  poll: 0
  ignore_errors: true

- name: Wait for server to come back ansible.builtin.wait_for_connection: connect_timeout: 10 sleep: 5 delay: 30 timeout: 300

Background Monitoring During Deployment

- name: Start log monitoring in background
  ansible.builtin.shell: "tail -f /var/log/myapp/app.log > /tmp/deploy-log.txt 2>&1 &"
  async: 600
  poll: 0
  register: monitor

- name: Deploy application ansible.builtin.include_role: name: deploy

- name: Stop monitoring ansible.builtin.command: "kill $(cat /tmp/deploy-monitor.pid)" ignore_errors: true

- name: Show deployment logs ansible.builtin.command: cat /tmp/deploy-log.txt register: deploy_logs changed_when: false

- name: Display logs ansible.builtin.debug: var: deploy_logs.stdout_lines

See also: Ansible Jinja2 Filters: Transform Data in Playbooks (Complete Reference)

Timeout Handling

# Task fails if it exceeds async timeout
- name: Process with timeout
  ansible.builtin.command: /opt/scripts/process.sh
  async: 300    # 5 minute maximum
  poll: 10
  register: result
  ignore_errors: true

- name: Handle timeout ansible.builtin.debug: msg: "Process timed out — cleaning up" when: result is failed

- name: Cleanup on timeout ansible.builtin.command: /opt/scripts/cleanup.sh when: result is failed

Limitations

Not all modules support async — Modules that need persistent connections (e.g., synchronize) may not work No async with with_items/loop — Each loop iteration runs sequentially; use fire-and-forget + async_status loop instead Temp files on remote hosts — Async creates ~/.ansible_async/ files that need cleanup become may not work with poll: 0 — Some privilege escalation methods conflict with backgrounding

FAQ

What does async do in Ansible?

async runs a task in the background with a maximum time limit. It prevents SSH timeouts for long operations and enables fire-and-forget patterns where you start a task and check its status later.

What is the difference between async with poll 0 and poll N?

poll: 0 (fire-and-forget) starts the task and immediately continues to the next task. poll: N (N > 0) starts the task and waits, checking every N seconds until it completes.

How do I run tasks in parallel with Ansible?

Use async with poll: 0 to start multiple tasks without waiting, then use async_status in a loop to wait for all jobs to complete. This runs tasks concurrently instead of sequentially.

What happens when an async task times out?

The task is killed on the remote host and Ansible reports a failure. Use ignore_errors: true if you want to handle timeouts gracefully with cleanup tasks.

Can I use async with loops?

Not directly — each loop iteration is still sequential. Instead, use poll: 0 inside the loop to start all iterations as fire-and-forget jobs, then use async_status with a second loop to wait for all results.

Conclusion

async: N + poll: M — Run with timeout, check every M seconds • async: N + poll: 0 — Fire and forget, check later with async_statusPrevents SSH timeouts for long operations • Enables parallel execution with fire-and-forget + async_status loops • Always set a reasonable async timeout to avoid zombie tasks

Related Articles

Ansible retries & until: Retry Failed TasksAnsible wait_for: Wait for ConditionsAnsible serial: Rolling Updates GuideAnsible Run Playbooks in Parallel

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home