2013-10-08 7 views
1

Я пытаюсь создать программу, которая:Прослушивание Twisted TCP соединение с питона-демон Плохим файловый дескриптор

  • вилка при запуске с помощью multiprocessing
  • раздвоенную процесс использует python-daemon раскошелиться снова в фоновом режиме
  • открытия витого прослушивания TCP порта в результате фонового процессе

Причину мне нужно раскошелиться процессом перед запуском python-daemon - это потому, что я хочу, чтобы процесс ожидания оставался в живых (по умолчанию python-daemon убивает процесс отца).

Пока мой код:

from twisted.web import xmlrpc, server 
from twisted.internet import reactor 
from daemon import daemon 
import multiprocessing 
import os 
import logging 

class RemotePart(object): 

    def setup(self): 
     self.commands = CommandPart() 
     reactor.listenTCP(9091, server.Site(self.commands)) 

class CommandPart(xmlrpc.XMLRPC, object): 

    def __init__(self): 
     super(CommandPart, self).__init__() 

    def xmlrpc_stop(self): 
     return True 


class ServerPart(object): 

    def __init__(self): 
     self.logger = logging.getLogger("server") 
     self.logger.info("ServerPart.__init__()") 

    def start_second_daemon(self): 
     self.logger.info("start_second_daemon()")   
     daemon_context = daemon.DaemonContext(detach_process=True) 
     daemon_context.stdout = open(
      name="log.txt", 
      mode='w+', 
      buffering=0 
     ) 
     daemon_context.stderr = open(
      name="log.txt", 
      mode='w+', 
      buffering=0 
     ) 
     daemon_context.working_directory = os.getcwd() 

     daemon_context.open() 
     self.inside_daemon() 

    def inside_daemon(self): 
     self.logger.setLevel(0) 
     self.logger.info("inside daemon") 
     self.remote = RemotePart() 
     self.remote.setup() 
     reactor.run() 

class ClientPart(object): 

    def __init__(self): 
     logging.basicConfig(level=0) 
     self.logger = logging.getLogger("client") 
     self.logger.info("ClientPart.__init__()") 

    def start_daemon(self): 
     self.logger.info("start_daemon()") 
     start_second_daemon() 

    def launch_daemon(self): 
     self.logger.info("launch_daemon()") 
     server = ServerPart() 
     p = multiprocessing.Process(target=server.start_second_daemon()) 
     p.start() 
     p.join() 

if __name__ == '__main__': 
    client = ClientPart() 
    client.launch_daemon() 

Запуск процесса, кажется, работает:

INFO:client:ClientPart.__init__() 
INFO:client:launch_daemon() 
INFO:server:ServerPart.__init__() 
INFO:server:start_second_daemon() 

Но, глядя в лог-файл фонового процесса, скрученный не может открыть порт TCP:

INFO:server:inside daemon 
Traceback (most recent call last): 
    File "forking_test.py", line 74, in <module> 
    client.launch_daemon() 
    File "forking_test.py", line 68, in launch_daemon 
    p = multiprocessing.Process(target=server.start_second_daemon()) 
    File "forking_test.py", line 45, in start_second_daemon 
    self.inside_daemon() 
    File "forking_test.py", line 51, in inside_daemon 
    self.remote.setup() 
    File "forking_test.py", line 12, in setup 
    reactor.listenTCP(9091, server.Site(self.commands)) 
    File "/usr/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 482, in listenTCP 
    p.startListening() 
    File "/usr/lib/python2.7/site-packages/twisted/internet/tcp.py", line 1004, in startListening 
    self.startReading() 
    File "/usr/lib/python2.7/site-packages/twisted/internet/abstract.py", line 429, in startReading 
    self.reactor.addReader(self) 
    File "/usr/lib/python2.7/site-packages/twisted/internet/epollreactor.py", line 247, in addReader 
    EPOLLIN, EPOLLOUT) 
    File "/usr/lib/python2.7/site-packages/twisted/internet/epollreactor.py", line 233, in _add 
    self._poller.register(fd, flags) 
IOError: [Errno 9] Bad file descriptor 

Любая идея? Кажется, python-daemon закрывает все файловые дескрипторы фонового процесса, когда он запускается, может ли это исходить из этого поведения?

ответ

1

Существует множество причин, из-за которых работает вилка, а затем запускается некоторый алгоритмический код библиотеки, который не работает. Было бы сложно перечислить их всех здесь, но, как правило, это не здорово делать. Мое предположение о том, что конкретно происходит здесь, заключается в том, что что-то в пределах multiprocessing закрывает «waker» файловый дескриптор, который позволяет Twisted общаться с пулом потоков, но я не могу быть абсолютно уверен.

Если бы вы были повторно написать это:

  1. Использование spawnProcess вместо multiprocessing
  2. Использование twistd вместо python-daemonize

взаимодействия будет гораздо менее удивительно, потому что вы» d использовать код нереста и демонанизации процесса, специально предназначенный для работы с Twisted, вместо двух вещей с большим количеством случайных взаимодействий платформы (вызов fork, сериализация тонких gs по трубам с рассолом, вызов setsid и setuid и изменение управляющего терминала и лидера сеанса в разное время).

(И на самом деле я бы рекомендовал интеграцию с инструментами управления демоном вашей платформы, как upstart или launchd или systemd или кросс-платформенной, подобный runit, а не в зависимости от кода daemonization, в том числе в twistd, но я бы нужно знать больше о вашем приложении, чтобы знать, что рекомендовать.)

+0

Мне не нужна интеграция с launchd/systemd/upstart, я просто хочу, чтобы мое приложение было в фоновом режиме и дистанционно управляемым с помощью XML-RPC. Основываясь на нашем ответе, я собираюсь использовать UnixApplicationRunner для запуска моего приложения. Благодарю. – Kartoch