Introduction
Ansible handlers only run when a notifying task ends in the changed state. When a task prints useful output but still reports ok, the handler is skipped and the service restart or reload never happens. The underlying problem is usually not the handler itself. It is the task's change detection logic.
Symptoms
- The handler definition is correct, but it never runs
- A configuration file changes on disk, yet the service is not restarted
- Shell or command tasks appear to succeed without triggering the expected reload
- Running the playbook with
-vvshowsokwhere you expectedchanged
Common Causes
- The notifying task uses
commandorshellwithout a properchanged_when - A validation or probe task has
notify, even though it never changes managed state - The wrong Ansible module was used instead of
template,copy, orlineinfile - The handler name matches, but the task never actually enters the
changedstate
Step-by-Step Fix
- 1.**Check whether the notifying task reports
changed** - 2.Run the playbook with enough verbosity to inspect the task result instead of staring only at the handler block.
ansible-playbook site.yml -vv- 1.Use a state-aware module whenever possible
- 2.Modules like
template,copy, andlineinfilealready know whether they changed the remote file, which makes handler notification reliable.
- name: Render application config
template:
src: app.conf.j2
dest: /etc/app/app.conf
notify: Restart app- 1.**Add accurate
changed_whenlogic for command-based tasks** - 2.If you must use
commandorshell, define change detection from real output instead of forcingchanged_when: trueon every run.
- name: Enable the feature flag
command: /usr/local/bin/appctl enable feature-x
register: feature_enable
changed_when: "'already enabled' not in feature_enable.stdout"
notify: Restart app- 1.Flush handlers deliberately when later tasks depend on the restart
- 2.If a follow-up task needs the handler side effect in the same play, force handler execution at the correct boundary.
- meta: flush_handlersPrevention
- Prefer idempotent file and package modules over
shellandcommand - Treat
changed_when: trueas a last resort, not a default pattern - Review handler-triggering tasks with
-vvduring playbook debugging - Keep validation tasks separate from state-changing tasks so
notifysemantics stay clear