Ansible Handlers & Notification Prompt
Use Ansible handlers correctly — notify, listen, force handlers, multi-handler chains, when handlers don't fire.
- Target user
- Ansible engineers handling service restarts
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a senior Ansible engineer who has debugged "handler didn't fire" countless times. You know the rules: notify only on change, deferred to end of play, handlers can listen. I will provide: - The handler config - The notifying task - Symptom (handler not firing, wrong order, multiple handlers) Your job: 1. **Handler basics**: - Defined in `handlers:` section of play or `roles/<role>/handlers/main.yml` - Triggered by `notify: <handler_name>` - Runs ONCE per play after all tasks - Only if task reported `changed` 2. **For handler not firing**: - Task didn't change anything (idempotent skipped) - Notify name doesn't match handler name - Play failed before handler section (use `--force-handlers`) - Handler in different play (handlers are play-scoped) 3. **For ordering**: - Handlers run in ORDER DEFINED, not order notified - Useful for dependency chains 4. **For multiple notifies**: - Same handler notified multiple tasks → runs once - Deduplicates 5. **For `listen:` (handlers)**: - Multiple handlers listen for same topic - Decoupled from task notification - One notify triggers all listeners 6. **For force-handlers**: - Playbook `force_handlers: true` runs handlers even on play failure - Useful for partial recovery 7. **For role handlers**: - In `roles/<role>/handlers/main.yml` - Notify by name (no role prefix needed within play) - Or import_handler for explicit 8. **For task-level handler-like behavior**: - `meta: flush_handlers` runs all pending handlers immediately - Useful when subsequent tasks depend on restarted service Mark DESTRUCTIVE: forcing handlers on critical failure (incomplete state), removing handler dependencies (broken restart chain), flush_handlers in wrong place (premature restart). --- Handler config: [PASTE] Notifying task: [PASTE] Symptom: [DESCRIBE]
Why this prompt works
Handlers have subtle rules. This prompt walks them.
How to use it
- Match notify name exactly.
- Order handlers in dependency order.
- Use listen for decoupling.
- flush_handlers when need before next task.
Useful commands
# Verbose to see handler firing
ansible-playbook playbook.yml -v
# Force handlers (run even if play fails)
ansible-playbook playbook.yml --force-handlers
# Check (handlers normally don't run in check)
ansible-playbook playbook.yml --check
Patterns
Basic handler
- hosts: webservers
tasks:
- name: Render nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: Render upstream config
template:
src: upstreams.conf.j2
dest: /etc/nginx/conf.d/upstreams.conf
notify: restart nginx # same handler; runs once
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
Listen for decoupling
- hosts: web
tasks:
- name: Update certs
copy: ...
notify: certs updated # topic
- name: Update config
template: ...
notify: config updated
handlers:
- name: restart nginx
service: { name: nginx, state: restarted }
listen: # listens for topics
- certs updated
- config updated
- name: notify slack
uri: ...
listen:
- certs updated
flush_handlers (run immediately)
- hosts: web
tasks:
- name: Install postgresql
package: { name: postgresql, state: present }
notify: start postgresql
- name: Run handlers now (before next task that needs DB)
meta: flush_handlers
- name: Initialize DB
shell: psql -c "CREATE DATABASE myapp;"
# postgresql is started; this works
handlers:
- name: start postgresql
service: { name: postgresql, state: started, enabled: true }
Force handlers on failure
- hosts: all
force_handlers: true # even if play fails, run handlers
tasks:
- name: Risky task
...
notify: cleanup
handlers:
- name: cleanup
file: { path: /tmp/lock, state: absent }
Common findings this catches
- Handler not firing → task idempotent, no change.
- Notify name mismatch → typo.
- Handler runs but service still old config → handler order; restart in wrong order.
- flush_handlers too early → service restarts unnecessarily mid-play.
- Cross-role handler notified but not present → import_role or include handler.
force_handlers: trueon partial config = bad state.- Multiple handlers same topic listen → all fire on one notify.
When to escalate
- Handler chain redesign — strategic.
- Cross-role handler coordination — role library.
- Failure recovery patterns — review.
Related prompts
-
Ansible Idempotency Design Prompt
Make Ansible tasks idempotent — when to use changed_when / failed_when, check mode, validating shell tasks.
-
Ansible Playbook Generator Prompt
Generate idempotent Ansible playbooks with proper handlers, tags, and check-mode support.
-
Ansible Roles Structure Best Practices Prompt
Design Ansible roles — defaults vs vars, meta dependencies, role parameters, tags, idempotency.