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: 120
Port 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: 120
Wait 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: 30
See 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: 300
File 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: 120
File to Be Absent
- name: Wait for lock file to be removed
ansible.builtin.wait_for:
path: /var/run/myapp.lock
state: absent
timeout: 60
Wait 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: 300
See 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: 60
Wait 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: localhost
Parameters 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 | — |
See also: Ansible Delete File & Remove File: file Module absent State Guide
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.
Conclusion
• Port checks:port: 8080 with state: started (open) or drained (closed)
• File checks: path: with state: present/absent or search_regex
• After reboots: Use wait_for_connection instead
• Always set timeout — don't let tasks hang forever
• Use delay to skip the initial startup period
Related Articles
• Ansible retries & until: Retry Failed Tasks • Ansible delegate_to: Run Tasks on Different Hosts • Ansible systemd Module: Manage ServicesCategory: troubleshooting