22

We have one Ansible role that needs to run three tasks in the handlers/main.yml task file, but it only runs the first task. How do I force it to run the other two tasks? I do have the ignore flag on for if the first task fails.

The tasks/main.yml file looks like:

- name: openfire | Copy plugins into openfire/plugins
  copy: src={{ srcdir }}/xmpp/{{ item }} dest=${bindir}/openfire/plugins/{{ item }}
  with_items:
   - x.jar
   - y.jar
  sudo: yes
  sudo_user: ${tomcat_user}
  notify: restart openfire

- name: openfire | Copy jars into openfire/lib
  copy: src={{ srcdir }}/xmpp/{{ item }} dest=${bindir}/openfire/lib/{{ item }}
  with_items:
   - a.jar
   - b.jar
  sudo: yes
  sudo_user: ${tomcat_user}
  notify: restart openfire

The handlers/main.yml file looks like:

- name: restart openfire
  service: name=openfire state=stopped
  ignore_errors: true
  sudo: yes

- name: restart openfire
  file: path=/var/run/openfire.pid state=absent
  sudo: yes

- name: restart openfire
  service: name=openfire state=restarted enabled=yes
  sudo: yes

Only the first handler task (shut down openfire) runs.

Mxx
  • 8,979
  • 4
  • 27
  • 37
Nova
  • 1,234
  • 3
  • 12
  • 25
  • I imagine it runs whatever matches 1st and then bails out from that playbook. Have you tried combining both of your `service` and `file` modules into a single block? That makes it harder to troubleshoot if things fail and is very ugly, but it should still work. – Mxx Jan 28 '14 at 04:54
  • It used to work. I'm wondering if our lead installed some ansible libraries... the executables we are using have not changed. I think I will eliminate using handlers completely for this openfire installation and just force a service start at the end of the normal playbook. – Nova Jan 28 '14 at 20:17
  • wait a second. I just looked at your playbook and it looks really strange..Why are you stopping a service, then deleting its pid file and then restarting it? Why don't you just do a single `state=restarted` statement? That will actually _restart_(stop and start) your service. – Mxx Jan 28 '14 at 23:48
  • I don't know. I need to find out from the original developer why he did it that way. The handler is called in the playbook when new jars are placed into openfire and everything after that is just minor tweaks that do not affect tomcat. I think it would be safe to just stick a regular old state=restarted in the playbook itself and not have this be a handler. – Nova Jan 29 '14 at 23:44
  • handlers are meant to be run when something changes, it looks like it might be better if you move your handlers into your tasks – dalore Feb 10 '14 at 13:32
  • I have done exactly that. I do not understand why the handler was used in the first place. I took out the two "notify" statements and added a final task to start the Openfire service and all is working well now. – Nova Feb 10 '14 at 21:30

4 Answers4

28

Its possible for handler to call another notify. Multiple notify calls are also allowed:

---
- name: restart something
  command: shutdown.sh 
  notify:
    - wait for stop
    - start something
    - wait for start

- name: wait for stop
  wait_for: port={{port}} state=stopped

- name: start something
  command: startup.sh

- name: wait for start
  wait_for: port={{port}} state=started
iTake
  • 4,082
  • 3
  • 33
  • 26
23

As of Ansible 2.2, you can now notify multiple handlers at the same time using the listen directive:

- name: stop openfire
  listen: restart openfire
  service: name=openfire state=stopped
  ignore_errors: true
  sudo: yes

- name: remove openfire pid file
  listen: restart openfire
  file: path=/var/run/openfire.pid state=absent
  sudo: yes

- name: restart openfire
  listen: restart openfire
  service: name=openfire state=restarted enabled=yes
  sudo: yes
Xiong Chiamiov
  • 13,076
  • 9
  • 63
  • 101
  • Using 'topic' with the `listen` directive is an officially documented way to run severl tasks in a handler. I feel this is the best answer. – luqo33 Mar 26 '17 at 18:04
9

Maybe it is too late, since your post is from January, but... why are you naming identically all the different handlers? It is supposed for the handlers to be called in the tasks by their name, so maybe you need to name them differently. Try to change the handlers file to something like this:

