Karp 的技术博客

场景描述

Supervisor 脚本定时重启脚本任务, 任务中存在多个子进程, 重启服务基本都是能一波带走所有子进程.
但这次发现有个服务重启失败, 查看原因是存在子进程未kill掉, 子进程占用服务端口, 重启服务端口被占用最后服务BACKOFF了, 原因就是子进程没杀掉, 莫得办法. 下面配置也都是有的,因为之前踩过坑.没想到还是有问题.

;使用supervisorctl停止时,子进程也会一起停止
stopasgroup=true
;向进程组发送kill信号,包括子进程
killasgroup=true     

为了监控这种服务异常拉起失败的场景, 百度一下 Supervisor 是有一个 事件监听的 Event Listener.

Event TypesSupervisor 官方定义,覆盖了进程运行生命周期的各种状态。

下面翻译一些常用的类型 :

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()

python Supervisor

版权属于:karp
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
更新于: 2023年09月03日 04:33
8

目录

来自 《Supervisor Event Listener 任务监控与告警》