так что мой проект структурирован следующим образом. У меня есть сервер 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, поэтому я также попробовал это сделать с ручкой, но я получил тот же результат. Так что в этот момент процесс больше не должен существовать, верно?