Ansible Curriculum
What Are Handlers
Throughout this guide, the phrase "notify a handler" has appeared dozens of times — in template tasks, in role configuration tasks, in service management. Now we focus on handlers as a system in their own right, because understanding how they work, when they fire, and what guarantees they provide is essential for writing correct Ansible automation.
The Core Concept
A handler is a special task that only runs when explicitly notified by another task — and only when that notifying task reports a changed result. Handlers are Ansible's way of implementing the rule: "only restart a service if something that affects it actually changed."
Consider what happens without handlers. If you deploy a configuration file and then unconditionally restart the service, two problems emerge. First, services restart on every playbook run, even when nothing changed — unnecessary downtime, unnecessary disruption to active connections. Second, if multiple tasks each restart the service, you restart it three times when once would have been sufficient.
Handlers solve both problems: they fire only on actual changes, and each handler fires at most once per play regardless of how many tasks notify it.
How Handlers Are Different from Regular Tasks
Regular tasks:
- Run unconditionally on every playbook execution (unless
when:skips them) - Run in the order they appear in the task list
- Run immediately when their position in the task list is reached
Handlers:
- Run only when notified by a task that produced a
changedresult - Run after all tasks in the play have completed
- Run only once per play, even if notified by multiple tasks
- Run in the order they are defined in
handlers:, not the order they were notified
Defining and Notifying Handlers
Handlers are defined in the handlers: section of a playbook or in a role's handlers/main.yml. They look exactly like regular tasks. The connection between a task and a handler is made through the handler's name: field:
Tasks notify handlers by their exact name:
In this sequence: both template tasks notify Reload Nginx. The binary copy notifies Restart application. After all tasks complete, Reload Nginx fires once and Restart application fires once. If both template tasks reported ok (no change), Reload Nginx does not fire at all.
Handler Execution Timing: End of Play
By default, handlers run at the end of the play after all tasks have finished. This means if your play has 50 tasks and task 5 notifies Reload Nginx, the handler does not run until after task 50 completes.
The practical implication: if task 5 changes the Nginx config and notifies a reload, but task 30 also needs to add a virtual host before Nginx is reloaded, everything works correctly — the reload happens after task 30 completes, so Nginx gets both changes in one reload.
If you need a handler to fire immediately at a specific point in the task list (not at the end), use ansible.builtin.meta: flush_handlers:
flush_handlers causes all pending handler notifications to be processed immediately at that point in the task list. After flushing, the handler queue is empty — if the same handler is notified again later, it will fire again at the end.
The next section covers the full mechanics of creating and naming handlers — including naming conventions, handler chaining (handlers that notify other handlers), and how to structure handlers for maintainability.