【问题标题】:How to keep a windows service running如何保持 Windows 服务运行
【发布时间】:2011-07-15 23:18:12
【问题描述】:

下面是我正在运行的 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 周围,但结果仍然相同。该服务在崩溃时没有重新启动......请有任何想法的人吗?如果在发生崩溃时无法重新启动服务,它就不是那么有用了……不妨将它作为 .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

【问题讨论】:

  • 是什么错误导致它崩溃?除了不在 main() 中休眠之外,您的代码看起来还可以使用。
  • @qor72 这只是使脚本成为服务的框架。我正在运行的脚本用于解析串行数据。问题是可能会发生许多错误,例如服务可能无法连接到我的数据库。我现在想要的是休眠几秒钟并再次重新启动服务。如果我有服务设置在失败时重新启动,我不确定为什么它应该死而不重新启动。我一定是在某处丢失了一段代码来处理这个问题?
  • 在我编写的服务中,而不是在 Python 中,错误检查会将错误写入日志并继续,无需重新启动。这就是为什么我对你的信息感到好奇;例如,是否该服务无法写入错误日志,从而导致破坏您的服务的错误?
  • @qor72 我刚刚想通了...这里的回答给了我一些见解。 stackoverflow.com/questions/220382/… 。所以在 python 中我需要做一个 os._exit(1) 或一些不为零的退出。 BiggAl 的答案很接近,但缺少 os._exit(-1) 而不是 return -1

标签: python windows-services


【解决方案1】:

为什么不使用 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)

【讨论】:

  • 在我的回答中我做到了。就在我调用 main 而不是函数本身的地方。
【解决方案2】:

以下是仅除以零以引发错误的服务。如果出现错误,则会发送一个事件并使用os._exit(-1) 退出服务。该值必须是除 0 以外的任何值,以便 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)

【讨论】:

  • 是否有理由使用 os._exit(-1) 而不是 sys.exit(-1)?
【解决方案3】:

我怀疑您的服务实际上并没有崩溃,而是在它有机会运行之前完成。您是否尝试过在main 函数中插入几秒钟的睡眠语句?

【讨论】:

  • main函数是一个无限循环,直到服务get的停止命令。该脚本实际上正在崩溃,因为记录了导致崩溃的错误。如果出现错误,我希望服务重新启动...
  • 您的错误信息是什么?是否有可能在崩溃时仍然返回错误代码 0?也许你需要一些类似的东西:try:\n main()\nexcept:\n return -1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-14
  • 2013-01-26
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
相关资源
最近更新 更多