Welcome, guest | Sign In | My Account | Store | Cart
8

A simple way to implement Windows Service.

Python, 105 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
# winservice.py

from os.path import splitext, abspath
from sys import modules

import win32serviceutil
import win32service
import win32event
import win32api

class Service(win32serviceutil.ServiceFramework):
    _svc_name_ = '_unNamed'
    _svc_display_name_ = '_Service Template'
    def __init__(self, *args):
        win32serviceutil.ServiceFramework.__init__(self, *args)
        self.log('init')
        self.stop_event = win32event.CreateEvent(None, 0, 0, None)
    def log(self, msg):
        import servicemanager
        servicemanager.LogInfoMsg(str(msg))
        def sleep(self, sec):
            win32api.Sleep(sec*1000, True)
    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
        try:
            self.ReportServiceStatus(win32service.SERVICE_RUNNING)
            self.log('start')
            self.start()
            self.log('wait')
            win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
            self.log('done')
        except Exception, x:
            self.log('Exception : %s' % x)
            self.SvcStop()
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        self.log('stopping')
        self.stop()
        self.log('stopped')
        win32event.SetEvent(self.stop_event)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)
    # to be overridden
    def start(self): pass
    # to be overridden
    def stop(self): pass

def instart(cls, name, display_name=None, stay_alive=True):
    ''' Install and  Start (auto) a Service
            
        cls : the class (derived from Service) that implement the Service
        name : Service name
        display_name : the name displayed in the service manager
        stay_alive : Service will stop on logout if False
    '''
    cls._svc_name_ = name
    cls._svc_display_name_ = display_name or name
    try:
        module_path=modules[cls.__module__].__file__
    except AttributeError:
        # maybe py2exe went by
        from sys import executable
        module_path=executable
    module_file = splitext(abspath(module_path))[0]
    cls._svc_reg_class_ = '%s.%s' % (module_file, cls.__name__)
    if stay_alive: win32api.SetConsoleCtrlHandler(lambda x: True, True)
    try:
        win32serviceutil.InstallService(
            cls._svc_reg_class_,
            cls._svc_name_,
            cls._svc_display_name_,
            startType = win32service.SERVICE_AUTO_START
        )
        print 'Install ok'
        win32serviceutil.StartService(
            cls._svc_name_
        )
        print 'Start ok'
    except Exception, x:
        print str(x)

#
#
#
#
##### TEST MODULE
#
#
#
#

# winservice_test.py

from winservice import Service, instart

class Test(Service):
    def start(self):
        self.runflag=True
        while self.runflag:
            self.sleep(10)
            self.log("I'm alive ...")
    def stop(self):
        self.runflag=False
        self.log("I'm done")

instart(Test, 'aTest', 'Python Service Test')

Tested on Win XP only.

Patch for py2exe from Franck VINCENT

14 comments

Matt Keranen 5 years, 2 months ago  # | flag

Method for service removal? What steps would remove a service registered by this code from the registry?

Louis RIVIERE (author) 5 years, 2 months ago  # | flag

Service management. A Service is just a regular Windows Service, you can handle it like any other service running on your system.

You can start/stop/... it from the Services Manager, in which you will see the _svc_display_name of your Service.

You can handle it from a console with the NET or the SC commands.

Note that these commands, unlike the Windows Service Manager, use the _svc_name.

So, if you've install a Service like that:

>>> instart(MyServiceClass, 'myservice')

You can stop it like that :

>>> net stop myservice

You can remove like that :

>>> sc delete myservice
franck vincent 5 years, 1 month ago  # | flag

don't work with a binary compiled with py2exe. take the same code, compile it with py2exe and you will have this error:

Traceback (most recent call last):
  File "test.py", line 14, in
    instart(Test, 'aTest', 'Python Service Test')
  File "winservice.pyc", line 59, in instart

AttributeError: 'module' object has no attribute '__file__'

Any idea ?

franck vincent 5 years, 1 month ago  # | flag

current compiled executable path/name. The error below because __file__ attributes is no longer available when you are executing the binary.

You have to use

"sys.executable"

rather than

"modules[cls.__module__].__file__"

Below the code i used:

if hasattr(modules[cls.__module__],'__file__'):
        cmod=modules[cls.__module__].__file__
    else:
        cmod=sys.executable
    module_file=splitext(abspath(cmod))[0]
    cls._svc_reg_class_ = '%s.%s' % (module_file, cls.__name__)
franck vincent 5 years, 1 month ago  # | flag

whereAmI when i'm compiled ? Interesting stuff here:

http://www.py2exe.org/index.cgi/WhereAmI

Hi Louis,

I like your winservice module. I want to use it to daemonize a simple python project i have started, craigslistTools. I have your winservice module posted (crediting you) to my google site at http://sites.google.com/site/ninetynine99s/craigslist-tools-1 so ppl can run my code and see what it does. I would like to create a sourceforge project so maybe i can get some help developing this into a real project (i am a python newbie).

I would like to get your permission to include winservice.py as part of this craigslistTools project, giving you full credit for that module Please let me know if this is ok.

Thanks, Gerard

PS. I couldn't find your email address. This is the only way I knew to contact you.

Louis RIVIERE (author) 4 years, 6 months ago  # | flag

Hi Gerard !

It is indeed totally ok for you to use this recipe in any way you like, as it is the all purpose of this Cookbook.

PS : I can be reached at riviere@ati33.org

Matias Gonzalez 4 years, 4 months ago  # | flag

Hello Louis,

I could make it to install the service from the command line, but when I try to run compiled in a py2exe executable it installs ok and then shows an error "(1053, 'StartService', ...)" saying that the service didnt response. Any ideas? I try the same script (without the client import) all in one file, to avoid imports (for path troubles). I think it has to be something with py2exe but i couldn't find anything else.

Thanks in advance! Matias.

Louis RIVIERE (author) 4 years, 4 months ago  # | flag

Nope,
I don't use py2exe and I don't know much about it.
Maybe you can find something useful in the system event log.
Good luck.

Jacob Oscarson 4 years, 2 months ago  # | flag

Just a little gotcha for you who tries this recipe: your script can't live on a mapped drive... (duh.. maybe obvious to more win-centric persons than me)

andrey pochekutov 3 years, 8 months ago  # | flag

Can use: win32serviceutil.HandleCommandLine(Service) for command line register, unregister, start, stop service

class Service(win32serviceutil.ServiceFramework): _svc_name_ = "sample_python_service" _svc_display_name_ = "Python Service" _svc_description_ = "Tests Python service"

if __name__ == '__main__': win32serviceutil.HandleCommandLine(Service)

K 1 year, 1 month ago  # | flag

Your code uses tabs rather than spaces for indentation, which does not conform with PEP8. Could you please fix your indentation?

PEP8 "Style Guide for Python Code": http://www.python.org/dev/peps/pep-0008/

Louis RIVIERE (author) 1 year, 1 month ago  # | flag

@k : done

alexander 3 weeks, 1 day ago  # | flag

Hi Louis, I'm trying you receipe... I've got one error in instart(): <type 'exceptions.Exception'>(1073, 'CreateService', 'The specified service already exists.' This error leads to win32serviceutil.InstallPythonClassString(pythonClassString, serviceName)

Maybe you have an idea how to fix it?

thank you in advance

Add a comment

Sign in to comment