【问题标题】:How to stop a service created in python? [duplicate]如何停止在 python 中创建的服务? [复制]
【发布时间】:2016-02-25 04:58:46
【问题描述】:

我根据此代码创建了一个服务Is it possible to run a Python script as a service in Windows? If possible, how?
问题是我无法顺利停止服务。
要停止服务,我需要每隔一段时间重新检查停止事件的标志。
有没有更好的方法来停止 python 中的服务? 这就是我目前尝试停止服务的方式。

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

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_,''))
    myStatusThread = threading.Thread(target=win32event.WaitForSingleObject, args=(self.hWaitStop, win32event.INFINITE))
    myStatusThread.start()
    while True:
        if not myStatusThread.isAlive():
            sys.exit(0)
        else:
            doStuff()#do something that takes some time

所以服务只有在“doStuff”完成后才会停止,这可能需要很长时间。
我想在用户在服务中停止服务后立即停止服务。

【问题讨论】:

  • 你在检查什么样的标志?
  • 服务通常包含一个循环,等待某事发生(连接到套接字、存在文件等)并处理事件。在不知道您的循环是什么样子的情况下,除了说 test the f... Stop event 之外,很难就停止它的方式给出建议。您能介绍一下您的服务的基本情况吗?
  • 我编辑了我的问题

标签: python windows-services


【解决方案1】:

使用NSSM 在winapi 中编写此任务可能会更好:

nssm install my_python_service
nssm set my_python_service Application C:\Python3\python.exe
nssm set my_python_service AppDirectory C:\myscript\
nssm set my_python_sevice AppParameters C:\myscrip\myscript_main_file.py

nssm set my_python_sevice Start SERVICE_AUTO_START
nssm run my_python_service

停止服务:

nssm stop my_python_service

【讨论】:

  • 这并没有解释为什么 OP 不能用 WINAPI 停止,也没有给出任何关于如何优雅地关闭一个用 NSSM 启动的服务的建议。你至少可以在引用的帖子上引用this answer
【解决方案2】:

事实上,您的问题是双重的:我如何测试一个事件以及如何顺利地停止一个长时间运行的例程?不幸的是,第二部分没有简单直接的答案。常见的用法是手动识别代码中的停止点,并在其中放置一个简单的例程来测试事件并引发自定义异常。这允许一个地方在退出之前进行一些清理。

你的代码可能会变成(或多或少):

class EventException(Exception):
   def __init__(status):
       # allows to know where you exit from in case cleanup depends on it
       self.status = status

以后...

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

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

def testEvent(self, status):
    if (win32event.win32event.WaitForSingleObject(self.hWaitStop, 0)
            == win32event.WAIT_OBJECT_0):
        raise EventException(status)

def SvcDoRun(self):
    servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                          servicemanager.PYS_SERVICE_STARTED,
                          (self._svc_name_,''))
    while True:
        # wait the event with a 0ms timeout (ie: just test it)
        evt = win32event.win32event.WaitForSingleObject(self.hWaitStop, 0)
        if evt == win32event.WAIT_OBJECT_0  # event is is signaled state
            sys.exit(0)
        else:
            try:
                self.doStuff()
            except EventException as e:
                status = e.status
                # cleanup potentially dependent on status

def doStuff(self):
    #do something that takes some time
    ...
    # in some places test if we should stop immediatelly
    self.testEvent(status)    # status is an arbitrary value
    ...

这样:

  • 您无需辅助线程即可测试事件
  • 您不必等待完整处理以停止服务
  • 如果您在处理过程中停止服务,您就有了清理空间。

【讨论】:

  • @yuval:我在问题关闭之前发布了一个不完整的答案,所以我可以编辑和取消删除它。
猜你喜欢
  • 2019-08-05
  • 2016-09-29
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 2019-06-18
  • 2010-12-17
  • 2022-08-07
  • 1970-01-01
相关资源
最近更新 更多