1
2
3 """
4 This file is part of the web2py Web Framework
5 Developed by Massimo Di Pierro <mdipierro@cs.depaul.edu> and
6 Limodou <limodou@gmail.com>.
7 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8
9 This makes uses of the pywin32 package
10 (http://sourceforge.net/projects/pywin32/).
11 You do not need to install this package to use web2py.
12
13
14 """
15
16 import time
17 import os
18 import sys
19 import traceback
20 try:
21 import win32serviceutil
22 import win32service
23 import win32event
24 except:
25 if os.name == 'nt':
26 print "Warning, winservice is unable to install the Mark Hammond Win32 extensions"
27 import servicemanager
28 import _winreg
29 from gluon.fileutils import up
30
31
32 __all__ = ['web2py_windows_service_handler']
33
34
35 -class Service(win32serviceutil.ServiceFramework):
36
37 _svc_name_ = '_unNamed'
38 _svc_display_name_ = '_Service Template'
39 _svc_description_ = '_Service Template description'
40
42 win32serviceutil.ServiceFramework.__init__(self, *args)
43 self.stop_event = win32event.CreateEvent(None, 0, 0, None)
44
46 servicemanager.LogInfoMsg(str(msg))
47
49 """
50 Log an error message to windows application event log.
51 """
52 servicemanager.LogErrorMsg(str(msg))
53
55 self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
56 try:
57 self.ReportServiceStatus(win32service.SERVICE_RUNNING)
58 self.start()
59 win32event.WaitForSingleObject(self.stop_event,
60 win32event.INFINITE)
61 except:
62 self.log(traceback.format_exc(sys.exc_info))
63 self.SvcStop()
64 self.ReportServiceStatus(win32service.SERVICE_STOPPED)
65
67 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
68 try:
69 self.stop()
70 except:
71 self.log(traceback.format_exc(sys.exc_info))
72 win32event.SetEvent(self.stop_event)
73 self.ReportServiceStatus(win32service.SERVICE_STOPPED)
74
75
76
79
80
81
84
85
87
88 _svc_name_ = 'web2py'
89 _svc_display_name_ = 'web2py Service'
90 _svc_description_ = 'Web2py application framework service'
91 _exe_args_ = 'options'
92 server = None
93
95 try:
96 h = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
97 r'SYSTEM\CurrentControlSet\Services\%s'
98 % self._svc_name_)
99 try:
100 cls = _winreg.QueryValue(h, 'PythonClass')
101 finally:
102 _winreg.CloseKey(h)
103 dir = os.path.dirname(cls)
104 os.chdir(dir)
105 from gluon.settings import global_settings
106 global_settings.gluon_parent = dir
107 return True
108 except:
109 self.log("Can't change to web2py working path; server is stopped")
110 return False
111
113 self.log('web2py server starting')
114 if not self.chdir():
115 return
116 if len(sys.argv) == 2:
117 opt_mod = sys.argv[1]
118 else:
119 opt_mod = self._exe_args_
120 options = __import__(opt_mod, [], [], '')
121 if True:
122 if hasattr(options, 'numthreads') and not hasattr(options, 'minthreads'):
123 options.minthreads = options.numthreads
124 if not hasattr(options, 'minthreads'):
125 options.minthreads = None
126 if not hasattr(options, 'maxthreads'):
127 options.maxthreads = None
128 from gluon import main
129 self.server = main.HttpServer(
130 ip=options.ip,
131 port=options.port,
132 password=options.password,
133 pid_filename=options.pid_filename,
134 log_filename=options.log_filename,
135 profiler_filename=options.profiler_filename,
136 ssl_certificate=options.ssl_certificate,
137 ssl_private_key=options.ssl_private_key,
138 min_threads=options.minthreads,
139 max_threads=options.maxthreads,
140 server_name=options.server_name,
141 request_queue_size=options.request_queue_size,
142 timeout=options.timeout,
143 socket_timeout=options.socket_timeout,
144 shutdown_timeout=options.shutdown_timeout,
145 path=options.folder,
146 interfaces=options.interfaces
147 )
148 try:
149 from gluon.rewrite import load
150 load()
151 self.server.start()
152 except:
153 self.server = None
154 raise
155
163
164
166
167 _svc_name_ = 'web2py_cron'
168 _svc_display_name_ = 'web2py Cron Service'
169 _svc_description_ = 'web2py Windows cron service for scheduled tasks'
170 _exe_args_ = 'options'
171
173 from gluon import newcron
174 import logging
175 import logging.config
176 from gluon.settings import global_settings
177 from gluon.fileutils import abspath
178 from os.path import exists, join
179
180 self.log('web2py Cron service starting')
181 if not self.chdir():
182 return
183 if len(sys.argv) == 2:
184 opt_mod = sys.argv[1]
185 else:
186 opt_mod = self._exe_args_
187 options = __import__(opt_mod, [], [], '')
188 logpath = abspath(join(options.folder, "logging.conf"))
189
190 if exists(logpath):
191 logging.config.fileConfig(logpath)
192 else:
193 logging.basicConfig()
194 logger = logging.getLogger("web2py.cron")
195 global_settings.web2py_crontype = 'external'
196 if options.scheduler:
197 apps = [app.strip() for app in options.scheduler.split(
198 ',') if check_existent_app(options, app.strip())]
199 else:
200 apps = None
201
202 misfire_gracetime = float(options.misfire_gracetime) if 'misfire_gracetime' in dir(options) else 0.0
203 logger.info('Starting Window cron service with %0.2f secs gracetime.' % misfire_gracetime)
204 self._started = True
205 wait_full_min = lambda: 60 - time.time() % 60
206 while True:
207 try:
208 if wait_full_min() >= misfire_gracetime:
209 self.extcron = newcron.extcron(options.folder, apps=apps)
210 self.extcron.start()
211 time.sleep(wait_full_min())
212 else:
213 logger.debug('time.sleep() offset detected: %0.3f s' % wait_full_min())
214 while wait_full_min() <= misfire_gracetime:
215 pass
216 if apps != None:
217 break
218 if not self._started:
219 break
220 except Exception, ex:
221 self.extcron = None
222 self.log_error('%s, restarting service.' % ex)
223 logger.exception('Exception! Restarting Windows cron service.' % ex)
224 self.start()
225
227 self.log('web2py Cron service stopping')
228 if not self.chdir():
229 return
230 if self.extcron:
231 self._started = False
232 self.extcron.join()
233
248
249 if __name__ == '__main__':
250 register_service_handler(cls=Web2pyService)
251 register_service_handler(cls=Web2pyCronService)
252