CherryPy作为Windows服务 – 示例

我见过不less人为此而苦恼 – 我也有问题。 如果有人能够帮助CherryPy服务的例子工作,这将是一个很大的帮助。 解释这些问题将不胜感激。

有一个CherryPy作为一个Windows服务的例子可以在: CherryPy Wiki 。 我正在努力使其工作。 这是我的代码:

""" The most basic (working) CherryPy 3.0 Windows service possible. Requires Mark Hammond's pywin32 package. """ import cherrypy import win32serviceutil import win32service import win32event import servicemanager class HelloWorld: """ Sample request handler class. """ def index(self): return "Hello world!" index.exposed = True class MyService(win32serviceutil.ServiceFramework): """NT Service.""" _svc_name_ = "CherryPyService" _svc_display_name_ = "CherryPy Service" def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) # create an event that SvcDoRun can wait on and SvcStop # can set. self.stop_event = win32event.CreateEvent(None, 0, 0, None) def SvcDoRun(self): self.ReportServiceStatus(win32service.SERVICE_START_PENDING) servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_,'')) cherrypy.tree.mount(HelloWorld(), '/') # in practice, you will want to specify a value for # log.error_file below or in your config file. If you # use a config file, be sure to use an absolute path to # it, as you can't be assured what path your service # will run in. cherrypy.config.update({ 'global':{ 'engine.autoreload.on': False, 'log.screen': False, 'log.error_file': 'c:\\MG\\temp\\CherryPy_Sample_Service.log', 'engine.SIGHUP': None, 'engine.SIGTERM': None } }) # set blocking=False so that start() does not block cherrypy.server.quickstart() cherrypy.engine.start(blocking=False) # now, block until our event is set... win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE) self.ReportServiceStatus(win32service.SERVICE_RUNNING) def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) cherrypy.server.stop() win32event.SetEvent(self.stop_event) if __name__ == '__main__': win32serviceutil.HandleCommandLine(MyService) 

以上不同于链接的例子。 我已经添加

  • self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
  • self.ReportServiceStatus(win32service.SERVICE_RUNNING)作为self.ReportServiceStatus(win32service.SERVICE_RUNNING)第一个和最后一个语句
  • 'log.error_file': 'c:\\MG\\temp\\CherryPy_Sample_Service.log',如wiki指示

重要说明 :虽然可以使用控制台python cherrypy_sample_service.py install来安装服务,但是不可能使用python cherrypy_sample_service.py start命令来启动它。 原因是,这种方式创build的服务将引用python可执行文件,这不是作为服务devise的。

因此,为了进一步testing,我使用以下代码编译了代码:

 from cx_Freeze import setup, Executable exe = Executable( script='cherrypy_sample_service.py' ) build_options = {'includes': ['cherrypy', 'win32serviceutil', 'win32service', 'win32event', 'servicemanager']} setup( name = "CherryPy Sample Service", version = "0.1", service = ["cherrypy_sample_service.py"], options = {"build_exe" : build_options}, executables = [exe]) 

在构build期间,我收到以下警告:

 Python27\App\lib\distutils\dist.py:267: UserWarning: Unknown distribution option: 'service' warnings.warn(msg) 

我已经根据下面的堆栈问题答案添加了这个选项。

现在我可以调用cherrypy_sample_service installcherrypy_sample_service removecherrypy_sample_service update 。 然而,试图运行服务(无论是从服务或通过cherrypy_sample_service start )导致以下错误:

 Error starting service: The service did not respond to the start or control request in a timely fashion. 

而我卡住了。 日志文件甚至没有创build。 你能帮我做个例子吗? 如果我们能够解释和运行一个例子,我想这对其他人在处理相关问题时也是有用的。 谢谢!

我刚刚从你提到的维基页面上获得了3.1版本,并且马上就能正常工作。 即它从命令行安装,启动和停止,因为它从服务管理GUI启动和停止。

 """ The most basic (working) CherryPy 3.1 Windows service possible. Requires Mark Hammond's pywin32 package. """ import cherrypy import win32serviceutil import win32service class HelloWorld: """ Sample request handler class. """ @cherrypy.expose def index(self): return "Hello world!" class MyService(win32serviceutil.ServiceFramework): """NT Service.""" _svc_name_ = "CherryPyService" _svc_display_name_ = "CherryPy Service" def SvcDoRun(self): cherrypy.tree.mount(HelloWorld(), '/') # in practice, you will want to specify a value for # log.error_file below or in your config file. If you # use a config file, be sure to use an absolute path to # it, as you can't be assured what path your service # will run in. cherrypy.config.update({ 'global':{ 'log.screen': False, 'engine.autoreload.on': False, 'engine.SIGHUP': None, 'engine.SIGTERM': None } }) cherrypy.engine.start() cherrypy.engine.block() def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) cherrypy.engine.exit() self.ReportServiceStatus(win32service.SERVICE_STOPPED) # very important for use with py2exe # otherwise the Service Controller never knows that it is stopped ! if __name__ == '__main__': win32serviceutil.HandleCommandLine(MyService) 

测试环境是:XP SP3,Python 2.7.5,CherryPy 3.3,0,pywin32 218.4。

调试技巧

不需要构建二进制文件来运行您的服务。 当您从源代码安装pywin32服务时,它使用%PYDIR%\Lib\site-packages\win32\pythonservice.exe作为服务代理。 即所有的服务都有它作为运行命令行,有REG:\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CherryPyService\PythonClass定义服务的实际Python类。

从命令行运行pythonservice.exe ,并确保它运行没有错误( 1 )。 您可能还会注意到,有一个调试选项可以让您将服务的stdout和stderr附加到终端( 2 )。

确保没有阻止pythonservice.exe从网络活动的防火墙软件。

最后,我找到了解决方案 – 我已经下载并重新安装pywin32 …一切工作完全正常! 🙂

一些最后的说明:

  • 服务从编辑器开始很好 – 编译是不需要的。
  • 添加'log.error_file': 'c:\\somedir\cherypy_sample_service.log'cherrypy.config.update有助于验证服务正在运行

在尝试调试问题时,我发现一旦win32serviceutil.HandleCommandLine调用StartService并进入代码的这一部分:

  try: win32service.StartService(hs, args) finally: win32service.CloseServiceHandle(hs) 

我无法步入win32service.StartService 。 我无法找到该文件,这就是为什么我重新安装pywin32。

我只能有一些错误信息 – 希望这将有助于其他人。