How do you run a Python script as a service in Windows?

后端 未结 13 1603
你的背包
你的背包 2020-11-22 02:18

I am sketching the architecture for a set of programs that share various interrelated objects stored in a database. I want one of the programs to act as a service which prov

13条回答
  •  隐瞒了意图╮
    2020-11-22 02:39

    A complete pywin32 example using loop or subthread

    After working on this on and off for a few days, here is the answer I would have wished to find, using pywin32 to keep it nice and self contained.

    This is complete working code for one loop-based and one thread-based solution. It may work on both python 2 and 3, although I've only tested the latest version on 2.7 and Win7. The loop should be good for polling code, and the tread should work with more server-like code. It seems to work nicely with the waitress wsgi server that does not have a standard way to shut down gracefully.

    I would also like to note that there seems to be loads of examples out there, like this that are almost useful, but in reality misleading, because they have cut and pasted other examples blindly. I could be wrong. but why create an event if you never wait for it?

    That said I still feel I'm on somewhat shaky ground here, especially with regards to how clean the exit from the thread version is, but at least I believe there are nothing misleading here.

    To run simply copy the code to a file and follow the instructions.

    update:

    Use a simple flag to terminate thread. The important bit is that "thread done" prints.
    For a more elaborate example exiting from an uncooperative server thread see my post about the waitress wsgi server.

    # uncomment mainthread() or mainloop() call below
    # run without parameters to see HandleCommandLine options
    # install service with "install" and remove with "remove"
    # run with "debug" to see print statements
    # with "start" and "stop" watch for files to appear
    # check Windows EventViever for log messages
    
    import socket
    import sys
    import threading
    import time
    from random import randint
    from os import path
    
    import servicemanager
    import win32event
    import win32service
    import win32serviceutil
    # see http://timgolden.me.uk/pywin32-docs/contents.html for details
    
    
    def dummytask_once(msg='once'):
        fn = path.join(path.dirname(__file__),
                    '%s_%s.txt' % (msg, randint(1, 10000)))
        with open(fn, 'w') as fh:
            print(fn)
            fh.write('')
    
    
    def dummytask_loop():
        global do_run
        while do_run:
            dummytask_once(msg='loop')
            time.sleep(3)
    
    
    class MyThread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
    
        def run(self):
            global do_run
            do_run = True
            print('thread start\n')
            dummytask_loop()
            print('thread done\n')
    
        def exit(self):
            global do_run
            do_run = False
    
    
    class SMWinservice(win32serviceutil.ServiceFramework):
        _svc_name_ = 'PyWinSvc'
        _svc_display_name_ = 'Python Windows Service'
        _svc_description_ = 'An example of a windows service in Python'
    
        @classmethod
        def parse_command_line(cls):
            win32serviceutil.HandleCommandLine(cls)
    
        def __init__(self, args):
            win32serviceutil.ServiceFramework.__init__(self, args)
            self.stopEvt = win32event.CreateEvent(None, 0, 0, None)  # create generic event
            socket.setdefaulttimeout(60)
    
        def SvcStop(self):
            servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                                servicemanager.PYS_SERVICE_STOPPED,
                                (self._svc_name_, ''))
            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
            win32event.SetEvent(self.stopEvt)  # raise event
    
        def SvcDoRun(self):
            servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                                servicemanager.PYS_SERVICE_STARTED,
                                (self._svc_name_, ''))
            # UNCOMMENT ONE OF THESE
            # self.mainthread()
            # self.mainloop()
    
        # Wait for stopEvt indefinitely after starting thread.
        def mainthread(self):
            print('main start')
            self.server = MyThread()
            self.server.start()
            print('wait for win32event')
            win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
            self.server.exit()
            print('wait for thread')
            self.server.join()
            print('main done')
    
        # Wait for stopEvt event in loop.
        def mainloop(self):
            print('loop start')
            rc = None
            while rc != win32event.WAIT_OBJECT_0:
                dummytask_once()
                rc = win32event.WaitForSingleObject(self.stopEvt, 3000)
            print('loop done')
    
    
    if __name__ == '__main__':
        SMWinservice.parse_command_line()
    

提交回复
热议问题