จะหยุดบริการที่สร้างใน 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... หยุดเหตุการณ์ คุณช่วยแสดงพื้นฐานของบริการของคุณได้ไหม?   -  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