50

I'm using Ansible to provision my development server.

I want it to always start some services for me. I have handlers for this purpose but what is the best way to trigger handler execution without condition, e.g. make it always work?

Something like this:

tasks:
    - name: Trigger handler
      run_handler: name=nginx-restart
Slava Fomin II
  • 1,661
  • 4
  • 17
  • 22
  • 6
    If you want a task to always run you should make it a task rather than a handler. – Jordan Feb 12 '15 at 15:21
  • @Jordan - sometimes you may want to have a handler that's conditionally triggered in most scenarios except this particular one. – silverdr Jul 30 '17 at 19:15

3 Answers3

81

If you absolutely need to trigger a handler every time then here are two options:

1) run a noop shell command which will always report as changed

-  name: trigger nginx-restart
   command: /bin/true
   notify: nginx-restart

2) use debug along with changed_when: to trigger a handler

-  debug: msg="trigger nginx-restart"
   notify: nginx-restart
   changed_when: true

Also of note for Option 1 and Check Mode: You may want to use check_mode: no if using Ansible version 2.2 or higher or always_run: yes if using earlier versions than that so that the task does not get skipped over in check mode. From my manual testing it looks like the handlers remain in check mode, but please be careful as your case may differ.

jarv
  • 1,253
  • 9
  • 6
  • 9
    Nowadays, you can ` --force-handlers run handlers even if a task fails` – conny May 07 '15 at 08:34
  • 6
    Yes though that will force all handlers to run – jarv May 08 '15 at 09:45
  • i found this post useful regarding the changed status, that lead me here. https://serverfault.com/a/799282/173002. ty. – sonjz Jan 10 '18 at 01:38
  • Thanks, I used option 2 and a `changed_when` with more logic in it to implement a non-idempotent task [which may be invoked more than once in some cases] as a handler rather than a task. – Sammitch Nov 29 '18 at 00:27
  • For me a combination of both options did it, as I needed the task itself to check a variable using `when`. Thanks! – Thorian93 Aug 12 '20 at 11:32
20

Ansible provides several options for forcing handlers:

  1. To always force all handlers, run ansible-playbook playbook.yml --force-handlers, as documented here: https://github.com/ansible/ansible/issues/4777

  2. To force handlers that have been notified at a specific point within a playbook, you can use a meta task https://docs.ansible.com/playbooks_intro.html:

    tasks:

    • shell: some tasks go here
    • meta: flush_handlers
    • shell: some other tasks
  3. However, it sounds like you just want to make sure a service is running or restarted, regardless of the outcome of another task. In that case, don't use a handler, use a new task that calls Ansible's service module: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html

    tasks:

    • name: ensure ntp is running service: name=ntp state=started enabled=yes

    • name: always reload nginx service: name=nginx state=reloaded

    • name: always restart MySQL service: name=mysql state=restarted

cdmo
  • 113
  • 5
Jeff Widman
  • 2,285
  • 3
  • 22
  • 20
  • 2
    The problem with (3) is that one might have several tasks which notify the handler, and I don't want the handler to run (restarting the service) several times. – Jonathan Hartley Oct 07 '15 at 10:51
  • Multiple tasks can notify the same handler, and the handler will only execute once. That's the whole point of handlers. – Jeff Widman Dec 02 '15 at 19:37
  • Hey Jeff. This answer is about not using handlers, specifying all actions just using tasks. – Jonathan Hartley Dec 04 '15 at 23:38
  • Sorry, I'm afraid I still don't understand the use case you're trying to solve for... Maybe open a new question with an example of what you're trying to accomplish? If you add a comment with a link to it I'll try to answer it. – Jeff Widman Dec 05 '15 at 00:36
  • 1
    I don't need a new question. The OQ asked "How can I make sure a handler ALWAYS runs", and this answer, part 3, suggested "Use tasks instead", and my comment points out "Your task might then run several times in some circumstances." – Jonathan Hartley Dec 07 '15 at 14:17
  • 1
    I believe the documentation you refer to in issue #4777 is incorrect: `--force-handlers` does not unconditionally run all handlers. https://unix.stackexchange.com/a/327595/29483 The behaviour of `--force-handlers`, which is correctly documented nearly everywhere else e.g. in the man page and the ansible user guide, is that *notified* handlers will be run even if the play stops early due to a failed task. – sourcejedi May 17 '18 at 11:24
  • @JonathanHartley Have you found a solution that ensures a service runs without restarting it (again) when handlers run? – wedi Jun 15 '20 at 08:44
  • @wedi I did not. – Jonathan Hartley Jun 16 '20 at 19:08
11

Restarting a service is one thing; ensuring it is running is another. If you want ansible to make sure nginx is running, you do this:

tasks:
  - name: Ensure nginx is running
    service: name=nginx state=started
Antonis Christofides
  • 2,556
  • 2
  • 22
  • 35