Ansible Handlers: Complete Guide to Event-Driven Task Execution
By Luca Berton · Published 2024-01-01 · Category: installation
Master Ansible handlers for event-driven automation. Learn when and how to use handlers, notify chains, listen directives, flush handlers, handler best practices, and common pitfalls with practical examples.
What Are Ansible Handlers?
Handlers are special tasks that run only when notified by another task. They execute once at the end of a play, regardless of how many tasks notify them. The most common use case: restart a service only if its configuration actually changed.
If neither template changed → handler doesn't run. If one or both templates changed → handler runs once at end of play.
How Handlers Work A task with notify: handler_name completes with changed status The handler is flagged to run All tasks in the play finish first Flagged handlers run in the order they're defined (not notification order) Each handler runs at most once per play
Handler Patterns
Multiple Handlers from One Task
Listen Directive — Multiple Triggers, One Handler
listen lets multiple handlers respond to a single notification topic. This decouples the notifying task from knowing which services need restarting.
Handler Chains — Handlers Notifying Handlers
Flush Handlers — Run Handlers Mid-Play
By default, handlers run at the end of the play. Use meta: flush_handlers to force them to run immediately:
When to flush: • Next task depends on the restarted service being up • Rolling updates where you need to verify health before continuing • Database migrations that require the app to be running
Handlers in Roles
Common Pitfalls
1. Handler Not Running
Fix: Handler name in notify must exactly match handler name (or listen topic).
2. Handler Runs Even When You Don't Want It
3. Task After Handler Needs the Service Running
4. Handler Doesn't Run on Failed Play
If a task fails, remaining tasks AND handlers are skipped. Use --force-handlers to run notified handlers even on failure:
Or in the playbook:
5. Handler Runs Multiple Times (Wanted)
Handlers run once per play by default. If you need a restart between multiple configuration changes:
Reload vs Restart
Rule of thumb: • Config file change → reload (graceful, no downtime) • Package update, major config change → restart • SSL cert change → depends on the service
Best Practices Use reload over restart when the service supports it — less disruptive Validate before restart — run config check (nginx -t, apachectl configtest) before restarting Name handlers clearly — restart nginx not handler1 Use listen for cross-cutting concerns (SSL change → multiple service restarts) Flush handlers before tasks that depend on the restarted service Use force_handlers: true in critical plays where services must be restarted regardless of failures Keep handlers in roles — handlers/main.yml is auto-loaded Don't use handlers for one-off tasks — if a task should always run, make it a regular task with a when condition
FAQ
Why is my handler not running?
Three common causes: (1) the notifying task didn't change anything (ok status, not changed), (2) the handler name doesn't exactly match the notify string, or (3) a task before the handler failed and force_handlers isn't set.
Can I run a handler from the command line?
No. Handlers only run when notified by tasks. If you need to run a handler manually, extract the task into a separate playbook or use tags to selectively run tasks.
What's the difference between notify and when?
notify triggers a handler only when the notifying task changes something — it's event-driven. when is a condition evaluated every time. Use notify for "restart service if config changed" and when for "run this task only on Ubuntu."
Do handlers run in parallel?
No. Handlers run sequentially in the order they're defined in the handlers section, not in notification order. If handler B must run after handler A, define A before B in the handlers list.
Conclusion
Handlers are Ansible's event-driven mechanism for efficient service management. They prevent unnecessary restarts, keep plays idempotent, and separate "what changed" from "what to do about it." Use notify to flag changes, listen for cross-cutting events, flush_handlers when ordering matters, and always validate configuration before restarting services.
Related Articles • Ansible Best Practices: ignore_errors • Ansible Lint Complete Guide • Ansible Documentation Complete Guide • Ansible Playbook Examples • Ansible Roles Complete Guide
Category: installation