Ansible не перезапустил сервис: когда срабатывает handler

Playbook обновил конфигурационный файл, а приложение продолжает отвечать со старым лимитом. В выводе нет ожидаемого RUNNING HANDLER. Прежде чем добавлять безусловный restart, стоит пройти всю цепочку: задача действительно изменила файл, отправила уведомление нужному handler и дошла до момента его выполнения?

Handler удобен для действий, которые нужны только после изменения. Несколько задач могут поправить разные фрагменты конфигурации, а перезапуск достаточно выполнить один раз. Отсюда две особенности диагностики: наличие notify ещё не означает уведомление, а уведомление ещё не означает немедленный запуск.

Воспроизведём механизм без перезапуска сервиса

Следующий самостоятельный playbook пишет файл в отдельный временный каталог локального Linux control node. Handler читает получившееся содержимое. Для выполнения нужны установленный Ansible и Python на этой машине; привилегии администратора и SSH не требуются.

- name: Understand notifications
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    demo_value: alpha
  tasks:
    - name: Create demo directory
      ansible.builtin.file:
        path: /tmp/latorn-handler-demo
        state: directory
        mode: '0700'
    - name: Write configuration
      ansible.builtin.copy:
        content: "value={{ demo_value }}\n"
        dest: /tmp/latorn-handler-demo/app.conf
        mode: '0600'
      notify: Read resulting configuration
    - name: Run pending handlers now
      ansible.builtin.meta: flush_handlers
  handlers:
    - name: Read resulting configuration
      ansible.builtin.command:
        argv: [cat, /tmp/latorn-handler-demo/app.conf]
      changed_when: false
ansible-playbook -i localhost, demo.yml
ansible-playbook -i localhost, demo.yml
ansible-playbook -i localhost, demo.yml -e demo_value=beta

При первом запуске с отсутствующим файлом copy должен вернуть changed, после чего появится handler. Второй запуск с alpha оставляет файл прежним, поэтому уведомления и чтения не будет. Третий меняет содержимое на beta и снова уведомляет handler. В его выводе проверьте stdout через подробный вывод Ansible, если текущий callback не показывает результат успешной command.

Changed управляет уведомлением

Найдите в реальном журнале задачу, у которой указан notify. Если она завершилась ok, отсутствие handler ожидаемо. Например, шаблон уже совпадает с файлом назначения или условие when пропустило задачу. Сначала сравните ожидаемое содержимое шаблона с dest на нужном хосте; одинаковое имя файла на другой машине не объясняет результат этого запуска.

Особенно внимательно смотрите на changed_when: false. Эту настройку полезно ставить на чтение, как в нашем handler, но у задачи записи она подавит и changed, и уведомление. Исправлять это безусловным changed_when: true тоже не стоит: тогда повторный запуск будет перезапускать сервис даже при одинаковом файле. Смысл changed должен совпадать с фактическим изменением.

Когда handler получает управление

Обычно обработчики выполняются в предусмотренных Ansible точках после секций задач, а повторные уведомления одного handler до такой точки объединяются. В примере meta: flush_handlers специально запускает накопленные обработчики сразу после записи. Это полезно, когда следующая задача уже должна обращаться к процессу с новой конфигурацией.

Flush выполняет все ожидающие handlers в этой точке, поэтому его место влияет на другие роли. Если вы хотите убедиться в работе механизма, сначала оставьте минимальный play, затем верните роли и зависимые задачи. Уведомление по имени требует точного совпадения; при использовании listen сопоставляется имя темы. Неоднозначные одинаковые имена обработчиков из нескольких ролей затрудняют диагностику.

Порядок нескольких handlers определяется их определением, а не порядком строк notify. Если перед reload требуется валидация, лучше проверять конфигурацию в задаче формирования файла или явно выразить зависимость. Нельзя рассчитывать, что список уведомлений сам построит безопасную последовательность.

Ошибка между записью и перезапуском

Если после изменения файла другая задача завершается ошибкой на хосте, отложенный handler по умолчанию может не выполниться на этом хосте. Тогда файл уже новый, а процесс ещё старый. Сопоставьте сообщения changed и failed на одной машине. Опция force_handlers меняет поведение при ошибках, но не делает недоступный хост доступным.

Для реального сервиса замените чтение файла обработчиком service или systemd_service и сначала подтвердите корректность конфигурации штатным валидатором приложения. Выбор между restart и reload зависит от того, умеет ли процесс перечитывать нужный параметр. Механика уведомлений разобрана в справке handlers, а поведение после ошибки — в обработке failures.

Проверяйте исправление двумя последовательными запусками: первый должен применить изменение и вызвать обработчик, второй — сохранить состояние без лишнего действия. Так проверяется вся причинная цепочка, а не только наличие слова notify в YAML.

Ещё по теме

Продолжить изучение

Хотите собрать настройку серверов в повторяемый процесс? Inventory, роли, шаблоны и обновление сервисов входят в программу «Ansible: автоматизация инфраструктуры».

Продолжить на практике

  • Ansible: автоматизация инфраструктуры ↗

    Настраивайте серверы воспроизводимо: inventory, playbooks, роли, шаблоны и секреты. Соберите автоматизацию для нескольких окружений, проверьте повторный запуск и обновляйте сервисы управляемо.