# ansible / configuration / handlers

Trigger Actions with Handlers

Restarting a service every time a playbook runs is inefficient and causes unnecessary downtime. Handlers solve this: they are special tasks that only execute when another task reports a "changed" state.

Execution State
Taskcopy file (index.html)
Statechanged
ActionHandler Triggered!
notify
Keyword
Once
Executions
# concept

Why Use Handlers?

If you update an Apache configuration file or replace an index.html, the Apache service needs to be restarted to apply the changes. But if the file hasn't changed, restarting the service is a waste of time and drops active connections.

the notify keyword

How it Works

You add the notify directive to any standard task. If that task results in a changed state (e.g., a file was actually modified or a package was newly installed), it sends a signal to a corresponding handler by name.

CAR WASH ANALOGY

Imagine telling a robot: "Check if my car is dirty. If it is, wash it. If you wash it, notify the drying system to dry it."

If the car is already clean, the robot does nothing, and the drying system is never turned on.

# code

The Apache Handler Playbook

deploy_apache.ymlYAML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
---
- name: install apache using handler
  hosts: localhost
  become: yes
  tasks:
    - name: install apache
      apt:
        name: apache2
        state: present
      notify: Restart apache

    - name: copy file
      copy:
        src: index.html
        dest: /var/www/html
      notify: Restart apache

    - name: restart service
      service:
        name: apache2
        state: started
        enabled: true

  handlers:
    - name: Restart apache
      service:
        name: apache2
        state: restarted
# lifecycle

The Execution Flow

What happens when you run this?

  • 1. Install

    Ansible ensures apache2 is installed. If it has to download it, it registers a "changed" state and queues the Restart apache handler.

  • 2. Copy

    Ansible copies index.html. If the file is different from what's on the server, it queues the handler again.

  • 3. Start

    Ansible simply ensures the service is currently running and enabled on boot.

  • 4. Handlers Flush

    At the very end of the play, Ansible looks at the queue. It sees the Restart apache handler was notified, and executes it exactly once.

terminal output
$ ansible-playbook deploy_apache.yml
 
TASK [install apache] *************************************
ok: [localhost]
 
TASK [copy file] ******************************************
changed: [localhost]
 
TASK [restart service] ************************************
ok: [localhost]
 
RUNNING HANDLER [Restart apache] **************************
changed: [localhost]
# best-practices

Crucial Rules of Handlers

NAME MATCHING

The name in the notify: directive must match the name of the handler exactly (case-sensitive). If you notify "restart apache" but the handler is named "Restart apache", it will fail silently.

DE-DUPLICATION

Even if 10 different tasks notify the "Restart apache" handler during a single playbook run, Ansible will deduplicate them and only restart the service once at the very end of the play.

RUN ON CHANGE ONLY

If you run this playbook a second time (and no files have changed), you will see "ok" for all tasks. Because nothing "changed", the handler block will be completely skipped.