Introduction
ansible.builtin.wait_for pauses playbook execution until a condition is met — a port opens, a file appears, a string shows up in a log, or a process finishes. Essential for deployment orchestration where services take time to start.
Wait for Port
# Wait for service to start listening
- name: Wait for nginx
ansible.builtin.wait_for:
port: 80
timeout: 30
# Wait for remote port
- name: Wait for database
ansible.builtin.wait_for:
host: db.internal
port: 5432
timeout: 60
# Wait for app to start
- name: Wait for application
ansible.builtin.wait_for:
port: 8080
delay: 5 # Wait 5s before first check
timeout: 60 # Give up after 60s
Parameters
| Parameter | Default | Description |
|---|---|---|
port | — | TCP port to check |
host | 127.0.0.1 | Host to check |
timeout | 300 | Max seconds to wait |
delay | 0 | Seconds to wait before first check |
sleep | 1 | Seconds between checks |
state | started | started, stopped, present, absent, drained |
path | — | File path to check |
search_regex | — | Regex to search in file or port output |
msg | — | Custom timeout error message |
connect_timeout | 5 | Connection timeout per check |
exclude_hosts | — | Hosts to exclude (for drained) |
active_connection_states | — | Connection states for drained |
Wait for Port to Close
# Wait for old service to stop
- name: Wait for port 8080 to be free
ansible.builtin.wait_for:
port: 8080
state: stopped
timeout: 30
# Wait for connections to drain before stopping
- name: Wait for connections to drain
ansible.builtin.wait_for:
port: 80
state: drained
timeout: 60
exclude_hosts: 10.0.0.1 # Exclude monitoring
Wait for File
# Wait for file to appear
- name: Wait for lock file to be created
ansible.builtin.wait_for:
path: /tmp/app.lock
state: present
timeout: 30
# Wait for file to be removed
- name: Wait for lock file to be released
ansible.builtin.wait_for:
path: /tmp/app.lock
state: absent
timeout: 120
# Wait for content in file
- name: Wait for app to be ready
ansible.builtin.wait_for:
path: /var/log/myapp/startup.log
search_regex: "Application started"
timeout: 60
Wait for SSH
# Wait for host to be reachable after reboot
- name: Reboot server
ansible.builtin.reboot:
reboot_timeout: 300
# Or manually
- name: Reboot
ansible.builtin.command: shutdown -r now
async: 1
poll: 0
- name: Wait for SSH
ansible.builtin.wait_for:
host: "{{ ansible_host }}"
port: 22
delay: 30
timeout: 300
delegate_to: localhost
# Or use wait_for_connection
- name: Wait for connection
ansible.builtin.wait_for_connection:
delay: 30
timeout: 300
Deployment Patterns
Rolling Deployment
- name: Stop application
ansible.builtin.service:
name: myapp
state: stopped
- name: Wait for port to close
ansible.builtin.wait_for:
port: 8080
state: stopped
timeout: 30
- name: Deploy new version
ansible.builtin.copy:
src: "myapp-{{ version }}.jar"
dest: /opt/myapp/myapp.jar
- name: Start application
ansible.builtin.service:
name: myapp
state: started
- name: Wait for app to be ready
ansible.builtin.wait_for:
port: 8080
delay: 10
timeout: 60
- name: Verify health
ansible.builtin.uri:
url: http://localhost:8080/health
status_code: 200
retries: 5
delay: 5
Database Migration
- name: Wait for database to be available
ansible.builtin.wait_for:
host: "{{ db_host }}"
port: 5432
timeout: 120
- name: Run migrations
ansible.builtin.command: /opt/myapp/migrate.sh
register: migration
- name: Wait for migration log completion
ansible.builtin.wait_for:
path: /var/log/migration.log
search_regex: "Migration complete"
timeout: 300
Multi-Service Startup
- name: Start all services
ansible.builtin.service:
name: "{{ item }}"
state: started
loop:
- redis
- postgresql
- myapp
- name: Wait for all services
ansible.builtin.wait_for:
port: "{{ item.port }}"
delay: 2
timeout: 30
loop:
- { name: redis, port: 6379 }
- { name: postgresql, port: 5432 }
- { name: myapp, port: 8080 }
Troubleshooting
Timeout Too Short
Default is 300s (5 min). Java apps may need more:
- wait_for:
port: 8080
delay: 15 # JVM needs startup time
timeout: 120 # 2 minutes
Checking Remote Port from localhost
Use delegate_to:
- name: Check remote port from controller
ansible.builtin.wait_for:
host: "{{ inventory_hostname }}"
port: 443
timeout: 30
delegate_to: localhost
Related Articles
Conclusion
wait_for bridges the gap between "I started the service" and "the service is actually ready." Always wait for ports after starting services. Use delay for apps with slow startup (Java, databases). Use search_regex to wait for specific log messages. Use state: drained before stopping services in load-balanced environments. It's the glue that makes deployment orchestration reliable.