AnsiblePilot — Ansible Automation Platform and Enterprise Ansible

AnsiblePilot covers Red Hat Ansible Automation Platform (AAP) and enterprise Ansible: install and upgrade paths, Event-Driven Ansible, security and day-2 operations, plus Luca Berton's books, videos and training.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 9 technical books published by Apress and Leanpub, 4 of them on Ansible, including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible Handlers Explained: How to Use and Flush Handlers

By Luca Berton · Published 2023-03-13 · Category: troubleshooting

How to flush the execution of an Ansible handler after the notification task using the ansible.builtin.meta module.

Ansible Handlers Explained: How to Use and Flush Handlers

When do Ansible Handlers run?

> By default, handlers run after all the tasks in a particular play have been completed.

See also: Ansible Multiple Handlers: Run Handlers in Sequence (listen, notify)

  • https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#controlling-when-handlers-run

Demo

Let's jump into a real-life example of how to run an Ansible Handler immediately. First of all, we need a task changed status. The simplest Ansible module returning a "changed" status is Ansible command module with a Linux command, like "uptime". Let's suppose we would like to execute a handler immediately after the changed status and not wait for the next task using the ansible.builtin.meta module.

Initial Playbook

  • flush_before.yml
---
- name: handler Playbook
  hosts: all
  tasks:
    - name: changed status
      ansible.builtin.command: "uptime"
      notify: message 1

    - name: message 2
      ansible.builtin.debug:
        msg: message 2

  handlers:
    - name: message 1
      ansible.builtin.debug:
        msg: message 1

inventory

localhost ansible_connection=local

Initial Execution

As you can notice the message 1 handler is executed AFTER the last task (message 2) of the Play being executed.

$ ansible-playbook -i inventory flush_before.yml

PLAY [handler Playbook] *********************************************************************

TASK [Gathering Facts] ******************************************************************
ok: [localhost]

TASK [changed status] *******************************************************************
changed: [localhost]

TASK [message 2] ************************************************************************
ok: [localhost] => {
    "msg": "message 2"
}

RUNNING HANDLER [message 1] *************************************************************
ok: [localhost] => {
    "msg": "message 1"
}

PLAY RECAP ******************************************************************************
localhost                  : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Modified Playbook

Let's add the ansible.builtin.meta Ansible module after the first task.

---
- name: handler Playbook
  hosts: all
  tasks:
    - name: changed status
      ansible.builtin.command: "uptime"
      notify: message 1

    - name: flush
      ansible.builtin.meta: flush_handlers

    - name: message 2
      ansible.builtin.debug:
        msg: message 2

  handlers:
    - name: message 1
      ansible.builtin.debug:
        msg: message 1

Modified Execution

As you can notice the message 1 handler is executed BEFORE the last task (message 2) of the Play being executed.

% ansible-playbook -i inventory flush.yml    

PLAY [handler Playbook] *********************************************************************

TASK [Gathering Facts] ******************************************************************
ok: [localhost]

TASK [changed status] *******************************************************************
changed: [localhost]

TASK [flush] ****************************************************************************

RUNNING HANDLER [message 1] *************************************************************
ok: [localhost] => {
    "msg": "message 1"
}

TASK [message 2] ************************************************************************
ok: [localhost] => {
    "msg": "message 2"
}

PLAY RECAP ******************************************************************************
localhost                  : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Conclusion

Now you know how to run immediately an Ansible Handler in a Playbook.

See also: Ansible Scheduled Tasks: Cron Jobs & at Module for Timed Execution

When to Flush Handlers

- name: Deploy and configure application
  hosts: all
  become: true
  tasks:
    - name: Deploy new config
      ansible.builtin.template:
        src: app.conf.j2
        dest: /etc/myapp/app.conf
      notify: restart myapp

    # Flush handlers NOW — before the next task needs the service running
    - name: Force handler execution
      ansible.builtin.meta: flush_handlers

    - name: Verify service is running
      ansible.builtin.uri:
        url: http://localhost:8080/health
        status_code: 200
      retries: 5
      delay: 3

  handlers:
    - name: restart myapp
      ansible.builtin.service:
        name: myapp
        state: restarted

Handler Patterns

  handlers:
    # Chain handlers with listen
    - name: restart web stack
      ansible.builtin.debug:
        msg: "Restarting web stack"
      listen: "web config changed"

    - name: restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted
      listen: "web config changed"

    - name: restart php-fpm
      ansible.builtin.service:
        name: php-fpm
        state: restarted
      listen: "web config changed"

See also: Securely Automate Sudo Passwords in Ansible Playbooks

FAQ

When should I use meta: flush_handlers?

Use it when a subsequent task depends on the handler having already run — for example, restarting a service before testing it, or reloading configuration before deploying dependent services.

Do handlers run if the play fails?

By default, no. Use --force-handlers or set force_handlers: true in ansible.cfg to run notified handlers even when the play fails.

Can a handler notify another handler?

Yes, starting from Ansible 2.2. Handlers can notify other handlers, creating a chain of actions.

Category: troubleshooting

Watch the video: Ansible Handlers Explained: How to Use and Flush Handlers — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home