|
|
#!/usr/bin/python3
|
|
|
# coding: utf-8
|
|
|
|
|
|
"""
|
|
|
author: 猪猪侠 https://github.com/ring04h
|
|
|
|
|
|
"""
|
|
|
|
|
|
import logging
|
|
|
import subprocess
|
|
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
|
|
|
|
|
#
|
|
|
# (crontab -l;echo '0 2 * * * /usr/local/bin/python3 /data/script/zombie_clean.py') | crontab -
|
|
|
#
|
|
|
|
|
|
import logging
|
|
|
import subprocess
|
|
|
|
|
|
# 判断是否超时的函数
|
|
|
def is_timeout(etime):
|
|
|
"""
|
|
|
判断进程的运行时间是否超时。
|
|
|
|
|
|
参数:
|
|
|
etime (str):进程的运行时间字符串,格式可能为 "天数-小时数" 或直接是小时数。
|
|
|
|
|
|
返回:
|
|
|
bool:如果天数大于等于 1 或者小时数超过一定阈值(这里没有具体指定阈值),返回 True,表示超时;否则返回 False。
|
|
|
"""
|
|
|
if '-' in etime:
|
|
|
day, hour = etime.split('-')
|
|
|
return True if int(day) >= 1 else False
|
|
|
else:
|
|
|
return False
|
|
|
|
|
|
# 执行命令的函数
|
|
|
def cmdprocess(cmdline):
|
|
|
"""
|
|
|
执行给定的命令行。
|
|
|
|
|
|
参数:
|
|
|
cmdline (str):要执行的命令行字符串。
|
|
|
|
|
|
返回:
|
|
|
tuple:包含命令的标准输出、标准错误输出和返回码。
|
|
|
"""
|
|
|
# 使用 subprocess.Popen 执行命令,捕获标准输出和标准错误输出
|
|
|
pipe = subprocess.Popen(cmdline, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
# 等待命令执行完成,获取标准输出和标准错误输出
|
|
|
output, stderr = pipe.communicate()
|
|
|
# 获取命令的返回码
|
|
|
return_code = pipe.returncode
|
|
|
# 将标准错误输出解码为字符串
|
|
|
stderr = stderr.decode(errors='replace')
|
|
|
# 将标准输出解码为字符串
|
|
|
output = output.decode(errors='replace')
|
|
|
return output, stderr, return_code
|
|
|
|
|
|
def main():
|
|
|
# 构建查找 crawlergo 进程 ID 的命令行
|
|
|
cmdline = "ps -ef | grep crawlergo | grep -v grep | awk '{print $2}'"
|
|
|
# 执行命令,获取输出、错误输出和返回码
|
|
|
output, stderr, return_code = cmdprocess(cmdline)
|
|
|
|
|
|
# 如果返回码不为 0,表示命令执行失败,直接返回
|
|
|
if return_code!= 0:
|
|
|
return
|
|
|
|
|
|
# 将输出的进程 ID 按行分割成列表
|
|
|
zombie_pids = output.splitlines()
|
|
|
|
|
|
# 遍历每个 crawlergo 的进程 ID
|
|
|
for zombie_pid in zombie_pids:
|
|
|
# 构建查找指定进程 ID 的运行时间的命令行
|
|
|
cmdline = f'''ps -eo pid,etime | grep {zombie_pid}'''
|
|
|
# 执行命令,获取输出、错误输出和返回码
|
|
|
ps_output, ps_stderr, ps_return_code = cmdprocess(cmdline)
|
|
|
|
|
|
# 如果返回码不为 0,表示命令执行失败,继续下一个进程 ID 的处理
|
|
|
if ps_return_code!= 0:
|
|
|
continue
|
|
|
|
|
|
# 遍历输出的每一行(包含进程 ID 和运行时间)
|
|
|
for line in ps_output.splitlines():
|
|
|
# 将每行按空格分割,获取进程 ID 和运行时间
|
|
|
pid, etime = line.split()
|
|
|
# 判断运行时间是否超时
|
|
|
status = is_timeout(etime)
|
|
|
# 打印调试信息,包括进程 ID、运行时间和是否超时
|
|
|
logging.debug(f"PID: {pid:<8} ETIME: {etime:<15} TIMEOUT: {status}")
|
|
|
|
|
|
# 如果没有超时,继续下一个进程 ID 的处理
|
|
|
if not status:
|
|
|
continue
|
|
|
|
|
|
# 构建杀死进程的命令行
|
|
|
kill_cmdline = f"kill -9 {pid}"
|
|
|
# 打印调试信息,表示要执行的杀死进程的命令
|
|
|
logging.debug(f"call kill : [{kill_cmdline}]")
|
|
|
|
|
|
# 执行杀死进程的命令
|
|
|
cmdprocess(kill_cmdline)
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
main()
|