Ansible Multiple Handlers: Run Handlers in Sequence (listen, notify)
By Luca Berton · Published 2024-01-01 · Category: installation
How to run multiple Ansible handlers from a single task. Use listen groups and multiple notify entries to chain handler execution with practical examples.

Two ways to run multiple Ansible handlers
How to execute two Ansible handlers on a changed status of Ansible Playbook.
See also: Ansible Handlers Explained: How to Use and Flush Handlers
What is an Ansible handler?
> Handler runs tasks on change.
Handlers execute some tasks only when the previous task returns a changed status. If not necessary, they don't execute.
Links
• https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.htmlSee also: Ansible ansible.builtin vs ansible.legacy: Collection Namespaces Explained
Demo
Let's jump into two real-life examples of how to run multiple Ansible handlers. First of all, we need a task changed status. The simplest Ansible module returning a "changed" status is the command module with a Linux command, like "uptime". Let's suppose we would like to execute two handlers on the screen, for example, two messages on the screen.
Solution 1
code
• two-1.yml---
- name: handler Playbook
hosts: all
tasks:
- name: Test connection
ansible.builtin.command: "uptime"
notify: message
handlers:
- name: message 1
ansible.builtin.debug:
msg: message 1
listen: message
- name: message 2
ansible.builtin.debug:
msg: message 2
listen: message
• inventory
localhost ansible_connection=local
See also: Ansible troubleshooting - VMware Unknown error while connecting to vCenter or ESXi
execution
$ ansible-playbook -i inventory two-1.yml
PLAY [handler Playbook] *********************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [localhost]
TASK [Test connection] ******************************************************************
changed: [localhost]
RUNNING HANDLER [message 1] *************************************************************
ok: [localhost] => {
"msg": "message 1"
}
RUNNING HANDLER [message 2] *************************************************************
ok: [localhost] => {
"msg": "message 2"
}
PLAY RECAP ******************************************************************************
localhost : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Solution 2
code
• two-2.yml---
- name: handler Playbook
hosts: all
tasks:
- name: Test connection
ansible.builtin.command: "uptime"
notify:
- message 1
- message 2
handlers:
- name: message 1
ansible.builtin.debug:
msg: message 1
- name: message 2
ansible.builtin.debug:
msg: message 2
execution
$ ansible-playbook -i inventory two-1.yml
PLAY [handler Playbook] *********************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [localhost]
TASK [Test connection] ******************************************************************
changed: [localhost]
RUNNING HANDLER [message 1] *************************************************************
ok: [localhost] => {
"msg": "message 1"
}
RUNNING HANDLER [message 2] *************************************************************
ok: [localhost] => {
"msg": "message 2"
}
PLAY RECAP ******************************************************************************
localhost : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
PLAY [handler Playbook] *********************************************************************
Conclusion
Now you know Two ways to run multiple Ansible handlers.Method 1: Multiple notify entries
tasks:
- name: Update nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Validate nginx config
- Restart nginx
handlers:
- name: Validate nginx config
ansible.builtin.command: nginx -t
changed_when: false
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
Method 2: listen groups (recommended)
tasks:
- name: Update nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart web stack
handlers:
- name: Validate config
ansible.builtin.command: nginx -t
listen: restart web stack
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
listen: restart web stack
- name: Clear cache
ansible.builtin.file:
path: /var/cache/nginx
state: absent
listen: restart web stack
Handler Rules
| Rule | Description | |------|-------------| | Run once | Even if notified multiple times | | End of play | Run after all tasks, not after each | | Order | Run in order defined, not notified | | Conditional | Only if notified (something changed) |
Force handlers mid-play
- name: Update config
template:
src: config.j2
dest: /etc/myapp/config.yml
notify: restart myapp
- meta: flush_handlers # Runs handlers NOW
- name: Verify service
uri:
url: http://localhost:8080/health
Chained Handlers
handlers:
- name: Validate config
command: nginx -t
notify: Reload nginx # Only reloads if validation passes
- name: Reload nginx
service:
name: nginx
state: reloaded
Deployment Pattern
tasks:
- name: Deploy code
ansible.builtin.git:
repo: https://github.com/myorg/myapp.git
dest: /opt/myapp
notify: deploy application
handlers:
- name: Install deps
command: pip install -r requirements.txt
args:
chdir: /opt/myapp
listen: deploy application
- name: Run migrations
command: python manage.py migrate
args:
chdir: /opt/myapp
listen: deploy application
- name: Restart app
systemd:
name: myapp
state: restarted
listen: deploy application
FAQ
Why didn't my handler run?
Handlers only run when a task reports changed. If the task shows ok, the handler is not notified.
Can handlers from different roles listen to the same topic?
Yes - that's a key advantage of listen over direct notify.
Related Articles
• the Ansible inventory deep-dive • using handlers in Ansible playbooksCategory: installation
Watch the video: Ansible Multiple Handlers: Run Handlers in Sequence (listen, notify) — Video Tutorial