blob: cc6c989ce1911a32dcac5dbd5df289cbd3cd2b3c [file] [log] [blame]
Joshua Hesketh0ddd6382013-07-26 10:33:36 +10001#!/usr/bin/python2
2#
3# Copyright 2013 ...
4
5import argparse
6import daemon
7import extras
8import imp
9import json
10import logging
11import os
12import signal
13import sys
14
15import worker_manager
16
17# as of python-daemon 1.6 it doesn't bundle pidlockfile anymore
18# instead it depends on lockfile-0.9.1 which uses pidfile.
19pid_file_module = extras.try_imports(['daemon.pidlockfile', 'daemon.pidfile'])
20
21
22class Server(object):
23
24 """ This is the worker server object to be daemonized """
Joshua Hesketh363d0042013-07-26 11:44:07 +100025 log = logging.getLogger("worker_server.Server")
Joshua Hesketh0ddd6382013-07-26 10:33:36 +100026
27 def __init__(self, config):
28 # Config init
29 self.config = config
30 self.manager = None
31 self.plugins = []
32 self.load_plugins()
33
34 # Python logging output file.
35 self.debug_log = self.config['debug_log']
36
37 self.tasks = {}
38
39 def setup_logging(self):
40 if self.debug_log:
41 logging.basicConfig(format='%(asctime)s %(message)s',
42 filename=self.debug_log, level=logging.DEBUG)
43 else:
44 logging.basicConfig(format='%(asctime)s %(message)s',
45 level=logging.WARN)
46 self.log.debug('Log pusher starting.')
47
48 def load_plugins(self):
49 """ Load the available plugins from task_plugins """
50 # Load plugins
51 for ent in os.listdir('task_plugins'):
52 if (os.path.isdir('task_plugins/' + ent)
53 and os.path.isfile('task_plugins/' + ent + '/task.py')):
54 plugin_info = imp.find_module('task', ['task_plugins/' + ent])
55 self.plugins.append(imp.load_module('task', *plugin_info))
56
57 def run_tasks(self):
58 """ Run the tasks """
59 for plugin in self.plugins:
60 self.tasks[plugin.__worker_name__] = plugin.Runner(self.config)
61 self.tasks[plugin.__worker_name__].daemon = True
62 self.tasks[plugin.__worker_name__].start()
63
64 self.manager = worker_manager.GearmanManager(self.config, self.tasks)
65 self.manager.daemon = True
66 self.manager.start()
67
68 def exit_handler(self, signum):
69 signal.signal(signal.SIGUSR1, signal.SIG_IGN)
70 for task_name, task in self.tasks.items():
71 task.stop()
72 self.manager.stop()
73 sys.exit(0)
74
75 def main(self):
76 self.setup_logging()
77 self.run_tasks()
78
79 while True:
80 try:
81 signal.pause()
82 except KeyboardInterrupt:
83 print "Ctrl + C: asking tasks to exit nicely...\n"
84 self.exit_handler(signal.SIGINT)
85
86
87def main():
88 parser = argparse.ArgumentParser()
89 parser.add_argument('-c', '--config',
90 default=
Joshua Hesketh363d0042013-07-26 11:44:07 +100091 '/etc/turbo-hipster/config.json',
Joshua Hesketh0ddd6382013-07-26 10:33:36 +100092 help='Path to json config file.')
Joshua Hesketh478f1512013-07-26 11:47:27 +100093 parser.add_argument('--background', action='store_true',
94 help='Run in the background.')
Joshua Hesketh0ddd6382013-07-26 10:33:36 +100095 parser.add_argument('-p', '--pidfile',
Joshua Hesketh363d0042013-07-26 11:44:07 +100096 default='/var/run/turbo-hipster/'
Joshua Hesketh0ddd6382013-07-26 10:33:36 +100097 'sql-migrate-gearman-worker.pid',
98 help='PID file to lock during daemonization.')
99 args = parser.parse_args()
100
101 with open(args.config, 'r') as config_stream:
102 config = json.load(config_stream)
103
104 server = Server(config)
105
Joshua Hesketh478f1512013-07-26 11:47:27 +1000106 if args.background:
Joshua Hesketh0ddd6382013-07-26 10:33:36 +1000107 pidfile = pid_file_module.TimeoutPIDLockFile(args.pidfile, 10)
108 with daemon.DaemonContext(pidfile=pidfile):
109 server.main()
Joshua Hesketh478f1512013-07-26 11:47:27 +1000110 else:
111 server.main()
Joshua Hesketh0ddd6382013-07-26 10:33:36 +1000112
113
114if __name__ == '__main__':
115 main()