supervisorctl重启服务发现存在子进程未完全关闭导致端口占用

问题

默认 Supervisor 只杀主进程,不会把子进程(worker)一起杀。
Gunicorn 是 master + workers 架构,所以会留下孤儿进程。

8da8624806af6bb64f00e4f79aff3722.png

解决

1. stopped`状态下仍然被Supervisor拉起进程

1.1. autostart=true

  • 作用:Supervisor 启动时,会自动启动该程序(系统重启)。

  • 如果你手动 supervisorctl stop auto_screen,但是后面你又执行了 supervisorctl reloadupdate,Supervisor 会重新按配置把它启动(因为配置写了 autostart=true)。

  • 解决:如果你希望停掉后就不再拉起,把它改成

    1
    autostart=false
  1. autorestart=true

    • 作用:只要进程退出(非手工标记为 STOPPED),Supervisor 会立刻拉起。

    • 所以哪怕你用 kill 杀掉进程,它也会起来。

    • 如果你希望手动停掉后不再自动启动,可以改为:

      1
      autorestart=false
    • 或者精细控制:

      1
      2
      autorestart=unexpected
      exitcodes=0

      表示只有非 0 异常退出才重启,正常退出不再拉起。


2.stop支持关闭work进程

默认 Supervisor 只杀主进程,不会把子进程(worker)一起杀。

Gunicorn 是 master + workers 架构,所以会留下孤儿进程。

解决方法,在 [program:auto_screen] 段里加上:
stopasgroup=true
killasgroup=true

这样 Supervisor 停止时会把整个进程组都干掉。

3.stop/start能彻底关闭启动服务

# 支持自启动
autostart=true

# 进程异常关闭支持自动拉起
autorestart=unexpected
exitcodes=0

# stop关闭master/slave进程
stopasgroup=true
killasgroup=true

Gunicorn + Supervisor配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ cat auto_screen.ini 
[group:auto_screen]
programs=auto_screen
priority=999

[program:auto_screen]
process_name=%(program_name)s_%(process_num)02d
command=/usr/local/python3/bin/gunicorn -c gunicorn_config.py app:app
directory=/usr/local/nginx/html/auto-screen

autostart=true

autorestart=unexpected
exitcodes=0

stopasgroup=true
killasgroup=true

user=root
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/supervisor/python.auto_screen.log
stderr_logfile=/var/log/supervisor/python.auto_screen.log
stdout_logfile_maxbytes=200MB
stdout_logfile_backups=20

Gunicorn + Supervisor 标准配置模板

[program:auto_screen]
directory=/usr/local/nginx/html/auto-screen
command=/usr/local/python3/bin/gunicorn -c gunicorn_config.py app:app
process_name=%(program_name)s_%(process_num)02d
numprocs=1

autostart=true
autorestart=unexpected
stopasgroup=true
killasgroup=true

user=root
redirect_stderr=true
stdout_logfile=/var/log/supervisor/python.auto_screen.log
stderr_logfile=/var/log/supervisor/python.auto_screen.log

服务重启

supervisorctl stop auto_screen:auto_screen_00
supervisorctl start auto_screen:auto_screen_00