Problem: use subprocess in the server to monitor the running state of python and record the logs. The code can run normally on your own computer, but run to subprocess.Popen().poll() in the server and output None all the time, which causes the program to run abnormally.
Environment: windows server 2003+python2.7
Cause analysis: I checked some data on the Internet and suggested not to use poll. Although it seems different from my problem, and I didn't find a more suitable solution, I gave up the use of poll. subprocess.Popen().poll() was replaced by subprocess.Popen().stdout, and then I judged whether subprocess.Popen().stdout was None. If it was None, I would sprint to start the subprocess .
The code is as follows:
# -*- coding: UTF-8 -*- #!DATE: 2018/10/9 #!@Author: yingying import os import time import subprocess import logging from logging.handlers import RotatingFileHandler todaylog = time.strftime('%Y-%m-%d', time.localtime(time.time())).decode('utf-8') ## log settings: SHOULD BE CONFIGURED BY config LOG_PATH_FILE = "C:\work\%s_my_service_mgr.log" % todaylog LOG_MODE = 'a' LOG_MAX_SIZE = 10 * 1024 * 1024 # 10M per file LOG_MAX_FILES = 10 # 10 Files: my_service_mgr.log.1, printmy_service_mgrlog.2, ... LOG_LEVEL = logging.DEBUG LOG_FORMAT = "%(asctime)s %(levelname)-10s[%(filename)s:%(lineno)d(%(funcName)s)] %(message)s" handler = RotatingFileHandler(LOG_PATH_FILE, LOG_MODE, LOG_MAX_SIZE, LOG_MAX_FILES) formatter = logging.Formatter(LOG_FORMAT) handler.setFormatter(formatter) Logger = logging.getLogger() Logger.setLevel(LOG_LEVEL) Logger.addHandler(handler) pid = os.getpid() def print_error(s): print '\033[31m[%d: ERROR] %s\033[31;m' % (pid, s) def print_info(s): print '\033[32m[%d: INFO] %s\033[32;m' % (pid, s) def print_warning(s): print '\033[33m[%d: WARNING] %s\033[33;m' % (pid, s) def start_child_proc(command, merged): try: if command is None: raise OSError, "Invalid command" Logger.info("def start_child_proc(command, merged):") child = None if merged is True: # merge stdout and stderr # child = subprocess.Popen(command) child = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE) else: # DO NOT merge stdout and stderr # child = subprocess.Popen(command) child = subprocess.Popen(command,stderr=subprocess.PIPE,stdout=subprocess.PIPE) Logger.info("if merged is True:") return child except subprocess.CalledProcessError: pass # handle errors in the called executable except OSError: raise OSError, "Failed to run command!" def run_forever(command): print_info("start child process with command: " + ' '.join(command)) Logger.info("start child process with command: " + ' '.join(command)) merged = False child = start_child_proc(command, merged) Logger.info(child) Logger.info("child = start_child_proc(command, merged)") failover = 0 while True: Logger.info("while True") Logger.info(child.poll()) #The previous child. Poll()! = none while child.stdout == None: Logger.info("while child.stdout == None") failover = failover + 1 print_warning("child process shutdown with return code: " + str(child.returncode)) Logger.critical("child process shutdown with return code: " + str(child.returncode)) print_warning("restart child process again, times=%d" % failover) Logger.info("restart child process again, times=%d" % failover) child = start_child_proc(command, merged) #child.wait() Logger.info("while end") # read child process stdout and log it out, err = child.communicate() Logger.info("out, err = child.communicate()") returncode = child.returncode if returncode != 0: Logger.info("if returncode != 0:") for errorline in err.slitlines(): Logger.info(errorline) else: Logger.info("execute child process failed") Logger.exception("!!!should never run to this!!!") if __name__ == "__main__": run_forever(['python', 'timer.py'])
Note: the return value of. poll() returns 0 and ends normally. The return value of 1 is sleep status. 2 subprocesses do not exist. None indicates running
. stdout indicates the output of the subprocess, so if. Stdout is none, it indicates that the subprocess has finished running and the subprogram needs to be reopened.