Handler: In which order are Role Handlers executed?

Hi,

We are currently asking ourselves in Team in which order handlers are executed from roles. We have several roles in a playbook with several handlers. In some playbooks, the handlers are executed in alphabetical order of the roles, but not in all playbooks.

We can’t find anything in the documentation either: Handlers: running operations on change — Ansible Community Documentation

They are executed based on the order they are defined in. Here’s a relevant snippet from the documentation:

In the above example, the handlers are executed on task change in the following order: Restart memcached, Restart apache. Handlers are executed in the order they are defined in the handlers section, not in the order listed in the notify statement.

This is the Roles Part of our Playbook:

roles:
    - role: elasticsearch-apikey
    - role: haproxy
    - role: executable-jar

This is the Result:

RUNNING HANDLER [elasticsearch-apikey : esapikey_invalidate_keys] **************
Tuesday 30 July 2024  17:04:14 +0200 (0:00:01.281)       0:00:34.533 ********** 
ok: [server11-dev]

RUNNING HANDLER [executable-jar : Executable_jar is restarted] *****************
Tuesday 30 July 2024  17:04:16 +0200 (0:00:01.590)       0:00:36.123 ********** 
changed: [server11-dev]

RUNNING HANDLER [executable-jar : Executable_jar is alive] *********************
Tuesday 30 July 2024  17:04:16 +0200 (0:00:00.518)       0:00:36.641 ********** 
ok: [server11-dev]

RUNNING HANDLER [haproxy : Haproxy Daemon reload] ******************************
Tuesday 30 July 2024  17:04:23 +0200 (0:00:07.031)       0:00:43.673 ********** 
ok: [server11-dev]

RUNNING HANDLER [haproxy : Haproxy started] ************************************
Tuesday 30 July 2024  17:04:24 +0200 (0:00:00.850)       0:00:44.523 ********** 
ok: [server11-dev]

RUNNING HANDLER [haproxy : Haproxy restarted] **********************************
Tuesday 30 July 2024  17:04:25 +0200 (0:00:00.499)       0:00:45.023 ********** 
changed: [server11-dev]

RUNNING HANDLER [haproxy : Haproxy reloaded] ***********************************
Tuesday 30 July 2024  17:04:26 +0200 (0:00:00.946)       0:00:45.970 ********** 
changed: [server11-dev]

But this is not the Order we defined!

Can you include the relevant handlers files so I can see the order they are defined in to try to reproduce the issue? Can you share the version of ansible-core you’re using too?

/roles/elasticsearch-apikey/handlers/main.yml:

- name: esapikey_invalidate_keys
  ansible.builtin.uri:
    url: "{{ esapikey_url }}/_security/api_key"

/roles/executable-jar/handlers/main.yml:

- name: Executable_jar is restarted
  ansible.builtin.service:
    name: executable-jar
    state: restarted
    enabled: true
  become: true
  listen: executable_jar_restarted

- name: Executable_jar is alive
  ansible.builtin.uri:
    url: "{{ executable_jar_alive_url }}"
    status_code: 200
  register: result
  until: result.status == 200
  retries: 60
  delay: 1
  tags: config
  listen: executable_jar_alive
  when:
    - not ansible_check_mode
    - executable_jar_alive_check

/roles/haproxy/handlers/main.yml:

- name: Haproxy Daemon reload
  ansible.builtin.systemd:
    daemon_reload: true
  become: true
  listen: Haproxy_daemon_reload

- name: Haproxy started
  ansible.builtin.service:
    name: haproxy
    state: started
    enabled: true
  become: true
  listen: Haproxy_started

- name: Haproxy restarted
  ansible.builtin.service:
    name: haproxy
    state: restarted
    enabled: true
  become: true
  listen: Haproxy_restarted

- name: Haproxy reloaded
  ansible.builtin.service:
    name: haproxy
    state: reloaded
    enabled: true
  become: true
  listen: Haproxy_reloaded

The handlers file in haproxy defines the handlers in this order:

  • Haproxy Daemon reload
  • Haproxy started
  • Haproxy restarted
  • Haproxy reloaded

The result you shared matches the order, I think.

I’m not sure where the handlers are notified, or if this could be a point of misunderstanding, but the notify order is not the definition-order. Here’s the relevant bit from the documentation:

Handlers are executed in the order they are defined in the handlers section, not in the order listed in the notify statement.

If I’m missing something, could you share the expected result?

First, handlers, no matter where defined, are attached to the play, so while a role can provide handlers they are always PLAY level handlers. The order of execution depends on the order in which they were added/defined to the play. This can get tricky with dependent roles and conflicting names, but should still hold true.

We have no dependency’s in our Roles. If I understand you correctly, all (handlers in the) roles should now be executed in the same order as listed under “roles:”, but currently they are executed in alphabetical order.

Is it possible to debug the order of handlers?

We dont want to flush the handlers at the end of each Role, just to ensure they get executed in the right order.

We have 3 Roles with Handlers:

roles:
    - role: Role_A
    - role: Role_C
    - role: Role_B

and I expect these execution Order of the handlers:

- Role_A_Handler_1
- Role_A_Handler_2
- Role_C_Handler_1
- Role_C_Handler_2
- Role_B_Handler_1
- Role_B_Handler_2

but I get:

- Role_A_Handler_1
- Role_A_Handler_2
- Role_B_Handler_1
- Role_B_Handler_2
- Role_C_Handler_1
- Role_C_Handler_2

And what is the order of handler notifies? Same as role order? Do you notify a handler in one role from some other role?

No, we have no cross roles notify. All handler get notified in there own Role.

Notification should not influence execution order, if the above is true, this is a bug. I would submit to github with a simple reproducer.

1 Like

I created a simple reproducer, but everything runs just fine - no Bug!
Now we have to test our Ansible Setup and all used Versions for the cause of the problem :expressionless:

I found our Problem. We have used the same Role more than once in the same Playbook.

  roles:
    - role: role_2
    - role: role_1
    - role: role_3
    - role: role_1

Handler Executon Order:

  • role_2
  • role_3
  • role_1
1 Like

So it works as expected, role1 handlers get ‘redefined’ so the first definition is masked by the latter, accounting for the change in order.