Handlers and change notification

Ansible · Essentials · 8 min

Restarting services on every run causes needless downtime; handlers restart only when needed.

A handler is a task that runs only when notified by another task that reported changed. The classic case: when the nginx config file changes, reload nginx; when it doesn't, do nothing.

  • Define handlers in the play's handlers: section (or a role's handlers/main.yml).
  • A task adds notify: Reload nginx (the handler's name, or a listen topic).
  • Handlers run once, at the end of the play (after all tasks), no matter how many tasks notified them, and in the order they are defined in the handlers section.

Details worth knowing:

  • If a later task fails on a host, pending handlers for that host don't run, so the config may have changed while the service wasn't reloaded. --force-handlers or force_handlers: true runs them anyway.
  • ansible.builtin.meta: flush_handlers runs pending handlers immediately, for example to restart a service before a health-check task later in the same play.
  • listen: "restart web stack" lets several handlers respond to one topic.

Prefer reloaded over restarted when the service supports it, and validate configuration before applying it: the template and copy modules have a validate: option, such as nginx -t -c %s, which refuses to install a broken file.

Example

- name: Configure nginx
  hosts: web
  become: true
  tasks:
    - name: Install site config
      ansible.builtin.template:
        src: site.conf.j2
        dest: /etc/nginx/conf.d/site.conf
        validate: nginx -t -c /etc/nginx/nginx.conf   # whole-config syntax test
      notify: Reload nginx

    - name: Install TLS certificate
      ansible.builtin.copy: {src: site.pem, dest: /etc/nginx/site.pem, mode: "0600"}
      notify: Reload nginx              # still only one reload

  handlers:
    - name: Reload nginx
      ansible.builtin.service: {name: nginx, state: reloaded}
# first run: both tasks changed -> RUNNING HANDLER [Reload nginx] once
# second run: nothing changed -> handler not run

Remember

  • Handlers run only when a notifying task changed
  • They run once, at the end of the play
  • flush_handlers runs them early; validate configs before reloading

Watch out for

  • Expecting a handler to run when a later task failed on that host; use force_handlers if needed.

Check yourself

  1. Three tasks notify the same handler and two of them report changed. How many times does it run?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html