After completing this section, you should be able to implement a task that runs only when another task changes the managed host.
Ansible modules are designed to be idempotent. This means that in a properly written playbook, the playbook and its tasks can be run multiple times without changing the managed host unless they need to make a change to get the managed host to the desired state.
Handlers are tasks that respond to a notification triggered by other tasks. Tasks only notify their handlers when the task changes something on a managed host. Each handler is triggered by its name after the play's block of tasks. If no task notifies the handler by name then the handler will not run. If one or more tasks notify the handler, the handler will run exactly once after all other tasks in the play have completed. Because handlers are tasks, administrators can use the same modules in handlers that they would use for any other task. Normally, handlers are used to reboot hosts and restart services.
Use unique names for your handlers. When multiple handlers are defined with the same name, only the last handler defined with the shared name will run.
Handlers can be considered as inactive tasks that only get triggered when explicitly invoked using a notify statement.
The following snippet shows how the Apache server is only restarted by the restart apache handler when a configuration file is updated and notifies it:
tasks: - name: copy demo.example.conf configuration templatetemplate: src: /var/lib/templates/demo.example.conf.template dest: /etc/httpd/conf.d/demo.example.conf notify:
- restart apache
handlers:
- name: restart apache
service:
name: httpd state: restarted
The task that notifies the handler. | |
The | |
The name of the handler to run. | |
The | |
The name of the handler invoked by tasks. | |
The module to use for the handler. |
In the previous example, the restart apache handler triggers when notified by the template task that a change happened.
A task may call more than one handler in its notify section.
Ansible treats the notify statement as an array and iterates over the handler names:
tasks:
- name: copy demo.example.conf configuration template
template:
src: /var/lib/templates/demo.example.conf.template
dest: /etc/httpd/conf.d/demo.example.conf
notify:
- restart mysql
- restart apache
handlers:
- name: restart mysql
service:
name: mariadb
state: restarted
- name: restart apache
service:
name: httpd
state: restartedAs discussed in the Ansible documentation, there are some important things to remember about using handlers:
Handlers always run in the order specified by the handlers section of the play.
They do not run in the order in which they are listed by notify statements in a task, or in the order in which tasks notify them.
Handlers normally run after all other tasks in the play complete.
A handler called by a task in the tasks part of the playbook will not run until all tasks under tasks have been processed.
(There are some minor exceptions to this.)
Handler names exist in a per-play namespace. If two handlers are incorrectly given the same name, only one will run.
Even if more than one task notifies a handler, the handler only runs once. If no tasks notify it, a handler will not run.
If a task that includes a notify statement does not report a changed result (for example, a package is already installed and the task reports ok), the handler is not notified.
The handler is skipped unless another task notifies it.
Ansible notifies handlers only if the task reports the changed status.
Handlers are meant to perform an extra action when a task makes a change to a managed host. They should not be used as a replacement for normal tasks.