скрипт python, запускающий 2 демона

Я планирую предоставить сценарий, как указано в заголовке. У меня есть идея, о которой я расскажу ниже. Если вы считаете, что что-то звучит плохо / глупо, буду благодарен за любые конструктивные комментарии, улучшения и т. Д.

Есть 2 службы, которые я хочу запустить как демоны. Один обязателен (служба кеширования), другой - необязательный (HTTP-доступ к службе кеширования). Я использую модуль argparse, чтобы получить --port, чтобы получить порт службы кеширования, и необязательный --http-port, чтобы получить доступ по протоколу http. Это у меня уже есть, и это работает. Теперь я хочу запустить демонов. Эти сервисы основаны на кручении, поэтому они должны запускать петлю реактора. Пока я хотел бы иметь два разных процесса: один для службы, а второй для доступа по http (хотя я знаю, что это может быть выполнено в одном асинхронном процессе).

Поскольку запуск скрученной службы выполняется через цикл реактора (который представляет собой код Python, а не сценарий оболочки, поскольку я еще не использую twistd), я думаю, что использование os.fork лучше, чем подпроцесс (для которого потребуется команда командной строки для запуска процесс). Я могу использовать os.fork для запуска демонов и касаться файлов service.pid и http.pid, но я не знаю, как получить доступ к дочернему pid, поскольку os.fork возвращает 0 для дочернего элемента.

Так что chld PID - это то, что мне не хватает. Более того, если что-то кажется нелогичным или слишком сложным, прокомментируйте это.

Мой текущий код выглядит так:

#!/usr/bin/python
import argparse
import os

from twisted.internet import reactor

parser = argparse.ArgumentParser(description='Run PyCached server.')
parser.add_argument('port', metavar='port', type=int,
    help='PyCached service port')
parser.add_argument('--http-port', metavar='http-port', type=int, default=None,
    help='PyCached http access port')
args = parser.parse_args()

def dumpPid(name):
    f = open(name + '.pid', 'w')
    f.write(str(os.getpid()))
    f.flush()
    f.close()

def erasePid(name):
    os.remove(name + '.pid')

def run(name, port, factory):
    dumpPid(name)
    print "Starting PyCached %s on port %d" % (name, port)
    reactor.listenTCP(port, factory)
    reactor.run()
    erasePid(name)
    print "Successfully stopped PyCached %s" % (name,)

# start service (required)
fork_pid = os.fork()
if fork_pid == 0:
    from server.service import PyCachedFactory
    run('service', args.port, PyCachedFactory())
else:
    # start http access (optional)
    if args.http_port:
        fork_pid = os.fork()
        if fork_pid == 0:
            from server.http import PyCachedSite
            addr = ('localhost', args.port)
            run('http', args.http_port, PyCachedSite(addr))
        else:
            pass

Я запускаю его с помощью:

./run.py 8001 # with main service only

or:

./run.py 8001 --http-port 8002 # with additional http

Завершение работы системы выполняется с помощью сценария одной оболочки:

#!/bin/bash

function close {
    f="$1.pid"
    if [ -f "$f" ]
    then
        kill -s SIGTERM `cat "$f"`
    fi    
}

close http
close service

person ducin    schedule 03.11.2013    source источник


Ответы (1)


Поскольку запуск скрученной службы выполняется через цикл реактора (который представляет собой код Python, а не сценарий оболочки, поскольку я еще не использую twistd), я думаю, что использование os.fork лучше, чем подпроцесс (для которого потребуется команда командной строки для начать процесс).

Вам следует использовать twistd. Если нет, то вам следует написать скрипт Python для запуска демона. Затем вы должны использовать модуль subprocess (или reactor.spawnProcess) для запуска дочернего процесса.

Использование os.fork без немедленного перехода к одной из os.exec* функций нарушено. Большое количество состояний разделяется между родительским и дочерним объектами, созданными os.fork. Вы не можете быть уверены, что это совместное использование ничего не сломает (и я могу сказать вам, что это сломает некоторые вещи в Twisted).

Вот несколько ссылок на обсуждения проблем fork-without-exec, которые могут помочь вам получить более полное представление о том, в какой проблемной области это находится.

person Jean-Paul Calderone    schedule 03.11.2013
comment
Мне нравится ваш ответ, я могу кое-чему научиться. Не могли бы вы указать мне на веб-ресурс / книжный ресурс, где я могу прочитать о _1 _ / _ 2_ / большом количестве состояний? Я новичок в вещах, подобных ОС, и не совсем понимаю, что вы здесь имеете в виду. PS, похоже, все работает с приведенным выше кодом. Значит, дело в масштабе, пока что-то не сломается? - person ducin; 03.11.2013
comment
добавил несколько ссылок, которые могут вас заинтересовать. поломка, скорее всего, не зависит от масштаба, а зависит от того, какой код библиотеки вы пытаетесь использовать - все будет работать нормально, пока вы не начнете вызывать некоторые функции библиотеки, которые плохо взаимодействуют с этим использованием (что может произойти, когда ваше приложение остается прежним, но изменяется библиотека). на самом деле я не думаю, что код, который вы разместили в своем вопросе, работает надежно: в Linux он будет использовать epollreactor, а epollreactor действительно сбивает с толку, ломает вещи при использовании с fork без exec. - person Jean-Paul Calderone; 04.11.2013