Ansible wait_for Module: Wait for Conditions, Ports & Files (Guide)
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
Complete guide to Ansible wait_for module. Wait for ports to open, files to appear, services to start, connections to drain, and processes to finish.
The ansible.builtin.wait_for module pauses playbook execution until a specified condition is met — a port is open, a file exists, a string appears in a file, or connections drain. It's essential for service readiness checks, deployment orchestration, and handling reboots.
Wait for a Port
Port to Open (Service Ready)
- name: Start application
ansible.builtin.systemd:
name: myapp
state: started
- name: Wait for app to listen on port 8080
ansible.builtin.wait_for:
port: 8080
delay: 5 # Wait 5s before first check
timeout: 60 # Fail after 60s
- name: Wait for remote port
ansible.builtin.wait_for:
host: db.example.com
port: 5432
timeout: 120Port to Close (Connections Drained)
- name: Stop accepting new connections
ansible.builtin.command: /opt/app/drain.sh
- name: Wait for all connections to close
ansible.builtin.wait_for:
port: 8080
state: drained
timeout: 120Wait for Port After Restart
- name: Restart service
ansible.builtin.systemd:
name: myapp
state: restarted
- name: Wait for service to be ready
ansible.builtin.wait_for:
port: "{{ app_port }}"
delay: 3
timeout: 30See also: Ansible 2.17.0-rc1: Elevating Automation with ‘Gallows Pole’
Wait for a File
File to Exist
- name: Start background job
ansible.builtin.command: /opt/batch/run.sh &
- name: Wait for output file
ansible.builtin.wait_for:
path: /opt/batch/output/results.csv
timeout: 300File to Contain a String
- name: Start application
ansible.builtin.systemd:
name: myapp
state: started
- name: Wait for "Server started" in log
ansible.builtin.wait_for:
path: /var/log/myapp/app.log
search_regex: "Server started on port"
timeout: 60
# Wait for specific pattern
- name: Wait for database migration complete
ansible.builtin.wait_for:
path: /var/log/myapp/migrate.log
search_regex: "Migrations complete|Already up to date"
timeout: 120File to Be Absent
- name: Wait for lock file to be removed
ansible.builtin.wait_for:
path: /var/run/myapp.lock
state: absent
timeout: 60Wait for Connection (After Reboot)
wait_for_connection is purpose-built for reconnecting after reboots:
- name: Reboot server
ansible.builtin.reboot:
reboot_timeout: 300
# Or manually:
- name: Reboot server
ansible.builtin.command: shutdown -r now
async: 1
poll: 0
- name: Wait for server to come back
ansible.builtin.wait_for_connection:
connect_timeout: 10
sleep: 5
delay: 30 # Don't start checking for 30s
timeout: 300See also: Ansible Development: Write Custom Modules, Plugins & Collections
Real-World Patterns
Rolling Deployment with Health Checks
- hosts: webservers
serial: 1
tasks:
- name: Remove from load balancer
ansible.builtin.command: "lb-ctl drain {{ inventory_hostname }}"
delegate_to: "{{ lb_host }}"
- name: Wait for connections to drain
ansible.builtin.wait_for:
port: 8080
state: drained
timeout: 60
- name: Deploy new version
ansible.builtin.include_role:
name: deploy
- name: Wait for application to start
ansible.builtin.wait_for:
port: 8080
delay: 5
timeout: 30
- name: Wait for health endpoint
ansible.builtin.uri:
url: "http://localhost:8080/health"
register: health
retries: 10
delay: 5
until: health.status == 200
- name: Re-enable in load balancer
ansible.builtin.command: "lb-ctl enable {{ inventory_hostname }}"
delegate_to: "{{ lb_host }}"Database Startup Chain
- name: Start PostgreSQL
ansible.builtin.systemd:
name: postgresql
state: started
- name: Wait for PostgreSQL to accept connections
ansible.builtin.wait_for:
port: 5432
delay: 2
timeout: 30
- name: Start Redis
ansible.builtin.systemd:
name: redis
state: started
- name: Wait for Redis
ansible.builtin.wait_for:
port: 6379
timeout: 15
- name: Start application (depends on DB + Redis)
ansible.builtin.systemd:
name: myapp
state: started
- name: Wait for app health check
ansible.builtin.wait_for:
port: 8080
delay: 5
timeout: 60Wait for Cloud Instance
- name: Create EC2 instance
amazon.aws.ec2_instance:
name: webserver
instance_type: t3.medium
image_id: "{{ ami_id }}"
register: ec2
- name: Wait for SSH to be ready
ansible.builtin.wait_for:
host: "{{ ec2.instances[0].public_ip_address }}"
port: 22
delay: 10
timeout: 300
delegate_to: localhostParameters Reference
| Parameter | Description | Default |
|---|---|---|
port | Port number to check | — |
host | Host to check | 127.0.0.1 |
path | File path to check | — |
state | started, stopped, present, absent, drained | started |
delay | Seconds to wait before first check | 0 |
timeout | Seconds before giving up | 300 |
sleep | Seconds between checks | 1 |
search_regex | Regex to match in file | — |
exclude_hosts | Hosts to ignore for drained | — |
connect_timeout | Seconds for each connection attempt | 5 |
msg | Custom failure message | — |
FAQ
What does wait_for do in Ansible?
The wait_for module pauses playbook execution until a specified condition is met: a TCP port opens, a file appears/disappears, or a regex pattern is found in a file. It's used to wait for services to start, connections to drain, or processes to complete.
What is the difference between wait_for and wait_for_connection?
wait_for checks for ports, files, or strings on target hosts. wait_for_connection specifically waits for Ansible to be able to connect (SSH/WinRM) to a host — designed for use after reboots.
How do I wait for a service to be ready?
Use wait_for with the service port: wait_for: port=8080 delay=5 timeout=60. For HTTP health checks, use the uri module with retries and until instead.
What happens when wait_for times out?
The task fails with a timeout error and the playbook stops (unless ignore_errors: true is set). Use the msg parameter to provide a helpful failure message.
Can I wait for multiple conditions?
Not in a single task. Use separate wait_for tasks for each condition, or use ansible.builtin.async with poll: 0 to check multiple conditions in parallel.
See also: Ansible Delete File & Remove File: file Module absent State Guide
Conclusion
- Port checks:
port: 8080withstate: started(open) ordrained(closed) - File checks:
path:withstate: present/absentorsearch_regex - After reboots: Use
wait_for_connectioninstead - Always set
timeout— don't let tasks hang forever - Use
delayto skip the initial startup period
Related Articles
Category: troubleshooting