|
# Copyright (C) 2009-2010 by Fog Creek Software. All rights reserved.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
import _winreg as winreg
import os
import servicemanager
import subprocess
import sys
import threading
import win32event
import win32evtlogutil
import win32service
import win32serviceutil
# must be set before mercurial.encoding is imported by further imports
os.environ['HGENCODING'] = 'utf8'
from werkzeug.debug import DebuggedApplication
import wsgiserver
from workerqueue.daemon import IndexDaemon, QueueDaemon
from workerqueue.kilnconfig import KilnConfig
from api.handlers import app
import settings
from versionmiddleware import VersionMiddleware
from errorloggingmiddleware import ErrorLoggingMiddleware
debug = getattr(settings, 'DEBUG', False)
app.debug = debug
app = VersionMiddleware(app)
app = ErrorLoggingMiddleware(app)
# This middleware gets loaded last.
if debug:
app = DebuggedApplication(app, evalex=True)
# DO NOT REMOVE THIS. It's used to trick py2exe and/or cxfreeze
# into including a bunch of modules when it builds the .exe.
if False:
import imports
class RedisServer(object):
def __init__(self, port, db_file):
super(RedisServer, self).__init__()
self.conf_file = os.path.join(os.path.dirname(db_file), 'redis.conf')
self.log_file = os.path.join(os.path.dirname(db_file), 'redis-log.txt')
self.write_conf(port, db_file)
self.redis = None
def write_conf(self, port, db_file):
with open(self.conf_file, 'w') as f:
f.write(self.conf(port, db_file, self.log_file))
def conf(self, port, db_file, log_file):
templ = '''
activerehashing yes
appendfsync everysec
appendonly no
daemonize no
databases 4
dbfilename %(dbfilename)s
dir %(dir)s
loglevel warning
logfile %(logfile)s
maxmemory 100m
maxmemory-policy volatile-lru
port %(port)s
rdbcompression yes
save 300 10
save 60 10000
save 900 1
timeout 300
vm-enabled no
vm-max-memory 0
'''
templ = '\n'.join(l.lstrip() for l in templ.splitlines())
d, f = os.path.split(db_file)
return templ % {'dir': d,
'dbfilename': f,
'logfile': log_file,
'port': port}
def start(self):
if self.redis: return
d = os.path.dirname(os.path.realpath(sys.argv[0] if not sys.argv[0].lower().endswith('pythonservice.exe') else __file__))
redis = os.path.join(d, 'redis-server.exe')
self.redis = subprocess.Popen([redis, self.conf_file])
def stop(self):
try:
self.redis.terminate()
except OSError, e:
pass
self.redis = None
class KilnBackendService(win32serviceutil.ServiceFramework):
_svc_name_ = "KilnStorageService"
_svc_display_name_ = "Kiln Storage Service"
_svc_deps_ = ["EventLog"]
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'Software\Fog Creek Software\Kiln') as hKey:
self.kiln_backend_port, _ = winreg.QueryValueEx(hKey, 'KilnBackendPort')
self.kiln_backend_ip, _ = winreg.QueryValueEx(hKey, 'KilnBackendIP')
self.redis_db, _ = winreg.QueryValueEx(hKey, 'MiniredisDB')
self.stop_mutex = win32event.CreateEvent(None, 0, 0, None)
def _serve(self):
try:
self.webserver.start()
except Exception, e:
self.SvcStop()
def SvcDoRun(self):
mtx = win32event.CreateMutex(None, False, 'KilnStorageServiceMutex')
try:
self.webserver = wsgiserver.CherryPyWSGIServer(
(self.kiln_backend_ip, self.kiln_backend_port),
wsgiserver.WSGIPathInfoDispatcher({'/': app}),
numthreads=20,
timeout=12 * 60 * 60, # matching Kiln front-end
)
except Exception, e:
import traceback
with open(r'c:\errors.txt', 'w') as fd:
fd.write(e + '\n\n' + traceback.format_exc())
conf = KilnConfig()
daemon_port = int(conf.read('Daemon', 'port'))
self.redis = RedisServer(port=daemon_port, db_file=self.redis_db)
self.daemons = [QueueDaemon(port=daemon_port, conf=conf) for x in xrange(int(conf.read('Daemon', 'QueueThreads', default=1)))]
self.daemons += [IndexDaemon(port=daemon_port, conf=conf) for x in xrange(int(conf.read('Daemon', 'IndexThreads', default=1)))]
t = threading.Thread(target=self._serve)
self.redis.start()
for daemon in self.daemons:
daemon.start()
t.start()
win32evtlogutil.ReportEvent(self._svc_name_,
servicemanager.PYS_SERVICE_STARTED,
0, # category
servicemanager.EVENTLOG_INFORMATION_TYPE,
(self._svc_name_, ''))
win32event.WaitForSingleObject(self.stop_mutex, win32event.INFINITE)
win32evtlogutil.ReportEvent(self._svc_name_,
servicemanager.PYS_SERVICE_STOPPED,
0,
servicemanager.EVENTLOG_INFORMATION_TYPE,
(self._svc_name_, ''))
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.webserver.stop()
for daemon in self.daemons:
daemon.stop()
self.redis.stop()
win32event.SetEvent(self.stop_mutex)
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(KilnBackendService)
|
Loading...