问题描述:
1、可能由于网络原因,导致django命令在多次定时器运行后,会出现假死,启动的那一刻就卡死,不执行任何代码
2、可能由于连接数据库异常导致假死
3、其他未知原因,如果有遇到的,或者知道原因的,希望得到指教
解决办法:
办法1、
1、在命令启动的时候把命令对应的进程ID号,以及超时时间,写到一个临时文件中
2、写一个定时服务不停的扫描文件中的进程ID,超时时间,如果发现超时,则杀死
3、这个办法,后面发现对于我的业务是不可行的,原因是命令启动,假死,压根就
没有执行任何代码,没有把PID和超时时间写到临时文件中
4、对于其他在不是在启动的时候假死的情况,是可以用的
# -*- coding: utf-8 -*- import os import time import sys import datetime import traceback import tempfile import logging COMMAND_PID_ROOT_PATH = os.path.join(tempfile.gettempdir(),"command_pids") def get_log(file_name): LOG_DIR = "/var/log/mylog/" #日志目录 if os.name != "posix": LOG_DIR = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] if not os.path.exists(LOG_DIR): os.mkdir(LOG_DIR) path = os.path.join(LOG_DIR,file_name) logger = logging.getLogger() hdlr = logging.FileHandler(path) formatter = logging.Formatter('%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.NOTSET) return logger logger = get_log("monitor_cmds.log") def monitor(): logger.info("****staring monitor commands*****") expire_minutes = 90 #进程运行过期时间 if not os.path.exists(COMMAND_PID_ROOT_PATH): os.mkdir(COMMAND_PID_ROOT_PATH) datas = os.listdir(COMMAND_PID_ROOT_PATH) pid_infos = [] for f in datas: file_path = os.path.join(COMMAND_PID_ROOT_PATH,f) if os.path.isfile(file_path): fid = file(file_path,"r") fdata = fid.read() #文件中内容格式为{pid}|{start_time} fid.close() d = fdata.split("|") d.append(file_path) pid_infos.append(d) dt_now = datetime.datetime.now() for pid,start_time,file_path in pid_infos: start_time_d = datetime.datetime.strptime(start_time,"%Y-%m-%d %H:%M:%S") end_time = start_time_d + datetime.timedelta(minutes = expire_minutes) if end_time <= dt_now: #超时了 kill_cmd = "kill -9 %s"%pid if os.system(kill_cmd) == 0: logger.info( "success kill pid info pid='%s',start_time='%s',file_path='%s'"%( pid,start_time,file_path, ) ) else: logger.info( "fail kill pid info pid='%s',start_time='%s',file_path='%s'"%( pid,start_time,file_path, ) ) logger.info("****ending monitor commands*****") if __name__ == "__main__": monitor()
办法2、
1、通过主进程,动态生成一个子进程的方式运行django命令Popen
2、父进程一直监控子进程状态,如果超时,子进程还未结束,则杀死
例子如下:
*/5 * * * * flock -xn /tmp/test.lock -c 'python /var/www/test_prj/monitor_cmd.py "python /var/www/test_prj/manage.py test_cmd"'
解释:
1、flock是为了防止定时器还未结束的时候,又重新启动执行,导致一个命令多个进程执行
2、django 命令 python /var/www/test_prj/manage.py test_cmd 通过monitor_cmd.py 主进程文件监控
3、monitor_cmd.py 源代码如下,希望对有需要的人有所帮助
# -*- coding: utf-8 -*- import os import time import sys import datetime import traceback import tempfile import subprocess import shlex import logging def get_log(file_name): LOG_DIR = "/var/log/mylog/" #日志目录 if os.name != "posix": LOG_DIR = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] if not os.path.exists(LOG_DIR): os.mkdir(LOG_DIR) path = os.path.join(LOG_DIR,file_name) logger = logging.getLogger() hdlr = logging.FileHandler(path) formatter = logging.Formatter('%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.NOTSET) return logger logger = get_log("monitor_cmd.log") TIMEOUT_COUNT = 60 #超时时间,单位秒 if __name__ == "__main__": args = shlex.split(sys.argv[1]) child = subprocess.Popen(args) start_time = time.time() while True: is_end = child.poll() end_time = time.time() if is_end == 0: #子进程正常结束 logger.info( "args='{args}' normal end pid='{pid}'".format( args=args, pid=child.pid, ) ) break elif (end_time - start_time)>TIMEOUT_COUNT: #超时 logger.info( "args='{args}' timeout kill child pid='{pid}'".format( args=args, pid=child.pid, ) ) child.kill() break else: time.sleep(3) logger.info("args='{args}' ending".format(args = args))
'