A simple way to implement Windows Service.
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
Method for service removal? What steps would remove a service registered by this code from the registry?
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:
You can stop it like that :
You can remove like that :
don't work with a binary compiled with py2exe. take the same code, compile it with py2exe and you will have this error:
Any idea ?
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:
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.
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
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.
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.
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)
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)
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/
@k : done
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
alexander check your services and see if the display name you are trying to use is already in use, if so create a new display name or use
sc delete myservice
to delete the service that you are trying to use
Hello Louis,
How would I go about adding a description for the service?
I added a variable for description in the service class and the instart function, but when I added it to the win32serviceutil.InstallService function call an error occured.
code:
Error:
Thanks in advance.
Try that :
Yeah that worked. Thank you very much. This is a really good example.
Please check lines 21,22 - I think your indentation is wrong. Thanks for the module, I will give it a try.
@Martin Ponweiser : fixed. Thanks for the report.
Louis,
I'm having the same problem that Matias Gonzalez had a few years ago. The service runs fine from command line, but when I try to run compiled in a py2exe executable it installs ok and then shows an error "(1053, 'StartService', ...)
I was wondering if you knew what is causing this or how to correct it?
Thanks again
@Andrew Ripo : No, I still don't use py2exe and I still don't have a clue. Sorry.
Louis,
I have solved the problem with the 1053 error. I'm going to leave my solution here for anyone that encounters the same issue.
When you create the .exe using py2exe you no longer need the instart function, because this is handled using command line functions on the .exe created.
So the start and stop functions from winservice_test.py need to be included in the winservice.py file in place of the functions they overwrite.
In addition the details for the name and display_name that would be passed to the instart function need to be included at the top of the winservice.py file instead of the templates
becomes:
Following the example from the py2exe sample service I added the following function.
in the next comment I will include a full copy of the working winservice_py2exe.py and a py2exe setup.py file.
This setup.py is taken from thenn py2exe samples included when you install the package.
setup.py
once you create the exe you can install the service from command using the following command
then to start the service you can use:
or from windows service manager.
Hope this was helpful.
On windows 7 64 bit with Anaconda 32bit installed
It will output
Install ok
Start ok
But actually it wasn't started. If I type
net start aTest
I got error code 3547
Thank you very much! This helped me create my first Windows service via python. While I have a service now, I am not sure how to use it... meaning I have some code I would like windows to run as a service (start on start up.. etc) but I don't know where/how my code fits into the service code above. Any examples of a very simple script running as a service ('hello world') would be greatly appreciated!