Skip to content

Instantly share code, notes, and snippets.

@liaoliaopro
Created March 30, 2016 02:51
Show Gist options
  • Save liaoliaopro/6f76a1e5a4826c4fcc873e58fd18ea76 to your computer and use it in GitHub Desktop.
Save liaoliaopro/6f76a1e5a4826c4fcc873e58fd18ea76 to your computer and use it in GitHub Desktop.
a lite supervisord for windows
#!/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