4tcw7w
Last Updated: March 29, 2016
·
14.83K
· rickhanlonii
Regent twitter

Setting Supervisor to *really* stop Django runserver

If you're using Supervisor and adding Django to it via

[program:some_django]
command=python manage.py runserver
directory=/dir/to/app

then you may notice that when you stop the some_django program (or kill the process) there is still a process running from your runserver command. And if you try to start the server back up, you'll raise an error because the port is in use!

If you look close enough, you'll see that this process's parent ID is the one which is now dead. What we have here is a rogue orphan.

Many thanks to Simon Pantzare for getting me on the right track. He recommends adding:

[program:some_django]
...
stopsignal=KILL
killasgroup=true

I tried and tested it by executing

supervisorctl stop some_django

but the orphaned process was still there. Looking into the docs, I found what I needed. You see, killasgroup kills all processes in the group when Supervisor resorts to sending a SIGKILL. The idea is that when the process is playing nicely, it should be allowed to handle stoping it's children on its own. But when it misbehaves and needs a bullet to the bits, you may need an option which that gives you the power to drag the whole family to the gallows for execution as well. From CHANGES.txt:

- Add a boolean program option `killasgroup`, defaulting to false, if true when resorting to send SIGKILL to stop/terminate the process send it to its whole process group instead to take care of possible children as well and not leave them behind.  Patch by Samuele Pedroni.

But when I ran the stop command, and even through the stopsignal was set to KILL, Supervisor wasn't inside the blocks that consider the killasgroup setting.

After digging through the docs and source, I found that I needed to use stopasgroup (which was added after killasgroup). From CHANGES.txt again:

- Add a boolean program option `stopasgroup`, defaulting to false. When true, the flag causes supervisor to send the stop signal to the whole process group.  This is useful for programs, such as Flask in debug mode, that do not propagate stop signals to their children, leaving them orphaned.  

So, the settings that works for running Django's runserver command in Supervisor is:

[program:some_django]
command=python manage.py runserver
directory=/dir/to/app
stopasgroup=true  

A few closing notes:

  1. Setting stopasgroup to true sets killasgroup to true as well. See options.py:

    stopasgroup = boolean(
            get(section, 'stopasgroup', 'false'))
    killasgroup = boolean(
            get(section, 'killasgroup', stopasgroup))  
  2. Setting stopasgroup to true and killasgroup to false raises an error. From options.py again:

    if stopasgroup and not killasgroup:
      raise ValueError(
        "Cannot set stopasgroup=true and killasgroup=false"
      )
Say Thanks
Respond

15 Responses
Add your response

6366
Ccc9abdf9963f3452808cff0e77679a1

Really cool you shared how you got to your solution. Thanks!

over 1 year ago ·
6368
573dea5358a619ba2c2798d412601228

I had trouble with this some time ago, if you use the "--noreload" argument Django will create a single process.

over 1 year ago ·
9162
92cc6c7d8ee5e633702b3a9cf097ffd3

cannot stop all processes, after adding lines, still one process is keeps running, how to solve this problem ? any solution ?

over 1 year ago ·
9272
Regent twitter

Can you post your config file yspanchal?

over 1 year ago ·
9853

hi all i have the same problem, where i add --noreload??

this is my config file:

[program:xxx]
command=path/.virtualenvs/dev_env/bin/python2.7 mypath/xxx/manage.py runserver 0.0.0.0:8082
directory=mypath/Proxy/xxx

stdoutlogfile=mypath/logs/xxxoutput.log
redirect_stderr=true

autostart=false
autorestart=false
priority=991

stopsignal=KILL
killasgroup=true
stopasgroup=true

over 1 year ago ·
9879
Regent twitter

@zoubydazarkouna can you fix the formatting for your log file?

over 1 year ago ·
9880

thanks for your reponse i fix my prob :
in command line i add --noreload option :

manage.py runserver 0.0.0.0:8082 directory=mypath/Proxy/xxx --noreload

over 1 year ago ·
11032
541296 623400141007383 906650011 n

My Supervisord cannot stop django-celery processes even with the 'stopasgroup=true' config.

over 1 year ago ·
12400
75193502521ba1b49cbb5e7d2a1221a0

+1 on the --noreload

over 1 year ago ·
16255
6bd5d2ba21271661c83db319b87f4749

solved my problem.

over 1 year ago ·
19338
None

Hi! You are the man! Thanks.

over 1 year ago ·
19339
None

Hi! You are the man! Thanks.

over 1 year ago ·
20689
49cb85a46fd8c961f659e3e397495448

It works with my Flask app! Thanks!

over 1 year ago ·
27391
052a899410cbeab04fd435b7058bf717

Thank you. It does help for my Flask app.

over 1 year ago ·
27458

Thank you for this.

over 1 year ago ·