Взаимодействие с запущенным демоном python
Я написал небольшое приложение Python, которое работает как демон. Он использует резьбу и очереди.
Я ищу общие подходы к изменению этого приложения, чтобы я мог общаться с ним во время его работы. В основном я хотел бы иметь возможность следить за его здоровьем.
в двух словах, я хотел бы быть в состоянии сделать что-то вроде этого:
python application.py start # launches the daemon
позже, я хотел бы иметь возможность прийти и сделать что-то вроде:
python application.py check_queue_size # return info from the daemonized process
будет ясно, что у меня нет никаких проблем с реализацией синтаксиса, вдохновленного Django. То, что я не знаю, как это сделать, - это отправить сигналы в демонизированный процесс (start) или как написать демон для обработки и ответа на такие сигналы.
Как я уже сказал выше, я ищу общие подходы. Единственное, что я вижу прямо сейчас, - это то, что демон постоянно записывает все, что может понадобиться в файл, но я надеюсь, что есть менее грязный способ оно.
обновление: Вау, много отличных ответов. Большое спасибо. Я думаю, что посмотрю и на пиро, и на web.py/Werkzeug подходит, так как Twisted-это немного больше, чем я хочу откусить в этот момент. Следующая концептуальная проблема, я полагаю, заключается в том, как говорить с моими рабочими потоками, не вешая их.
еще раз спасибо.
7 ответов:
Как насчет того, чтобы он запускал http-сервер?
Это кажется сумасшедшим, но работает простой веб-сервер для администрирования вашего сервер требует всего несколько строк с помощью web.py
вы также можете рассмотреть возможность создания канала unix.
еще один подход: использовать Pyro (объекты удаленного взаимодействия Python).
Pyro в основном позволяет публиковать экземпляры объектов Python в качестве служб, которые могут быть вызваны удаленно. Я использовал Pyro для точной цели, которую вы описываете, и я обнаружил, что он работает очень хорошо.
по умолчанию демон Pyro server принимает соединения отовсюду. Чтобы ограничить это, либо используйте средство проверки соединения (см. документацию), либо поставьте
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. Я не пробовал ветеранами.
использовать werkzeug и сделать ваш демон включает в себя сервер WSGI на основе HTTP.
ваш демон имеет коллекцию небольших приложений WSGI для ответа с информацией о состоянии.
ваш клиент просто использует urllib2, чтобы сделать Post или GET запросы на localhost:некий_порт. Ваш клиент и сервер должны согласовать номер порта (и URL-адрес).
Это очень просто реализовать и очень масштабируемо. Добавление новых команд является тривиальным упражнение.
обратите внимание, что ваш демон не должен отвечать в HTML (это часто просто, хотя). Наши демоны отвечают на WSGI-запросы с помощью объектов состояния в кодировке JSON.
Я бы использовал twisted с именованной трубой или просто открыл сокет. Взгляните на эхо-сервер и клиент примеры. Вам нужно будет изменить эхо-сервер, чтобы проверить некоторую строку, переданную клиентом, а затем ответить на любую запрошенную информацию.
из-за проблем с потоками Python у вас будут проблемы с ответом на информационные запросы, одновременно продолжая делать все, что демон должен делать в любом случае. Асинхронный методы или разветвление других процессов - ваш единственный реальный вариант.
# 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, проверьте пример кода здесь.
предполагая, что вы находитесь под *nix, вы можете отправлять сигналы в запущенную программу с помощью
kill
из оболочки (и аналогов во многих других средах). Чтобы справиться с ними изнутри python проверить сигнал модуль.
вы можете связать его с Pyro (http://pythonhosted.org/Pyro4/) удаленный объект Python. Он позволяет удаленно обращаться к объектам python. Это легко реализовать, имеет низкие накладные расходы и не так инвазивно, как Twisted.