Using the subprocess module, running to. poll() always means that None causes the program to run abnormally

Keywords: Programming Python Windows

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.

Posted by Sekka on Fri, 13 Dec 2019 10:01:06 -0800