- name: stop openfire
  service: name=openfire state=stopped
  ignore_errors: true
  sudo: yes

- name: remove openfire pid
  file: path=/var/run/openfire.pid state=absent
  sudo: yes

- name: restart openfire
  service: name=openfire state=restarted enabled=yes
  sudo: yes

Anyway, I agree with Mxx in the point that this handlers file is quite strange. It should be enough with a state=restarted.

José L. Patiño
  • 3,683
  • 2
  • 29
  • 28
8

The way the example code above is using notify in Ansible isn't officially supported, so I'm not surprised it's not working (and would be surprised if it ever were really working). In your particular case, using one task in your playbook, or a handler that simply uses state=restarted to restart the service, would be a better option:

- service: name=openfire state=restarted enabled=yes

However, if you do need to have multiple handlers run as a result of one operation, the best way to do it would be to notify each separate command in a chain. Note that this is almost always indicative of a deeper problem... but every once in a while, I've had to notify another handler after a certain handler completed, like so:

# Inside handlers/main.yml:
- name: import database
  mysql_db: name=database state=import target=/path/to/dump.sql
  notify: run shell script

- name: run shell script
  shell: /path/to/some/shell/script.sh

This should be pretty rare, but I wouldn't think it's too bad an option for certain scenarios (in my case, I had to import a database dump, then run a shell script after that was complete, and the best way to make that operation idempotent was to notify the import database handler instead of try doing the import directly in my playbook).

geerlingguy
  • 4,682
  • 8
  • 56
  • 92
  • 1
    I need to disagree. The ``notify`` directive up there is correctly used, according with the latest documentation and with several of my own playbooks. You can define tasks in ``handlers/main.yml`` file which you can call via ``notify`` in your ``tasks/*`` files without any problem and, in fact, it is the correct way to do it. Check out [this repo](https://github.com/jose-lpa/ansible_jenkins-nginx/tree/master/roles/jenkins-ci) for a simple example if you want :) – José L. Patiño Mar 26 '14 at 08:15
  • 4
    I wasn't implying you can't call handlers from tasks/playbooks, only that you can't define multiple handlers with the exact same name, and expect all of them to be called. This answer simply shows how you can call multiple handlers in succession, if need be. – geerlingguy Mar 26 '14 at 12:28
  • I'm *amazed* to discover this, as it makes handlers massively less useful for re-usable roles. You have to have exactly one listener for a notification? really? – Craig Ringer Apr 26 '15 at 13:03
  • One other way to achieve it is to create some additional tasks with `debug` module and attach different `notify` with each one. – pawel7318 Jun 16 '15 at 07:54
  • [Issue 4943](https://github.com/ansible/ansible/issues/4943) states > If you want to trigger multiple handlers, handlers are unique by name. It's certainly not yet clearly spelled out in the docs @CraigRinger. – Marc Tamsky Jul 15 '15 at 09:38
  • @user31209 Exactly. The triggering role has to know the name(s) of all the handlers it's going to trigger. So if you want a "my_server" role, you have to copy and edit it for each deployment, adding a list of handlers for the applications/extensions/whatever you want to deploy on that particular instantiation that need to do an action at a particular stage. It's backwards IMO. The opposite of OO modular development. The cart is pushing the horse. Handlers are useful, but very limited because of this. You should be able to fire *events* and have registered listeners take action on the event. – Craig Ringer Jul 15 '15 at 09:45
  • @CraigRinger - you may not want to admit the situation isn't as bad as you make it out to be, but the reality is, handlers exist in a global namespace, and unrelated roles could declare overlapping names; see [discussion by mdehaan](https://groups.google.com/d/msg/ansible-project/qtyWGOQN3O8/uPpMr0LpsD8J). The OO _event_ model you're describing _is_ possible by declaring a uniquely-named "event" `handler` that does nothing but "dispatch" more `notify` _events_ to several additional uniquely-named handlers. – Marc Tamsky Jul 19 '15 at 06:12