Ansible Handlers and Notify Explained with Examples – Restart Services Only When Changes Occur
Hello DevOps Experts!! let's zoom into the usage of the Ansible Handlers and notifies
Have you ever restarted a service in Ansible even though nothing actually changed?
Many beginners add service restart tasks directly into their playbooks. While this works, it can cause unnecessary service interruptions, increase deployment times, and introduce avoidable downtime.
Ansible provides a smarter mechanism called Handlers, which execute only when a task reports a change. Combined with the notify directive, handlers help build efficient, idempotent, and production-ready automation.
In this article, we'll explore how Ansible Handlers work, when to use them, and common DevOps use cases.
What We'll Learn
By the end of this article, you will understand:
- What Ansible Handlers are
- Why handlers are important
- How the notify keyword works
- When handlers are triggered
- How multiple tasks can notify a single handler
- Real-world DevOps use cases
- Best practices for handler design
- Common mistakes and troubleshooting tips
What are Ansible Handlers?
The handlers section or the tasks defined under the handlers folder are executed at the end of the play once all tasks are finished. In the handlers tasks we are typically do either start, reload, restart and stop services.
Sometimes we may need to execute the task only when a particular change is made that can be notified. Simple example of Apache web server when we modify httpd.conf file then we want to restart the httpd service.
Handlers typically perform actions such as:
- Restarting services
- Reloading services
- Restarting applications
- Reloading firewall configurations
- Reloading NGINX or Apache configurations
- Restarting Tomcat after configuration updates
- Reloading systemd daemon
Why we need Ansible Task handlers?
Let's take an use case to understand this clearly, consider Apache Web Server. Suppose we have updated the configuration file: /etc/httpd/conf/httpd.conf
To reflect the changes we need to restart the httpd service.
Before Handlers use :
tasks:
- name: Update Apache configuration
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
- name: Restart Apache
service:
name: httpd
state: restarted
Here is the problem?
Apache restarts every time the playbook runs, even if the configuration file remains unchanged.
This creates unnecessary downtime.
How the Handlers solves this problem?
With handlers logic implementation here:tasks:
- name: Update Apache configuration
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify:
- Restart Apache
define the Handler:
handlers:
- name: Restart Apache
service:
name: httpd
state: restarted
Now Apache restarts only when the configuration file changes.
This is one of the core principles of idempotent automation.
How Notify Works with Handlers
The notify keyword tells Ansible Controller which handler should be triggered.Example:
notify: - Restart ApacheWhen the task reports:
changed=1Ansible schedules the handler execution.
If the task reports:
changed=0Observe that - The handler execution is skipped.
So here the point is that handler tasks will be performed only when they are notified.
Ensure that handler task name should have a globally unique name.
Important Behavior of Handlers
Many new Ansible automation users expect handlers to run immediately, Even I thought the same but after reading documentation got it clear understanding.
However, handlers are executed:- ✅ After all normal tasks complete
- ❌ Not immediately after notification
tasks:
- Task A
notify: Restart Apache
- Task B
- Task C
Execution order for the above snippet:
Task A Task B Task C Restart Apache
This behavior prevents multiple unnecessary service restarts.
Real-World Example: Apache Web Server for PHP
Role Structure
php-webserver/ ├── tasks/ │ └── main.yml ├── handlers/ │ └── main.ymltasks/main.yml
---
- name: Install PHP packages
yum:
name: "{{ item }}"
state: latest
loop:
- php
- php-gd
- php-pear
- php-mysql
notify:
- Restart Apache
handlers/main.yml
---
- name: Restart Apache
service:
name: httpd
state: restarted
Let's see the example of notify and handlers
Calling the role
Now you can see how to include the role php-webserver into the main playbook# Filename: test-handler.yml
---
- hosts: web
user: root
become: yes
roles:
- php-webserver
Save the file as test-handler.yml. Now, Execution of the test-handler will be like this:
ansible-playbook test-handler.yml
Real-World DevOps Use Cases
1. Reload system's Firewalld
- name: Add firewall rule
firewalld:
port: 8080/tcp
permanent: yes
state: enabled
notify:
- Reload Firewalld
Handler for firewal deamon reload:
- name: Reload Firewalld
service:
name: firewalld
state: reloaded
2. Restart Tomcat when app deployed
- name: Deploy application
copy:
src: app.war
dest: /opt/tomcat/webapps/
notify:
- Restart Tomcat
Handler for restarting Tomcat server:
- name: Restart Tomcat
service:
name: tomcat
state: restarted
3. Reload NGINX when conf updates
- name: Update nginx.conf
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Reload NGINX
Handler for reload NGINX web server:
- name: Reload NGINX
service:
name: nginx
state: reloaded
4.Multiple Tasks Can Notify the Same Handler
This is valication of a powerful feature of Handler in Ansible.
- name: Update vhost config
template:
src: vhost.conf.j2
dest: /etc/httpd/conf.d/vhost.conf
notify:
- Restart Apache
- name: Update httpd.conf
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify:
- Restart Apache
Even if both tasks change, Apache restarts only once.
This improves performance and reduces service disruptions.
Force Immediate Handler Execution
Sometimes you need the handler to run before later tasks.
Use:
- meta: flush_handlersExample:
tasks:
- name: Update configuration
template:
src: app.conf.j2
dest: /etc/app.conf
notify:
- Restart App
- meta: flush_handlers
- name: Validate application
shell: appctl status
Here the restart happens immediately before validation.
Best practices for Ansible Handlers
1. Use Meaningful Names
Better naming samples:
Restart Apache Reload Firewalld Restart TomcatAvoid:
handler1 restart task1
2. Use Reload Instead of Restart When Possible
Reload causes less disruption.Examples:
NGINX Apache HAProxy
3. Keep Handlers Idempotent
Handlers should safely execute multiple times without causing unexpected side effects.
4. Centralize Service Management
Keep service restart logic inside handlers rather than scattering restart tasks throughout playbooks.
Don't do this Mistakes
Handler Name TypoTask: notify: - Restart ApacheHandler:
- name: Restart HTTPDResult:
ERROR! The requested handler was not foundNames must match exactly. Expecting Immediate Execution Be aware of that Handlers run at the end of the play unless:
meta: flush_handlersis used. Using Restart Instead of Reload For services supporting configuration reloads, use:
state: reloadedinstead of:
state: restartedwhen appropriate and applicable.
Benefits of Using Handlers
| Benefit | Description |
|---|---|
| Reduced Downtime | Services restart only when required |
| Better Performance | Fewer unnecessary operations |
| Idempotency | Supports repeatable automation |
| Cleaner Playbooks | Service management is centralized |
| Scalability | Suitable for large environments |
| Production Safety | Reduces accidental disruptions |
Reader Challenge
Try implementing the following:
Beginner
- Restart Apache only when httpd.conf changes
Intermediate
- Reload NGINX after virtual host updates
Advanced
- Use multiple notifications for a single handler
-
Implement
flush_handlers - Build reusable handlers within Ansible roles
Conclusion
Ansible Handlers are one of the most important features for building efficient and production-ready automation. They ensure that services are restarted, reloaded, or refreshed only when necessary, helping reduce downtime and maintain idempotent deployments.
Whether you are managing Apache, NGINX, Tomcat, Kubernetes nodes, or enterprise applications, understanding handlers and notifications will make your Ansible automation cleaner, faster, and more reliable.
Dear Reader Question
Which service do you most commonly manage with Ansible handlers—Apache, NGINX, Tomcat, Docker, Kubernetes, or something else?
Share your experience in the comments and let fellow automation engineers learn from your real-world use cases.
Comments