django命令卡死问题解决

问题描述:

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



'

猜你喜欢

转载自blog.csdn.net/pengwupeng2008/article/details/72637760