問題描述:
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))
'