странная ситуация с правами доступа к файлам на Windows - PullRequest
0 голосов
/ 08 февраля 2012

так что мой проект структурирован следующим образом. У меня есть сервер cherrypy и внутренний сервер, который выполняет некоторые операции. Теперь у меня есть «основной» файл app.py, который обрабатывает запуск этих процессов. Они начинаются как:

    SERVER = subprocess.Popen([PYTHON_EXE_PATH, '-m', WEB_SERVER, 
                                    'tvb'], shell=False)

    BACKEND = subprocess.Popen([PYTHON_EXE_PATH, '-m', 'bin.rpserver'
                            , cfg.RPC_SERVER_IP, cfg.RPC_SERVER_PORT],
                            shell=False)

Теперь после запуска эти пиды сохраняются в файле, поэтому пользователь может запустить скрипт остановки и закрыть их. Этот скрипт также отлично работает и в основном:

def execute_stop():  
    if os.path.exists(PID_FILE):  
        pid_file = open(PID_FILE, 'r')
        has_processes = False
        for pid in pid_file.read().split('\n'):
            if len(pid.strip()):
                try:
                    if sys.platform == 'win32':
                        import ctypes
                        handle = ctypes.windll.kernel32.OpenProcess(1, False, 
                                                                int(pid))
                        ctypes.windll.kernel32.TerminateProcess(handle, -1)
                        ctypes.windll.kernel32.CloseHandle(handle)
                    else:
                        os.kill(int(pid), signal.SIGKILL) 
                except Exception, _:
                    has_processes = True
        if has_processes:
            sys.stdout.write("Some old PIDs were still registered; \
                          They could not be stopped.")                    
        pid_file.close()
    pid_file = open(PID_FILE, "w")
    pid_file.close()

Теперь этот файл pid вместе с моим файлом логгера и другими файлами данных хранится в cfg.STORAGE, и у меня также есть простая чистая процедура для этого:

def execute_clean():
    """Remove TVB folder, TVB File DB, and log file."""
    try:
        if os.path.isdir(cfg.TVB_STORAGE):
            shutil.rmtree(cfg.TVB_STORAGE)
    except Exception, excep1:
        sys.stdout.write("Could not remove storage folder!")
        sys.stdout.write(str(excep1)) 

Это также хорошо работает при вызове отдельно. Но здесь есть проблема: в моей программе есть опция, которая позволяет пользователю изменять некоторые настройки, и в этом случае вся программа должна быть перезапущена, и шаги должны быть переделаны. Для этого я:

    cherrypy.engine.exit()
    self.logger.debug("Waiting for Cherrypy to terminate.")
    sleep(2)
    python_path = cfg().get_python_path()
    proc_params = [python_path, '-m', 'bin.app', 'start', 'web', 'backend']
    subprocess.Popen(proc_params, shell=False) 

Так что это снова делает в основном следующие шаги:

    execute_stop()
    execute_clean()
    start both processes again

Странная вещь, которую я не могу понять, это то, что execute_stop() работает нормально, и, как вы можете видеть в конце этого, PID_FILE открывается в режиме записи и закрывается, чтобы очистить содержимое, но затем сразу после execute_clean() произойдет сбой, сказав, что PID_FILE заблокирован другим процессом.

Теперь я проверил и перепроверил, и каждый раз, когда этот файл открывается, он закрывается после, и я действительно не знаю, что искать. Это происходит только в Windows, и я попытался использовать средство обхода зависимостей, чтобы увидеть, что происходит, и кажется, что когда запущены процессы python, средство отслеживания зависимостей видит 4 ссылки и 2 обработчика на эти файлы, что странно, учитывая, что они закрыты каждый раз. Мне также кажется странным, что я могу открывать файлы в режиме 'w', но не могу их удалить.

Буду очень признателен за любые идеи, которые могут быть неправильными / что искать.

EDIT

Я пытался использовать как sugested os.waitpid, но при выполнении:

    os.waitpid(int(pid), 0) 

Я получил [Errno 10] No child processes. Я также прочитал и увидел, что кто-то говорит, что в windows вы должны передать дескриптор вместо pid os.waitpid, поэтому я также попробовал это сделать с ручкой, но я получил тот же результат. Так что в этот момент процесс больше не должен существовать, верно?

1 Ответ

0 голосов
/ 08 февраля 2012

Это просто выстрел в темноте ...
Я догадываюсь, что один или оба процесса SERVER, BACKEND не завершаются должным образом и имеют открытый PID_FILE.Убедитесь, что каждый из них открывает PID_FILE с помощью mode='a' и быстро его закрывает.Если я не в курсе того, как SERVER / BACKEND обрабатывает PID_FILE, вы также можете попробовать os.waitpid(pid) после вашего звонка на TerminateProcess.Это должно блокировать, пока процесс действительно не завершится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...