Handlers in Ansible

Ansible is an open-source automation platform widely used for configuration management, application deployment, and task automation. One of the most powerful features in Ansible playbooks is the use of handlers. Handlers allow you to define actions that should only run when notified by other tasks, which helps in improving the efficiency and performance of your automation scripts. In this detailed guide, we will dive into the concept of handlers in Ansible, how to use them effectively, and explore their best practices.

What Are Handlers in Ansible?

Introduction to Handlers

Handlers in Ansible are special tasks that are executed only when notified by another task. Typically, handlers are used for tasks that should only run if there is a change in the system, such as restarting a service after a configuration file is modified. Unlike regular tasks, handlers are triggered by other tasks via the notify directive. Once notified, handlers will run at the end of the playbook execution, after all tasks have been completed.

Why Use Handlers in Ansible?

Handlers provide several advantages:

  1. Efficiency: Handlers only run when necessary (i.e., when there is a change in state). This minimizes unnecessary operations, such as restarting a service multiple times.
  2. Performance: By grouping changes and running them after all tasks are completed, handlers help in optimizing performance and reducing downtime.
  3. Clean and Modular Code: Handlers promote a more organized and modular approach to writing Ansible playbooks, as they are reusable and easy to maintain.

How Handlers Work in Ansible

Handlers are defined just like regular tasks in Ansible, but with the difference that they are only triggered if notified by another task.

Basic Syntax for Handlers

Here’s a simple example of defining a handler in Ansible:

---
- name: Example of Handlers in Ansible
  hosts: all
  tasks:
    - name: Modify the configuration file
      copy:
        src: /path/to/new/config
        dest: /etc/application/config
      notify:
        - Restart application
  handlers:
    - name: Restart application
      service:
        name: application
        state: restarted

In this example:

  • The task Modify the configuration file copies a new configuration file.
  • The notify directive triggers the handler Restart application, which restarts the application service.
  • The handler is only executed if the configuration file has been changed, minimizing redundant restarts.

Key Points About Handlers

  • Notify Directive: A task notifies handlers using the notify keyword. This is how tasks communicate that they want a handler to be executed.
  • Execution Order: Handlers always execute after all tasks have been run, which ensures that changes are consolidated and executed in a controlled manner.
  • Uniqueness: Handlers are only triggered once, even if they are notified multiple times in a playbook. This ensures that services are not restarted unnecessarily.

Example of Handlers in Ansible

Example 1: Restarting a Service After File Change

Imagine you are configuring a web server and need to restart the service only if the configuration file is modified.

  

---
- name: Example of Handlers for Web Server
  hosts: webservers
  tasks:
    - name: Update Nginx configuration
      copy:
        src: /path/to/nginx/config
        dest: /etc/nginx/nginx.conf
      notify:
        - Restart nginx
  handlers:
    - name: Restart nginx
      service:
        name: nginx
        state: restarted

In this example:

  • The task Update Nginx configuration copies a new configuration file.
  • If the file is copied (i.e., it’s changed), the handler Restart nginx is notified and the Nginx service is restarted.

Example 2: Handling Multiple Changes in a Playbook

You may have multiple tasks that modify configurations, and you want to restart a service only once after all configurations are updated.

 

---
- name: Example of Multiple Handlers in Ansible
  hosts: all
  tasks:
    - name: Modify application configuration
      copy:
        src: /path/to/app/config
        dest: /etc/application/config
      notify:
        - Restart application
    - name: Modify database configuration
      copy:
        src: /path/to/db/config
        dest: /etc/database/config
      notify:
        - Restart application
  handlers:
    - name: Restart application
      service:
        name: application
        state: restarted

In this example:

  • Both tasks (modifying application and database configurations) notify the same handler Restart application.
  • The handler is triggered only once, even though it was notified twice, ensuring that the service is restarted just once.

Advanced Usage of Handlers in Ansible

Delaying Handler Execution with listen

You can use the listen directive to control the execution order of handlers and ensure that handlers are only executed when specific conditions are met. This is particularly useful in complex playbooks where you need to control the order of service restarts.

  

---
- name: Example of Handlers with Listen
  hosts: all
  tasks:
    - name: Modify configuration 1
      copy:
        src: /path/to/config1
        dest: /etc/application/config1
      notify:
        - Restart application
    - name: Modify configuration 2
      copy:
        src: /path/to/config2
        dest: /etc/application/config2
      notify:
        - Restart application
  handlers:
    - name: Restart application
      service:
        name: application
        state: restarted
      listen: "restart_application_handler"

In this example:

  • Both tasks notify the handler Restart application.
  • The listen directive ensures that only one handler is triggered, and handlers can be grouped together using this directive to control their execution.

Conditional Handlers

You can also use conditionals (when statements) to run handlers only under certain conditions.

---
- name: Example of Conditional Handlers
  hosts: all
  tasks:
    - name: Modify application config if needed
      copy:
        src: /path/to/config
        dest: /etc/application/config
      notify:
        - Restart application
      when: config_changed == true
  handlers:
    - name: Restart application
      service:
        name: application
        state: restarted

Here, the handler will only be triggered if the condition config_changed == true evaluates to true, adding flexibility to your automation scripts.

Best Practices for Using Handlers in Ansible

  1. Use Handlers for Expensive Operations: Handlers are perfect for actions like restarting services, reloading configurations, or performing tasks that are expensive or disruptive. Avoid running them unnecessarily.

  2. Consolidate Handlers: Group similar handler actions into a single handler. This avoids redundant operations, improving performance and keeping the playbook clean.

  3. Use Conditionals with Handlers: Conditional logic (via when) can be used within handlers to make sure they are executed only when required, further optimizing the playbook.

  4. Ensure Handler Idempotence: Handlers should be idempotent (i.e., they should not cause issues if run multiple times), as they are triggered based on state changes.

Ashutosh Dixit

I am currently working as a Senior Technical Support Engineer with VMware Premier Services for Telco. Before this, I worked as a Technical Lead with Microsoft Enterprise Platform Support for Production and Premier Support. I am an expert in High-Availability, Deployments, and VMware Core technology along with Tanzu and Horizon.

Leave a Reply