Click here to Skip to main content
15,075,864 members
Articles / Programming Languages / Python
Article
Posted 1 Aug 2016

Tagged as

Stats

55.7K views
16 bookmarked

Using Python to Make a Windows Service

Rate me:
Please Sign up or sign in to vote.
3.82/5 (9 votes)
8 Aug 2016CPOL1 min read
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)

Share

About the Author

Zen_Z
China China
No Biography provided

Comments and Discussions

 
QuestionAlternative way to address your need without a custom service Pin
yitzikc15-Jun-17 2:19
Memberyitzikc15-Jun-17 2:19 
GeneralA good start... Pin
FiresChild2-Aug-16 14:01
MemberFiresChild2-Aug-16 14:01 
on a good idea. Personally, I would have waited to flesh it out a bit more before posting it. That aside, I'll keep a track on this and do some research on it myself as well.
GeneralMy vote of 5 Pin
maratoni2-Aug-16 2:58
Membermaratoni2-Aug-16 2:58 
QuestionPyWin32 IS available for 3.5! Pin
Brisingr Aerowing1-Aug-16 16:21
professionalBrisingr Aerowing1-Aug-16 16:21 
AnswerRe: PyWin32 IS available for 3.5! Pin
Zen_Z2-Aug-16 15:43
MemberZen_Z2-Aug-16 15:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.