Общение с работающим демоном python - PullRequest
52 голосов
/ 18 марта 2009

Я написал небольшое приложение на Python, которое работает как демон. Он использует многопоточность и очереди.

Я ищу общие подходы к изменению этого приложения, чтобы я мог общаться с ним во время его работы. В основном я хотел бы иметь возможность следить за его здоровьем.

В двух словах, я хотел бы иметь возможность сделать что-то вроде этого:

python application.py start  # launches the daemon

Позже я хотел бы иметь возможность прийти и сделать что-то вроде:

python application.py check_queue_size  # return info from the daemonized process

Для ясности, у меня нет проблем с реализацией вдохновленного Django синтаксиса. Я не имею ни малейшего представления о том, что делать, это посылать сигналы демонизированному процессу (запуск) или как писать демон для обработки и реагирования на такие сигналы.

Как я уже говорил выше, я ищу общие подходы. Единственное, что я сейчас вижу, это то, что демон постоянно записывает в файл все, что может понадобиться, но я надеюсь, что есть менее грязный способ сделать это.

ОБНОВЛЕНИЕ: Ого, много хороших ответов. Спасибо. Я думаю, что я посмотрю как на Pyro, так и на web.py/Werkzeug, так как Twisted - это немного больше, чем я хотел бы откусить в данный момент. Я полагаю, что следующая концептуальная задача заключается в том, чтобы поговорить с моими рабочими потоками, не вешая их.

Еще раз спасибо.

Ответы [ 7 ]

35 голосов
/ 18 марта 2009

Еще один подход: используйте Pyro (объекты удаленного взаимодействия Python).

Pyro в основном позволяет публиковать экземпляры объектов Python как сервисы, которые можно вызывать удаленно. Я использовал Pyro именно для той цели, которую вы описываете, и нашел, что она работает очень хорошо.

По умолчанию демон Pyro-сервера принимает подключения отовсюду. Чтобы ограничить это, либо используйте средство проверки соединения (см. Документацию), либо предоставьте host='127.0.0.1' конструктору Daemon, чтобы прослушивать только локальные соединения.

Пример кода взят из документации к Pyro:

Сервер

import Pyro.core

class JokeGen(Pyro.core.ObjBase):
        def __init__(self):
                Pyro.core.ObjBase.__init__(self)
        def joke(self, name):
                return "Sorry "+name+", I don't know any jokes."

Pyro.core.initServer()
daemon=Pyro.core.Daemon()
uri=daemon.connect(JokeGen(),"jokegen")

print "The daemon runs on port:",daemon.port
print "The object's uri is:",uri

daemon.requestLoop()

Клиент

import Pyro.core

# you have to change the URI below to match your own host/port.
jokes = Pyro.core.getProxyForURI("PYROLOC://localhost:7766/jokegen")

print jokes.joke("Irmen")

Еще один похожий проект - RPyC . Я не пробовал RPyC.

18 голосов
/ 18 марта 2009

Как насчет того, чтобы он запускал http-сервер?

Кажется сумасшедшим, но работает простой веб-сервер для администрирования вашего серверу требуется всего несколько строк, используя web.py

Вы также можете рассмотреть возможность создания Unix-канала.

16 голосов
/ 18 марта 2009

Используйте werkzeug и включите в свой демон WSGI-сервер на основе HTTP.

У вашего демона есть коллекция небольших приложений WSGI для ответа на информацию о состоянии.

Ваш клиент просто использует urllib2 для отправки запросов POST или GET на localhost: somePort. Ваш клиент и сервер должны согласовать номер порта (и URL).

Это очень просто реализовать и очень масштабируемо. Добавление новых команд - тривиальное упражнение.

Обратите внимание, что ваш демон не должен отвечать в HTML (хотя это часто просто). Наши демоны отвечают на WSGI-запросы объектами состояния в кодировке JSON.

9 голосов
/ 18 марта 2009

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

Из-за проблем с многопоточностью в Python у вас будут проблемы с ответом на информационные запросы при одновременном продолжении делать то, что демон должен делать в любом случае. Асинхронные методы или разветвление других процессов - ваш единственный реальный выбор.

7 голосов
/ 18 марта 2009
# your server

from twisted.web import xmlrpc, server
from twisted.internet import reactor

class MyServer(xmlrpc.XMLRPC):

    def xmlrpc_monitor(self, params):        
        return server_related_info

if __name__ == '__main__':
    r = MyServer()
    reactor.listenTCP(8080, Server.Site(r))
    reactor.run()

клиент может быть написан с использованием xmlrpclib, посмотрите пример кода здесь .

5 голосов
/ 18 марта 2009

Предполагая, что вы находитесь под * nix, вы можете отправлять сигналы запущенной программе с kill из оболочки (и аналогов во многих других средах). Чтобы обработать их из Python, проверьте модуль signal .

4 голосов
/ 18 марта 2009

Вы можете связать его с Pyro (http://pythonhosted.org/Pyro4/) Удаленный объект Python. Он позволяет удаленно обращаться к объектам Python. Он прост в реализации, имеет низкие накладные расходы и не так агрессивен, как Twisted.

...