如何保持Windows服务运行

4 投票
3 回答
7920 浏览
提问于 2025-04-16 13:45

下面是我正在运行的Windows服务的框架。如果出现错误,错误会被记录下来,并可以在事件查看器中查看。问题是,脚本一旦出错就会直接退出,而不会重新启动,尽管我已经设置了在第一次、第二次及后续失败时重启服务。目前我没有太多的错误处理,因为我想看看在事件查看器中可能出现的错误,以便我可以编写代码来相应地处理这些错误。

from win32api import CloseHandle, GetLastError, SetConsoleCtrlHandler
import os
import sys 
import time
import pythoncom
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket

class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "my_service_name"
    _svc_display_name_ = "my service"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        SetConsoleCtrlHandler(lambda x: True, True)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.run = False

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.run = True
        self.main()

    def main(self):
        while self.run == True
            pass          

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

补充:

我尝试在self.main周围加上try: except:,但结果还是一样。服务崩溃时没有重新启动……请问有没有人有什么想法?如果服务在崩溃时无法重启,那就没什么用处了……还不如直接运行一个.pyc文件。

补充:

下面是我脚本中可能出现的一个错误示例……我认为这个错误信息并不是特别有用,因为我想要实现的是让服务在崩溃后重新启动,但无论如何,这里有一个导致我的服务崩溃而没有重新启动的错误示例:

The instance's SvcRun() method failed 
Traceback (most recent call last):
  File "C:\Python27\lib\site-packages\win32\lib\win32serviceutil.py", line 806, in SvcRun
    self.SvcDoRun()
  File "C:\Some_Service.py", line 46, in SvcDoRun
    self.main()
  File "Some_Service.py", line 61, in main
    ser = self.open_serial_port()
  File "Some_Service.py", line 70, in open_serial_port
    serial_connection.open()
  File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 56, in open
    raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
SerialException: could not open port COM6: [Error 1225] The remote system refused the network connection. 
%2: %3

3 个回答

0

你为什么不使用try-except来处理这个呢?

class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "my_service_name"
    _svc_display_name_ = "my service"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        SetConsoleCtrlHandler(lambda x: True, True)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.run = False

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.run = True
        self.main()

    def main(self):
        while self.run == True
            try :
                <your code>
            except :
                time.sleep(3)
                <may be an error log here>



if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)
0

我怀疑你的服务其实并没有崩溃,而是在运行之前就已经完成了。你有没有试过在main函数里加一个暂停几秒钟的语句呢?

8

下面是一个服务,它只是通过除以零来制造一个错误。如果发生错误,就会发送一个事件,然后服务会使用 os._exit(-1) 退出。这个值必须是非零的,这样Windows系统才能知道这个服务没有正常退出。

from win32api import CloseHandle, GetLastError, SetConsoleCtrlHandler
import os
import sys
import time

import win32serviceutil
import win32service
import win32event
import servicemanager

import traceback



class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "test"
    _svc_display_name_ = "test"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        SetConsoleCtrlHandler(lambda x: True, True)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)




    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.run = False
    def SvcDoRun(self):

        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.run = True
        try: # try main
            self.main()
        except:
            servicemanager.LogErrorMsg(traceback.format_exc()) # if error print it to event log
            os._exit(-1)#return some value other than 0 to os so that service knows to restart


    def main(self):

        while self.run == True:
            time.sleep(30)         
            t = 1/0

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

撰写回答