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.

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: restarted

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: restarted

How 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).

Takeaway

Write handlers and trigger them with notify. Use the chapter lab to check this on a real host.