场景描述
Supervisor
脚本定时重启脚本任务, 任务中存在多个子进程, 重启服务基本都是能一波带走所有子进程.
但这次发现有个服务重启失败, 查看原因是存在子进程未kill掉, 子进程占用服务端口, 重启服务端口被占用最后服务BACKOFF
了, 原因就是子进程没杀掉, 莫得办法. 下面配置也都是有的,因为之前踩过坑.没想到还是有问题.
;使用supervisorctl停止时,子进程也会一起停止
stopasgroup=true
;向进程组发送kill信号,包括子进程
killasgroup=true
为了监控这种服务异常拉起失败的场景, 百度一下 Supervisor
是有一个 事件监听的 Event Listener
.
Event Types
由 Supervisor
官方定义,覆盖了进程运行生命周期的各种状态。
下面翻译一些常用的类型 :
Event | 解释 |
---|---|
PROCESS_STATE | 进程状态发生改变 |
PROCESS_STATE_STARTING | 进程状态从其他状态转换为正在启动(Supervisord 的配置项中有startsecs 配置项,是指程序启动时需要程序至少稳定运行x秒才认为程序运行正常,在这x秒中程序状态为正在启动) |
PROCESS_STATE_RUNNING | 进程从正在启动状态转换为正在运行状态 |
PROCESS_STATE_BACKOFF | 进程从正在启动状态转换为启动失败状态,Supervisor 正在重启该进程 |
PROCESS_STATE_STOPPING | 进程从正在运行状态或正在启动状态转换为正在停止状态 |
PROCESS_STATE_EXITED | 进程从正在运行状态转换为退出状态,expected 退出码,如果是 0 表示进程异常退出,1 表示进程正常退出。 |
PROCESS_STATE_STOPPED | 进程从正在停止状态转换为已停止状态 |
PROCESS_STATE_FATAL | 进程从启动失败状态(BACKOFF )转换为失败状态(FATAL ). 意味着 startretries 尝试次数已达上限,Supervisor 已放弃重启该进程。 |
PROCESS_LOG | 进程产生日志输出,被管理的进程需配置,stdout_events_enabled=true or stderr_events_enabled=true 这个事件通知才会生效。 |
PROCESS_LOG_STDOUT | 进程产生标准输出,被管理的进程需配置,stdout_events_enabled=true |
PROCESS_LOG_STDERR | 进程产生错误输出,被管理的进程需配置,stderr_events_enabled=true |
Supervisor
配置如下
[eventlistener:phplistener]
command=/usr/bin/python3 /opt/webserver/listener.py
events=PROCESS_STATE_EXITED,PROCESS_STATE_FATAL ; 监控事件
stdout_logfile=/opt/weblogs/phplistener_stdout.log
stderr_logfile=/opt/weblogs/phplistener_stderr.log
需要特别注意的是 这个eventlistener
配置修改后不能通过 supervisorctl update
更新配置. 要吗remove
后在update/add
,要不就reread
.
/opt/webserver/listener.py
文件
# encoding: utf-8
import sys
import requests
import time # 步骤1:导入时间模块
def write_stdout(s):
# Only eventlistener protocol messages may be sent to stdout
sys.stdout.write(s)
sys.stdout.flush()
def write_stderr(s):
sys.stderr.write(s)
sys.stderr.flush()
def send_message(message):
url = 'https://xxxx/send_message'
params = {'content': message}
response = requests.post(url, params=params)
return response
def main():
while True:
write_stdout('READY\n')
line = sys.stdin.readline()
write_stderr(line)
headers = dict([x.split(':') for x in line.split() ])
eventname = headers['eventname']
data = sys.stdin.read(int(headers['len']))
write_stderr(data+'\n')
datas = dict([y.split(':') for y in data.split() ])
processname = datas['processname']
from_state = datas['from_state']
# Customize this part to perform specific actions based on the event data
event_message = "【 Supervisor Listener 服务异常 】 \n\n 服务名称 : "+processname+"\n Event : "+eventname+"\n State : "+from_state+"\n\n"+line+"\n"+data+"\n"
# 仅报警失败的服务
if eventname == 'PROCESS_STATE_FATAL':
response = send_message(event_message)
if response.status_code == 200:
write_stderr("Message sent successfully.\n")
else:
write_stderr("Failed to send message.\n")
write_stdout('RESULT 2\nOK')
if __name__ == '__main__':
main()