Анотация
Если у тебя в плейбуках после каждой правки конфига идёт ещё одна таска service: restarted, а nginx в логах дёргается по десять раз за запуск — значит, пора познакомиться с handlers. В этой статье разберём, что такое handler, как notify связывает его с тасками и почему сервис перезапускается ровно один раз, даже если его «дёрнули» сразу несколько задач.
Зачем вообще нужны handlers
Типичная история:
- у тебя есть несколько задач, которые правят конфиги nginx;
- после каждой ты на всякий случай делаешь service: name=nginx state=restarted;
- если меняется два файла — nginx перезапускается два раза подряд.
Это лишняя нагрузка, лишние риски и просто неаккуратно.
Handlers помогают сделать перезапуск сервисов «умным»: только когда реально что-то поменялось, и один раз за запуск плейбука.
Что такое handler в Ansible
Handler — это такая же задача, как обычная, но живёт она в отдельном блоке handlers: и выполняется только по сигналу (notify).
Простейший пример:
Что здесь происходит:
- в tasks мы кладём шаблон конфига;
- в этой же таске пишем notify: Restart nginx;
- в handlers описываем задачу с таким же name, которая перезапускает nginx.
Если файл реально изменился — Ansible «запомнит», что нужно вызвать handler Restart nginx.
Если файл такой же, как был, — handler не сработает вообще.
Как notify связывает таску и handler
Всё держится на одном простом правиле:
Название в notify должно совпадать с name у handler.
Важно понять две вещи:
- Handler вызывается только при изменении.
Модуль template сам определяет, изменился ли файл. Если да — таска в статусе changed, и notify срабатывает. Если нет — статус ok, handler не нужен. - Можно нотифать несколько handlers.
notify может быть списком:
Почему handler вызывается один раз, даже если его нотифнули несколько тасок
Рассмотрим пример:
Если обе задачи что-то изменили, то логика Ansible такая:
- Первая таска изменила файл → ставим Restart nginx в очередь handlers.
- Вторая таска тоже изменила файл → handler уже в очереди, добавлять второй раз не нужно.
- В конце плейбука Ansible запускает каждый handler ровно один раз.
Итог: два изменённых конфига → один аккуратный перезапуск nginx.
Так меньше рисков поймать ошибки на старте, меньше «дёрганий» сервиса и логика плейбуков становится чище.
Пошаговый пример: template + notify + handler
Шаг 1. Готовим шаблон конфига
Пусть у нас есть простой шаблон templates/nginx.conf.j2:
Шаг 2. Пишем таску с notify
Если в шаблоне или переменных что-то поменялось — файл на сервере тоже поменяется, таска станет changed, и handler поставится в очередь.
Шаг 3. Описываем handler перезапуска
Теперь при изменении конфига Ansible:
- обновит файл;
- в конце плейбука выполнит handler Restart nginx.
Если запустить плейбук второй раз без изменений — увидишь:
- таска template в статусе ok;
- handler даже не будет упомянут — ему нечего делать.
Типичные ошибки и быстрые фиксы
1. Опечатка в имени handler
и
Для Ansible это два разных имени.
Handler просто не найдётся и не выполнится.
Как фиксить:
держать единый стиль, лучше копировать name целиком, а не печатать с нуля.
2. Handler не срабатывает, потому что таска всегда ok
Если ты вручную переопределил changed_when: false, handler никогда не вызовется:
Ansible думает, что изменений нет → и не вызывает handler.
Как фиксить:
использовать changed_when только осознанно. Если ты говоришь Ansible «ничего не изменилось», он тебе верит.
3. Перезапуск нужен раньше конца плейбука
По умолчанию handlers выполняются в конце плейбука (или роли).
Если тебе нужно перезапустить сервис сразу после серии задач — используй:
Пример:
Тут nginx перезапустится до health-check.
4. Вместо restart иногда лучше reload
Перезапуск (state: restarted) полностью гасит сервис и поднимает его заново.
Иногда достаточно reloaded, чтобы перечитать конфиги без полной остановки.
Почему это работает
- Ansible чётко разделяет «обычные» таски и handlers: первые выполняются всегда, вторые — только по сигналу.
- Модуль в таске (например, template) сам решает, было ли изменение. Это позволяет не перезапускать сервис без необходимости.
- Все уведомления (notify) по одному и тому же имени складываются в очередь, но handler выполняется один раз — это экономит время и снижает риски.
- Порядок «таски → notify → handlers в конце» делает сценарий предсказуемым и повторяемым: один запуск плейбука даёт один и тот же результат.
Что мы сделали в этой статье
- Разобрали, что такое handler в Ansible и чем он отличается от обычной таски.
- Посмотрели, как notify связывает задачи и handlers по имени.
- Поняли, почему handler выполняется один раз, даже если его нотифнули несколько задач.
- Собрали типичный паттерн: template → notify: Restart nginx → handler с service: state=restarted.
- Разобрали несколько типичных ошибок и как их быстро исправить.
Сделать прямо сейчас (чеклист)
- Найди плейбук, где несколько задач правят конфиги одного сервиса и каждая сама его перезапускает.
- Вынеси перезапуск в handler в блоке handlers:
- В тасках вместо отдельных service поставь notify: Restart <service>
- Запусти плейбук два раза подряд и посмотри вывод: при втором запуске handler не должен выполняться.
- Для сервисов, где достаточно перечитать конфиг, замени restarted на reloaded.
CTA
Если хочешь дальше прокачивать Ansible без боли и магии — подписывайся на серию. В следующих материалах разберём роли, структуру проектов и более сложные сценарии с условиями и циклами.
Пиши в комментариях:
- есть ли у тебя сейчас «лишние» перезапуски;
- какой сервис ты хочешь «обложить» handlers в первую очередь.
Можем вместе разобрать твой плейбук и превратить хаос перезапусков в аккуратную схему.