Created
March 30, 2016 02:51
-
-
Save liaoliaopro/6f76a1e5a4826c4fcc873e58fd18ea76 to your computer and use it in GitHub Desktop.
a lite supervisord for windows
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# coding:utf-8 | |
import sys | |
import os | |
import re | |
import time | |
import socket | |
import subprocess | |
import threading | |
import logging | |
import xmlrpclib | |
import SimpleXMLRPCServer | |
import ConfigParser | |
USE_PYTHONW = 'C:\\Python27\\pythonw.exe' | |
SUPERVISORD_CONF = './supervisord.conf' | |
DEFAULT_PORT = 9001 | |
CURRENT_WATCHDOGS = [] | |
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(asctime)s %(message)s') | |
class WatchDog(threading.Thread): | |
"""a windows process watch dog""" | |
TICK_SECONDS = 1 | |
START_SECONDS = 5 | |
def __init__(self, name, commandline): | |
threading.Thread.__init__(self) | |
self.setName(name) | |
self._commanline = commandline | |
self._birthtime = None | |
self._stoped = False | |
self._pipe = None | |
def run(self): | |
close_fds = False if sys.platform == 'win32' else True | |
self._pipe = subprocess.Popen(self._commanline, shell=False, close_fds=close_fds) | |
self._birthtime = time.time() | |
while True: | |
try: | |
time.sleep(self.TICK_SECONDS) | |
if self._stoped: | |
self._pipe.terminate() | |
self._pipe = None | |
return True | |
else: | |
if self._pipe.poll() is not None: | |
if time.time() - self._birthtime < self.START_SECONDS: | |
logging.error('WatchDog(%r) start failed', self.getName()) | |
self._stoped = True | |
self._pipe = None | |
return False | |
else: | |
logging.error('WatchDog(%r) aborted, try restart', self.getName()) | |
self._pipe = subprocess.Popen(self._commanline, shell=False, close_fds=close_fds) | |
self._birthtime = time.time() | |
else: | |
logging.debug('WatchDog(%r) is alive', self.getName()) | |
except Exception as e: | |
logging.exception('WatchDog.run error: %r', e) | |
def start(self): | |
threading.Thread.start(self) | |
return True | |
def stop(self): | |
self._stoped = True | |
timeout = self.START_SECONDS | |
while timeout > 0: | |
if self._pipe is None: | |
return True | |
else: | |
time.sleep(self.TICK_SECONDS) | |
timeout -= self.TICK_SECONDS | |
return False | |
def check_daemon(timeout=1): | |
try: | |
socket.create_connection(('127.0.0.1', DEFAULT_PORT), timeout=timeout).close() | |
return True | |
except socket.error: | |
return False | |
def read_service(filename): | |
assert os.path.isfile(filename) | |
config = ConfigParser.ConfigParser() | |
config.read(filename) | |
services = {} | |
for section in config.sections(): | |
if section.startswith('program:') and config.has_option(section, 'command'): | |
name = section[8:].strip() | |
command = config.get(section, 'command').strip() | |
if USE_PYTHONW and command.startswith('python'): | |
command = ' '.join([USE_PYTHONW] + command.split()[1:]) | |
services[name] = command | |
return services | |
def clear_stoped_watchdog(): | |
global CURRENT_WATCHDOGS | |
CURRENT_WATCHDOGS = [x for x in CURRENT_WATCHDOGS if not x._stoped and x._pipe] | |
def do_start(name, commandline): | |
clear_stoped_watchdog() | |
for watchdog in CURRENT_WATCHDOGS: | |
if watchdog.getName() == name: | |
msg = 'WatchDog(%r) already started' % name | |
logging.error(msg) | |
return msg | |
watchdog = WatchDog(name, commandline) | |
watchdog.start() | |
CURRENT_WATCHDOGS.append(watchdog) | |
msg = 'WatchDog(%r) started' % watchdog.getName() | |
logging.info(msg) | |
return msg | |
def do_stop(name, commandline): | |
assert name and commandline | |
clear_stoped_watchdog() | |
for watchdog in CURRENT_WATCHDOGS: | |
if watchdog.getName() == name: | |
logging.info('try stoping WatchDog(%r)', name) | |
result = watchdog.stop() | |
clear_stoped_watchdog() | |
if result: | |
return 'Stop WatchDog(%r) OK' % watchdog.getName() | |
else: | |
return 'Stop WatchDog(%r) Error' % watchdog.getName() | |
return 'Stop WatchDog(%r) existed, Stop OK' % name | |
def do_restart(name, commandline): | |
msg = do_stop(name, commandline) | |
if 'ok' in msg.lower(): | |
return do_start(name, commandline) | |
else: | |
return msg | |
def do_list(name, commandline): | |
assert name and commandline | |
clear_stoped_watchdog() | |
return os.linesep.join('%s PID:%s' % (x.getName(), x._pipe.pid) for x in CURRENT_WATCHDOGS) | |
def supervisord(): | |
server = SimpleXMLRPCServer.SimpleXMLRPCServer(('', DEFAULT_PORT), logRequests=True) | |
server.register_function(do_start) | |
server.register_function(do_stop) | |
server.register_function(do_restart) | |
server.register_function(do_list) | |
server.serve_forever() | |
def supervisorctl(): | |
argstr = ' '.join(sys.argv[1:]) | |
m = re.search('--service=(\w+)', argstr) | |
service = m.group(1) if m else 'node_agent' | |
m = re.search('-c\s+(\w+)', argstr) | |
action = m.group(1) if m else '' | |
filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), SUPERVISORD_CONF) | |
conf_services = read_service(filename) | |
services = conf_services.keys() if service == 'all' else [service] | |
for service in services: | |
if service not in conf_services: | |
logging.error('cannot found service=%r in %r', service, filename) | |
proxy = xmlrpclib.ServerProxy('http://localhost:%d' % DEFAULT_PORT) | |
if action == 'start': | |
print(proxy.do_start(service, conf_services[service])) | |
elif action == 'stop': | |
print(proxy.do_stop(service, conf_services[service])) | |
elif action == 'restart': | |
print(proxy.do_restart(service, conf_services[service])) | |
else: | |
print(proxy.do_list(service, conf_services[service])) | |
def main(): | |
if '--daemon' in sys.argv[1:]: | |
supervisord() | |
sys.exit(0) | |
if not check_daemon(): | |
if USE_PYTHONW: | |
close_fds = False if sys.platform == 'win32' else True | |
cmd = '%s "%s" --daemon' % (USE_PYTHONW, os.path.abspath(__file__)) | |
subprocess.Popen(cmd, close_fds=close_fds) | |
else: | |
cmd = 'start "%s" "%s" --daemon' % (sys.executable, os.path.abspath(__file__)) | |
os.system(cmd) | |
supervisorctl() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment