5.1 : Handlers et notify : ne redémarrer que si nécessaire

Imaginez ce scénario : votre playbook modifie un fichier de configuration Apache. Logiquement, il faut redémarrer Apache pour que le changement prenne effet. Mais si le fichier n’a pas changé (parce qu’il était déjà conforme), faut-il redémarrer quand même ?

Non — et c’est justement le genre de redémarrage inutile qui a causé des problèmes concrets chez Nordika par le passé (coupures de service pour rien, caches vidés sans raison). C’est exactement ce que les handlers permettent d’éviter.

Le principe : une action déclenchée, pas systématique

Un handler est une tâche un peu spéciale : elle ne s’exécute que si une autre tâche l’a explicitement demandé, via notify. Et même notifié plusieurs fois dans le même play, un handler ne s’exécute qu’une seule fois, à la toute fin du play.

---
- name: Configurer Apache avec redémarrage conditionnel
  hosts: webservers
  become: yes

  tasks:
    - name: Installer Apache
      ansible.builtin.apt:
        name: apache2
        state: present

    - name: Déployer la configuration du VirtualHost
      ansible.builtin.copy:
        src: files/nordika.conf
        dest: /etc/apache2/sites-available/nordika.conf
      notify: Redémarrer Apache

  handlers:
    - name: Redémarrer Apache
      ansible.builtin.service:
        name: apache2
        state: restarted

Décortiquons : la clé handlers est un bloc séparé de tasks, au même niveau dans le play. Le nom du handler (Redémarrer Apache) doit correspondre exactement au texte utilisé dans notify — c’est une chaîne de caractères, pas une référence technique, donc attention à la moindre faute de frappe.

Le comportement clé : uniquement si changed

Le point essentiel à retenir : un notify ne déclenche le handler que si la tâche qui le porte a produit un changed. Si nordika.conf était déjà exactement dans l’état voulu (donc ok, pas changed), le handler n’est jamais appelé, et Apache continue de tourner sans interruption.

TASK [Déployer la configuration du VirtualHost] ********
ok: [nrd-web1]

# Le handler "Redémarrer Apache" n'apparaît PAS dans les logs : jamais notifié
TASK [Déployer la configuration du VirtualHost] ********
changed: [nrd-web1]

RUNNING HANDLER [Redémarrer Apache] ********************
changed: [nrd-web1]

Un handler exécuté une seule fois, même notifié plusieurs fois

C’est un détail important en pratique : si plusieurs tâches différentes notifient le même handler dans un même play, il ne s’exécute qu’une fois, à la fin — pas une fois par notification.

tasks:
  - name: Déployer le VirtualHost principal
    ansible.builtin.copy:
      src: files/nordika.conf
      dest: /etc/apache2/sites-available/nordika.conf
    notify: Redémarrer Apache

  - name: Déployer le VirtualHost secondaire
    ansible.builtin.copy:
      src: files/nordika-admin.conf
      dest: /etc/apache2/sites-available/nordika-admin.conf
    notify: Redémarrer Apache

handlers:
  - name: Redémarrer Apache
    ansible.builtin.service:
      name: apache2
      state: restarted

Même si les deux fichiers changent, Apache ne redémarre qu’une seule fois à la fin du play, jamais deux fois de suite pour rien.

Notifier plusieurs handlers à la fois

Une tâche peut notifier plusieurs handlers en même temps, sous forme de liste :

- name: Déployer la configuration Apache et son firewall
  ansible.builtin.copy:
    src: files/nordika.conf
    dest: /etc/apache2/sites-available/nordika.conf
  notify:
    - Redémarrer Apache
    - Recharger le firewall

meta: flush_handlers : forcer l’exécution immédiate

Par défaut, les handlers s’exécutent à la toute fin du play, jamais avant. Si un handler doit impérativement s’exécuter avant une tâche suivante (par exemple, redémarrer un service avant de vérifier qu’il répond), on peut forcer leur déclenchement immédiat :

tasks:
  - name: Déployer la configuration
    ansible.builtin.copy:
      src: files/nordika.conf
      dest: /etc/apache2/sites-available/nordika.conf
    notify: Redémarrer Apache

  - name: Forcer l'exécution des handlers maintenant
    ansible.builtin.meta: flush_handlers

  - name: Vérifier que le service répond après redémarrage
    ansible.builtin.uri:
      url: http://localhost
      status_code: 200

Ce qu’il faut retenir

  • Un handler ne s’exécute que si notifié, et uniquement si la tâche notifiante a produit un changed.
  • Même notifié plusieurs fois, un handler ne s’exécute qu’une seule fois, à la fin du play.
  • Le nom du handler dans notify doit correspondre exactement à son name — c’est une correspondance textuelle, pas une référence.
  • meta: flush_handlers force leur exécution immédiate si l’ordre normal (fin de play) ne convient pas.

Dans la prochaine leçon, on aborde les templates Jinja2 : comment générer un fichier de configuration dynamique, plutôt que de copier un fichier statique comme on vient de le faire ici.