简体   繁体   中英

CherryPy as a Windows Service - the example

I've seen quite a few people struggle with it - I'm having issues too. It would be a great help if someone could help to make the CherryPy Service example work. Explaining the issues would be greatly appreciated.

There is a CherryPy as a Windows Service example available at: CherryPy Wiki . I'm trying to make it work. Here's my code:

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

The above differs from the linked example. I've added

  • self.ReportServiceStatus(win32service.SERVICE_START_PENDING) and
  • self.ReportServiceStatus(win32service.SERVICE_RUNNING) as first and last statement of SvcDoRun
  • 'log.error_file': 'c:\\\\MG\\\\temp\\\\CherryPy_Sample_Service.log', as the wiki instructs

Important remark : while it is possible to use the console python cherrypy_sample_service.py install to install the service, it is not possible to start it using python cherrypy_sample_service.py start command. The reason for this is, that service created this way will refer to python executable, which is not designed as a service.

Therefore for my further testing I've compiled the code using the following:

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

During the build I get the following warning:

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

I've added this option as per the following stack problem answer .

Now I'm able to call cherrypy_sample_service install , cherrypy_sample_service remove and cherrypy_sample_service update . However trying to run the service (either from services or via cherrypy_sample_service start ) results in the following error:

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

And I'm stuck. Log file does not even get created. Would you please help me to get the example running? I guess this would be also useful for other people struggling with related issues if we could have an example explained and running. Thanks!

I just took the version for 3.1 from the wiki page you mentioned and it works right away. Ie it installs, starts and stops from command line, as it starts and stops from service administration 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)

The test environment was: XP SP3, Python 2.7.5, CherryPy 3.3,0, pywin32 218.4.

Debugging tips

There's no requirement to build a binary to run your service. When you install pywin32 services from source it uses %PYDIR%\\Lib\\site-packages\\win32\\pythonservice.exe as a service proxy. Ie all service have it as run command line, having REG:\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\CherryPyService\\PythonClass defining actual Python class of the service.

Run pythonservice.exe from command line and make sure it runs without an error ( 1 ). You may also notice that there's a debugging option that allows you to attach stdout and stderr of the service to the terminal ( 2 ).

Make sure there's no firewall software that prevents pythonservice.exe from networking activity.

Finally I've found the solution - I've downloaded and reinstalled pywin32 ... Everything works perfectly fine! :)

Some final notes:

  • Service starts fine from Editor - compilation is not needed.
  • Adding 'log.error_file': 'c:\\\\somedir\\cherypy_sample_service.log' , to cherrypy.config.update helps to verify that service is up&running

While trying to debug the problem I've found out that once win32serviceutil.HandleCommandLine calls the StartService and gets to this part of the code:

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

I was not able to step into win32service.StartService . I was not able to locate the file and that is why I've reinstalled pywin32.

I could only wihs there was some error message - hope this will be helpful for others.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM