我有一个使用python创建的简单的Windows服务。我的问题是,我不知道服务需要多长时间才能完成,它可能需要15秒,或者可能需要4个多小时,具体取决于需要对数据执行的操作。 4个多小时是一个罕见的情况,但我遇到过这种情况。
以下是我一直关注的Windows服务的一般模式。我拿出了所有逻辑,但这不是问题,只留下了一个虚拟记录命令。有没有办法阻止服务继续或不刷新,直到逻辑部分完成而不是使用超时?
import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import os
import sys
import time
import logging
class aservice(win32serviceutil.ServiceFramework):
_svc_name_ = "WeatherService"
_svc_display_name_ = "Weather Service"
_svc_description_ = "Downloads weather data from NOAA and creates maps"
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):
import servicemanager
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
self.timeout = 640000 #640 seconds / 10 minutes (value is in milliseconds)
#self.timeout = 120000 #120 seconds / 2 minutes
# This is how long the service will wait to run / refresh itself (see script below)
while 1:
# Wait for service stop signal, if I timeout, loop again
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
# Stop signal encountered
servicemanager.LogInfoMsg(self._svc_name_ + " - STOPPED!") #For Event Log
break
else:
#[actual service code between rests]
try:
logging.basicConfig(filename=r"c:\temp\example.log",level=logging.DEBUG,
format='%(asctime)s %(message)s')
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
#file_path = "C:\whereever\my_REAL_py_work_to_be_done.py"
#execfile(file_path) #Execute the script
#inc_file_path2 = "C:\whereever\MORE_REAL_py_work_to_be_done.py"
#execfile(inc_file_path2) #Execute the script
except:
pass
#[actual service code between rests]
def ctrlHandler(ctrlType):
return True
if __name__ == '__main__':
win32api.SetConsoleCtrlHandler(ctrlHandler, True)
win32serviceutil.HandleCommandLine(aservice)
答案 0 :(得分:0)
您可以启动一个新流程来执行长时间运行的事情。如果停止信号到达,则会终止子进程。
答案 1 :(得分:0)
将服务用作具有多个线程的控制器。 一个线程(Main)应该同步和排队命令,并使用win32 serviceframework进行通信,注册到系统等。 另一个线程(Worker)应该等待队列中的命令并执行它们。如果您将任意代码作为单独的进程执行,那么您可以从工作线程中生成那些代码,并在完成并清理后简单地回读结果。
这样,当一个停止到达时,你的主线程会将它注册到队列中的worker,它会唤醒并尝试发出其他进程的信号以退出,稍等一下并清理或强制终止它们
<强>更新强>
下面是一个示例概念,说明如何使服务始终响应并在必要时运行。每个工人都可以抛出
...
import threading
...
class InterruptedException(Exception):
pass
class WorkerThread(threading.Thread):
def __init__(self, controller):
self._controller = controller
self._stop = threading.Event()
super(WorkerThread, self).__init__()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def run(self):
try:
# Insert the code you want to run as a service here
# rather than do "execfile(.../.../blah)" simply do:
# You can have your code throw InterruptedException if your code needs to exit
# Also check often if self.stopped and then cleanly exit
import your_file
your_file.main()
# if code in another module is not yours or cannot check often if it should stop then use multiprocessing which will spawn separate processes that you can terminate then from here when you need to stop and return
# in that case simply block here on self._stop.wait()
except InterruptedException as exc:
# We are forcefully quitting
pass
except Exception as e:
# Oh oh, did not anticipate this, better report to Windows or log it
finally:
# Close/release any connections, handles, files etc.
# OK, we can stop now
win32event.SetEvent(self._controller)
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.hWaitDone = win32event.CreateEvent(None, 0, 0, None)
def SvcDoRun(self):
import servicemanager
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
worker = WorkerThread(self.hWaitDone)
worker.start()
while True:
# Wait for service stop signal
rc = win32event.WaitForMultipleObjects([self.hWaitStop, self.hWaitDone], win32event.INFINITE)
# Check to see if self.hWaitStop happened as part of Windows Service Management
if rc == 0:
# Stop signal encountered
servicemanager.LogInfoMsg(self._svc_name_ + " - STOPPED!") #For Event Log
break
if rc == 1:
# Wait until worker has fully finished
worker.join()
# Determine from worker state if we need to start again (because run finished)
# Or do whatever
if not worker.need_to_start_again():
break
worker.start()
答案 2 :(得分:0)
我最终使用了这种模式:http://code.activestate.com/recipes/551780/
效果很好,但不像魅力。我确实遇到了多处理问题,但这个过程并没有产生实例。关于那个的建议?
请继续发布您的答案,我希望看到每个人的解决方案,因为win32api可能难以使用。
谢谢大家