Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Python

Using Python to Make a Windows Service

3.82/5 (9 votes)
8 Aug 2016CPOL1 min read 68.7K  
How to make a Windows service using Python

Introduction

This is about the way how to make a Windows service using Python.

Background

For business thing, I have to transfer data from SQLServer to MongoDB. And it needs to occur everyday. So I have to make it a Windows service.

Using the Code

This is a packaging code, for making my logic which is written with Python to a Windows service.

The code is like this:

C++
import pythoncom
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import time
import DataTransToMongo
import sys

class DataTransToMongoService(win32serviceutil.ServiceFramework):
    _svc_name_ = 'DataTransToMongoService'
    _svc_display_name_ = 'DataTransToMongoService'
    
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        
        socket.setdefaulttimeout(60)
        self.isAlive = True
        
    def SvcStop(self):
        self.isAlive = False
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        
    def SvcDoRun(self):
        self.isAlive = True
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, 
                              servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ''))
        self.main()
        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
        
    def main(self):
        #i = 0
        while self.isAlive: 
            DataTransToMongo.run() //This is where my logic exists
            time.sleep(86400)
        
        #pass
        
if __name__ == '__main__':
    if len(sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(DataTransToMongoService)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(DataTransToMongoService)

Of course, we do not want to install Python environment on our production server. So I have to make it an executable file, which is EXE for Windows. The problem is that the version of python I used is 3.5, so the famous tool pywin32 is not available for me.(As one of the comments says, pywin32 is available now, I wrote this long time ago, sorry for not checking it out.)  After searching, finally I found it--pyinstaller.

Download and install it. Then run cmd, typing the code like below:

pyinstaller --onefile --hidden-import win32timezone DataTransToMongoService.py

There are a lot of other parameters, and we can get help from http://www.pyinstaller.org/.

 

About --hidden-import, now it has an alias called --hiddenimport.

When I run pyinstaller --onefile DataTransToMongoService.py, I get a error which shows ImportError: No module named win32timezone.

Then I add that option. But now, pyinstaller has solved this problem. I don't need --hiddenimport anymore.

 

 

2016/08/09

Last night I researched the code, and found that there is something can be optimized.

The service can not be closed normally. So I write a sample for test, and it goes well.

The sample code is like below:

import pythoncom
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import time
import DataTransToMongo
import sys

class TestService(win32serviceutil.ServiceFramework):
    _svc_name_ = 'TestService'
    _svc_display_name_ = 'TestService'
    
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)        
        socket.setdefaulttimeout(60)
        
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        
    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ''))
        self.main()
        
    def main(self):
        f = open('D:\\test.txt', 'a')
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            f.write('Test Service  \n')
            f.flush()
            #block for 24*60*60 seconds and wait for a stop event
            #it is used for a one-day loop
            rc = win32event.WaitForSingleObject(self.hWaitStop, 24*60*60*1000)
        f.write('shut down \n')
        f.close()
        
if __name__ == '__main__':
    if len(sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(TestService)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(TestService)

History

  • 1st August, 2016: Initial version
  • 9th August, 2016: fix the unclosable bug.( unclosable => can not be closed ^^)

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)