π Understanding Tasks β The Core Building Block
A task is a single unit of work that Ansible executes against a host.
π Table of Contents
- π Understanding Tasks β The Core Building Block
- π§ Understanding Handlers β Deferred Idempotent Actions
- βοΈ When to Use Tasks Directly β Straightforward Changes
- ποΈ Idempotent Operations
- π¦ Service Management without Dependency
- π’ When Handlers Provide Value β Coordinated State Changes
- π Deferred Restarts
- π Conditional Triggers
- π© Final Thoughts
- β Frequently Asked Questions
- Can a handler be notified by more than one task?
- Do handlers respect
whenclauses? - Is it possible to force a handler to run immediately?
- π References & Further Reading
π§ Understanding Handlers β Deferred Idempotent Actions
A handler is a special task that runs only when notified by another task and only after the entire play finishes.
# handlers.yml
- name: restart nginx service: name: nginx state: restarted
What this does:
-
service: interacts with the system's init system;
restartedtriggers a stop then start only if the service is already running.
Handlers are defined separately from regular tasks but live in the same playbook or role. A task can notify a handler; the handler is queued and executed once all tasks in the play have succeeded. This guarantees that a service restart occurs after all configuration files have been updated.
Key point: Handlers provide a safe, deferred way to react to changes without interrupting a partially applied configuration.
βοΈ When to Use Tasks Directly β Straightforward Changes
This section outlines situations where a regular task suffices and a handler adds no value.
ποΈ Idempotent Operations
Tasks that are already idempotent and do not require a later action can remain as plain tasks. Installing a package or creating a user follows this pattern.
# install_user.yml
- name: Create deploy user user: name: deploy state: present groups: sudo
The user module creates the account only if it does not exist, so no additional coordination is needed.
π¦ Service Management without Dependency
If a service must be started or stopped unconditionally, invoke the service module directly.
# start_service.yml
- name: Ensure nginx is running service: name: nginx state: started
Running the playbook produces the following output:
$ ansible-playbook start_service.yml
PLAY [all] ********************************************************************* TASK [Gathering Facts] *********************************************************
ok: [web01] TASK [Ensure nginx is running] *************************************************
changed: [web01] PLAY RECAP *********************************************************************
web01: ok=2 changed=1 unreachable=0 failed=0
The service starts immediately; no later tasks depend on its state, so a handler would introduce unnecessary complexity. (More onPythonTPoint tutorials)
Key point: Use tasks alone when the action is independent and idempotent, avoiding the overhead of notifications.
π’ When Handlers Provide Value β Coordinated State Changes
This section describes scenarios where deferring an action via a handler is the appropriate choice.
π Deferred Restarts
When multiple tasks modify files that affect the same service, restart the service only once after all changes are applied.
# site.yml
- hosts: webservers become: true tasks: - name: Update nginx.conf copy: src: nginx.conf dest: /etc/nginx/nginx.conf notify: restart nginx - name: Deploy site content copy: src: index.html dest: /var/www/html/index.html notify: restart nginx handlers: - import_tasks: handlers.yml
Running the playbook yields:
$ ansible-playbook site.yml
PLAY [webservers] ************************************************************* TASK [Gathering Facts] *******************************************************
ok: [web01] TASK [Update nginx.conf] *****************************************************
changed: [web01] TASK [Deploy site content] ***************************************************
changed: [web01] RUNNING HANDLER [restart nginx] *********************************************
changed: [web01] PLAY RECAP *******************************************************************
web01: ok=4 changed=3 unreachable=0 failed=0
The handler runs once, after both files are copied, guaranteeing a single restart.
π Conditional Triggers
Handlers can be conditioned on variables, allowing fineβgrained control.
# conditional_handler.yml
- hosts: webservers vars: restart_needed: "{{ (ansible_facts['distribution'] == 'Ubuntu') }}" tasks: - name: Update config copy: src: nginx.conf dest: /etc/nginx/nginx.conf notify: restart nginx handlers: - name: restart nginx service: name: nginx state: restarted when: restart_needed
Only Ubuntu hosts execute the restart, demonstrating selective notification.
According to the Ansible documentation, handlers are executed in the order they are defined, after all tasks in the current play have completed.
| Aspect | Task | Handler |
|---|---|---|
| Execution Timing | Immediately when encountered | Queued, runs at end of play |
| Idempotence Requirement | Must be idempotent itself | Often idempotent, but can be nonβidempotent (e.g., restart) |
| Use Case | Simple state changes | Coordinated actions after multiple changes |
Key point: Handlers excel when a single, coordinated reaction to several related changes is required.
π© Final Thoughts
Choosing between tasks and handlers hinges on the need for deferred execution. If a change can be applied independently and does not affect other resources, a plain task keeps the playbook simple and readable. When multiple changes converge on a single service or system component, a handler guarantees that the dependent action runs exactly once, after the entire set of changes succeeds.
Understanding the mechanismβtasks run in order, handlers are queued and executed after the playβlets you design playbooks that are both efficient and reliable. Aligning the choice with the desired execution semantics avoids unnecessary restarts and reduces the risk of transient failures.
β Frequently Asked Questions
Can a handler be notified by more than one task?
Yes. Multiple tasks can use the same notify name; the handler still runs only once per play, regardless of how many notifications it receives.
Do handlers respect when clauses?
Handlers can include when conditions, and they are evaluated at the time the handler runs, after all tasks have completed.
Is it possible to force a handler to run immediately?
Using the meta: flush_handlers task forces any queued handlers to execute at that point in the playbook.
π‘ Want to practise this hands-on? DigitalOcean gives new accounts $200 free credit for 60 days β enough to spin up a full Linux/Docker/Kubernetes environment at no cost.
π Recommended reading: Best DevOps & cloud books on Amazon β from Linux fundamentals to Kubernetes in production, curated for working engineers.
π References & Further Reading
- Official Ansible documentation on handlers β detailed behavior and examples: docs.ansible.com
- Understanding Ansible task execution order β insight into playbook flow: docs.ansible.com
- Best practices for idempotent Ansible modules β why idempotence matters: docs.ansible.com

Top comments (0)