Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shutdown supervisord once one of the programs is killed #712

Closed
EslamElHusseiny opened this issue Jan 18, 2016 · 9 comments
Closed

shutdown supervisord once one of the programs is killed #712

EslamElHusseiny opened this issue Jan 18, 2016 · 9 comments

Comments

@EslamElHusseiny
Copy link

Hi,
I've two programs managed by supervisord.
Is there anyway to shutdown supervisord once of those programs is killed ?

@tarrychk
Copy link

You can achive this with an event listener:

supervisord-watchdog:

#!/usr/bin/python
import sys
import os
import logging
import subprocess
import time

from supervisor.childutils import listener

def main(args):
    logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, format='%(asctime)s %(levelname)s %(filename)s: %(message)s')
    logger = logging.getLogger("supervisord-watchdog")
    debug_mode = True if 'DEBUG' in os.environ else False

    while True:
        logger.info("Listening for events...")
        headers, body = listener.wait(sys.stdin, sys.stdout)
        body = dict([pair.split(":") for pair in body.split(" ")])

        logger.debug("Headers: %r", repr(headers))
        logger.debug("Body: %r", repr(body))
        logger.debug("Args: %r", repr(args))

        if debug_mode: continue

        try:
            if headers["eventname"] == "PROCESS_STATE_FATAL":
                logger.info("Process entered FATAL state...")
                if not args or body["processname"] in args:
                    logger.error("Killing off supervisord instance ...")
                    res = subprocess.call(["/bin/kill", "-15", "1"], stdout=sys.stderr)
                    logger.info("Sent TERM signal to init process")
                    time.sleep( 5 )
                    logger.critical("Why am I still alive? Send KILL to all processes...")
                    res = subprocess.call(["/bin/kill", "-9", "-1"], stdout=sys.stderr)
        except Exception as e:
            logger.critical("Unexpected Exception: %s", str(e))
            listener.fail(sys.stdout)
            exit(1)
        else:
            listener.ok(sys.stdout)

if __name__ == '__main__':
    main(sys.argv[1:])

Then add this config snippet:

[eventlistener:supervisord-watchdog]
command=/path/to/supervisord-watchdog
events=PROCESS_STATE_FATAL

@tarrychk
Copy link

That eventlistener snippet above was written for running supervisord in a docker container where it would have PID 1. You'll have to replace the kill commands with something suitable for your use case, like "pkill", "-15", "supervisord".

@mnaberez
Copy link
Member

Writing an eventlistener similar to the one above is the recommended way to achieve this. More examples of eventlisteners can be found in the Superlance package.

@tillahoffmann
Copy link

tillahoffmann commented Jun 12, 2018

This is probably not the recommended way of shutting down supervisor but the following configuration has worked well for me.

[program:something]
command = bash -c "something && kill -s SIGINT `cat supervisord.pid`"
stopasgroup = true

; other bits

It will execute something and then interrupt the supervisord process.

@bdusell
Copy link

bdusell commented Jan 20, 2019

The watchdog script works well if none of the processes exit immediately -- I've been using something similar on my server for over a year. But if one of the processes exits before Supervisor starts the watchdog process (e.g. Nginx exits because its configuration file has a syntax error), then Supervisor continues to run. Setting priority=1 on the watchdog doesn't help.

@tillahoffmann 's solution avoids this problem, avoids running an extra process, and is much simpler.

@mnaberez
Copy link
Member

mnaberez commented Apr 1, 2020

Note for maintainers: See additional comments in #1340.

@mnaberez
Copy link
Member

This issue was reopened in error. Usually when we need to watch processes and perform some configurable action based on their behavior, we implement those things in eventlisteners rather than supervisord itself. This was a design decision that was made a long time ago and why the eventlistener system came about.

For example, it kept coming up that a subset of users wanted to monitor when a process uses "too much" memory and perform some action as a result. It was decided to keep that functionality in eventlisteners. The same points were raised in those tickets, e.g. some users do not want to run an extra eventlistener process. However, eventlisteners were written to do it and users run them. Overall, it seems to have worked out.

Similarly here, some users want to monitor when a process does something and cause supervisord itself to exit as a result. Users have reported successfully using eventlisteners in those scenarios. At least for the time being, we are going to continue to recommend that approach since it's what we do for similar things.

@sdshq
Copy link

sdshq commented Nov 25, 2022

This is probably not the recommended way of shutting down supervisor but the following configuration has worked well for me.

[program:something]
command = bash -c "something && kill -s SIGINT `cat supervisord.pid`"
stopasgroup = true

; other bits

It will execute something and then interrupt the supervisord process.

This is a great idea and helps me out. A minor issue: it would not make supevisord to exit by invoking supervisorctl stop something, since it kills the bash.

@ahmedabdou14
Copy link

the solution above #712 (comment) won't work if your program exists with a non 0 code

it will equate to false && true which will not execute the second statement.
What you need in this case is false || true

[program:something]
command = bash -c "something || kill -s SIGINT `cat supervisord.pid`"
stopasgroup = true

; other bits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

7 participants