Chapter 5: Implementing Task Control
Implementing handlers
When a configuration file changes, the service that reads it must be restarted, but only then. Restarting on every run would interrupt users for no reason. Handlers are tasks that run only when another task reports that it changed something.
- Write handlers and trigger them with
notify. - Predict when handlers run, in which order, and how many times.
- Know what happens to handlers when a play fails.
What handlers are
Modules are idempotent: they change a host only when it differs from the desired state. But a change sometimes requires a follow-up action. A new configuration file means the service must be reloaded; a kernel update may mean a reboot.
Handlers are tasks that respond to a notification from other tasks. A task notifies a handler, by name, only when the task changes something. Notified handlers run once, after all the tasks in the play have finished. If nothing notifies a handler, it does not run at all.
Handlers use the same modules as any other task. In practice they mostly restart services and reboot hosts.
Writing a handler
tasks:
- name: copy demo.example.conf configuration template
ansible.builtin.template:
src: /var/lib/templates/demo.example.conf.template
dest: /etc/httpd/conf.d/demo.example.conf
notify:
- restart apache
handlers:
- name: restart apache
ansible.builtin.service:
name: httpd
state: restartednotifyon a task lists the handlers to trigger if the task reportschanged. Its value is a list, so a task can notify several handlers.handlersis a play-level section, at the same indentation astasks. Each handler is a normal task, identified by itsname.
A task can notify more than one handler:
tasks:
- name: copy demo.example.conf configuration template
ansible.builtin.template:
src: /var/lib/templates/demo.example.conf.template
dest: /etc/httpd/conf.d/demo.example.conf
notify:
- restart mysql
- restart apache
handlers:
- name: restart mysql
ansible.builtin.service:
name: mariadb
state: restarted
- name: restart apache
ansible.builtin.service:
name: httpd
state: restartedHow handlers behave
Try it: flip tasks between ok and changed, and add a failure:
The rules the simulator follows:
If the task reports ok (for example, the package was already installed) or failed, its handlers are not notified.
A handler notified by the first task still waits until every task in the tasks section has run. (There are a few advanced exceptions.)
Even if five tasks notify the same handler, it runs a single time. That is exactly what you want for a service restart.
Handlers run in the order they are listed under handlers, not in the order they were notified, and not in the order of a task's notify list.
If a task fails and the play stops on that host, notified handlers do not run, unless the play sets force_handlers: true (covered in the task failure section).
- Three tasks notify `restart web`. Two report `changed`, one reports `ok`. How many times does the handler run?
- When does a notified handler run?
- The handlers section lists `restart A` then `restart B`. A task notifies B first, then another task notifies A. In which order do they run?
- Where is the `handlers` keyword placed?
Takeaway
Write handlers and trigger them with notify. Use the chapter lab to check this on a real host.