CherryPy作为Windows服务 - 示例

时间:2014-09-09 09:42:37

标签: python windows service cherrypy

我见过很多人都在努力 - 我也有问题。如果有人可以帮助使CherryPy服务示例工作,那将是一个很大的帮助。非常感谢您解释这些问题。

CherryPy Wiki上可以找到 CherryPy作为Windows服务示例。我试图让它发挥作用。这是我的代码:

"""
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)作为SvcDoRun
  • 的第一个和最后一个声明 wiki指示
  • 'log.error_file': 'c:\\MG\\temp\\CherryPy_Sample_Service.log',

重要说明:虽然可以使用控制台python cherrypy_sample_service.py install来安装服务,但 <}> 可以使用{{1}启动它命令。这样做的原因是,以这种方式创建的服务将引用python cherrypy_sample_service.py start可执行文件,它不是作为服务设计的。

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

python

在构建过程中,我收到以下警告:

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])

我已根据以下stack problem answer添加了此选项。

现在我可以致电Python27\App\lib\distutils\dist.py:267: UserWarning: Unknown distribution option: 'service' warnings.warn(msg) cherrypy_sample_service installcherrypy_sample_service remove了。但是,尝试运行服务(来自服务或通过cherrypy_sample_service update)会导致以下错误:

cherrypy_sample_service start

我被卡住了。甚至没有创建日志文件。你能帮助我让这个例子运行吗?我想如果我们能够解释并运行一个例子,这对于其他与相关问题斗争的人也会有用。谢谢!

2 个答案:

答案 0 :(得分:1)

我刚刚从您提到的维基页面上获取了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网络活动的防火墙软件。

答案 1 :(得分:1)

最后我找到了解决方案 - 我已经下载并重新安装了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的原因。

我只能有一些错误信息 - 希望这对其他人有用。