What Handlers Are For
A handler is a special kind of task, defined under a 'handlers:' section, that only runs when explicitly triggered via the 'notify' keyword on a regular task — and only if that task actually reports 'changed'. This is the standard pattern for actions like restarting a service after its config file changes: you don't want to restart nginx on every single playbook run, only when the configuration actually differed from what was already deployed.
Cricket analogy: A handler is like a drinks break called only when the umpire signals it's needed, not automatically every over — the 'notify' is the umpire's signal, and the break (handler) only happens if that signal actually fires.
notify, listen, and Execution Order
Handlers run once, in the order they are defined in the 'handlers:' section, after all tasks in the current play have finished — not immediately when notified, and not once per notification even if multiple tasks notify the same handler. Ansible also supports the 'listen' keyword, letting several differently-named handlers all respond to one shared notification topic, which is useful when one config change needs to trigger both a service restart and a cache flush.
Cricket analogy: Handlers running once at the end of the play is like the ground staff only rolling the pitch once at the innings break, no matter how many bowlers requested it during the session.
tasks:
- name: Deploy nginx configuration
ansible.builtin.template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: '0644'
notify: Restart nginx
- name: Deploy app config
ansible.builtin.template:
src: templates/app.env.j2
dest: /etc/myapp/app.env
mode: '0640'
notify:
- Restart nginx
- Reload app cache
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
- name: Clear cache
ansible.builtin.command: /opt/myapp/bin/cache-clear
listen: "Reload app cache"
Forcing Handlers Mid-Play
Sometimes waiting until the very end of a play is too late — for example, if a later task in the same play depends on a service having already restarted with the new config. The 'meta: flush_handlers' task forces all currently-queued handlers to run immediately at that point in the play, after which execution continues with the remaining tasks.
Cricket analogy: meta: flush_handlers is like a captain calling for an immediate strategy review mid-innings instead of waiting until the end-of-day debrief, because the next over's field placement genuinely depends on it happening now.
Handlers are matched by exact name (or 'listen' topic string), so a typo in 'notify: Restart Nginx' versus a handler named 'Restart nginx' silently does nothing — Ansible won't error, it simply never triggers that handler. Double-check spelling and capitalization when wiring notify to handler names.
- Handlers are tasks that only run when triggered via 'notify' on a task that reports 'changed'.
- By default, handlers run once, at the end of the play, in the order they're defined.
- Multiple tasks can notify the same handler; it still only executes once.
- 'listen' lets multiple differently-named handlers share one notification topic.
- 'meta: flush_handlers' forces queued handlers to run immediately mid-play.
- Handler names (or listen topics) must match notify strings exactly, or nothing fires silently.
- Handlers are the standard mechanism for restarts, reloads, and cache flushes after config changes.
Practice what you learned
1. When does an Ansible handler run by default?
2. If three different tasks all notify the same handler, how many times does the handler run?
3. What does the 'listen' keyword enable?
4. What does 'meta: flush_handlers' do?
5. What happens if a task's 'notify' string doesn't exactly match any defined handler name or listen topic?
Was this page helpful?
You May Also Like
Tasks and Modules
Understand how Ansible tasks invoke modules to perform idempotent actions, and how to choose the right module for the job.
Playbook Structure Basics
Learn how Ansible playbooks are organized as YAML documents of plays and tasks, and how top-level keys like hosts, vars, and roles fit together.
Conditionals in Ansible
Use the 'when' clause and Jinja2 expressions to run tasks conditionally based on facts, variables, and previous task results.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics
DevOpsCI/CD Tools & Pipelines Study Notes
YAML · 37 topics