Как остановить службу, созданную на Python?

Я создал службу на основе этого кода Можно ли запустить сценарий Python как службу в Windows? Если возможно, то как?
Проблема в том, что я не могу остановить службу плавно.
Чтобы остановить службу, мне нужно было бы повторно проверять флаг для события остановки каждый период времени.
Есть ли лучший способ остановить службу в 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", что может занять много времени.
Я хотел бы остановить службу, как только пользователь остановит ее в службах.


person yuval    schedule 23.11.2015    source источник
comment
какой флаг вы проверяете?   -  person user1767754    schedule 23.11.2015
comment
Служба часто содержит цикл, ожидающий чего-то (подключение к сокету, наличие файла и т. Д.) И обработки события. Не зная, как выглядит ваш цикл, трудно дать совет, как его остановить, кроме как проверить событие f ... Stop. Не могли бы вы показать основы вашего сервиса?   -  person Serge Ballesta    schedule 23.11.2015
comment
Я отредактировал свой вопрос   -  person yuval    schedule 23.11.2015


Ответы (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
    ...

Туда:

  • вы тестируете событие без необходимости во вспомогательном потоке
  • вы не обязаны ждать полной обработки, чтобы остановить службу
  • у вас есть чистое место для очистки, если вы остановите службу в середине обработки.
person Serge Ballesta    schedule 23.11.2015
comment
@yuval: я опубликовал неполный ответ до того, как вопрос был закрыт, чтобы я мог отредактировать и восстановить его. - person Serge Ballesta; 23.11.2015

Возможно, лучше использовать 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
person Kirill Dudkin    schedule 23.11.2015
comment
Это не объясняет, почему OP не может остановиться с помощью WINAPI, и не дает никаких советов о том, как корректно закрыть службу, запущенную с помощью NSSM. И вы могли бы хотя бы процитировать этот ответ в указанной публикации. - person Serge Ballesta; 23.11.2015