使用 Python 创建 Windows 服务
如何使用 Python 创建 Windows 服务
引言
本文介绍如何使用 Python 创建 Windows 服务。
背景
由于业务需求,我需要将数据从 SQLServer 传输到 MongoDB,并且需要每天执行。因此,我需要将其制作成 Windows 服务。
Using the Code
这段代码用于将我用 Python 编写的逻辑打包成 Windows 服务。
代码如下
import pythoncom
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import time
import DataTransToMongo
import sys
class DataTransToMongoService(win32serviceutil.ServiceFramework):
_svc_name_ = 'DataTransToMongoService'
_svc_display_name_ = 'DataTransToMongoService'
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
self.isAlive = True
def SvcStop(self):
self.isAlive = False
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
self.isAlive = True
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ''))
self.main()
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
def main(self):
#i = 0
while self.isAlive:
DataTransToMongo.run() //This is where my logic exists
time.sleep(86400)
#pass
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(DataTransToMongoService)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(DataTransToMongoService)
当然,我们不希望在生产服务器上安装 Python 环境。因此,我需要将其制作成可执行文件,即 Windows 上的 EXE 文件。问题在于我使用的 Python 版本是 3.5,所以著名的工具 pywin32 对我来说不可用。(正如评论中提到的,pywin32 现在可用了,我很久以前写的,抱歉没有检查。) 经过搜索,最终我找到了--pyinstaller
。
下载并安装它。然后在 cmd 中运行以下代码
pyinstaller --onefile --hidden-import win32timezone DataTransToMongoService.py
还有很多其他参数,我们可以在 http://www.pyinstaller.org/ 获取帮助。
关于 --hidden-import
,现在它有一个别名叫做 --hiddenimport
。
当我运行 pyinstaller --onefile DataTransToMongoService.py
时,我收到一个错误,显示ImportError: No module named win32timezone.
然后我添加了那个选项。但是现在,pyinstaller 已经解决了这个问题。我不再需要 --hiddenimport 了。
2016/08/09
昨晚我研究了代码,发现有一些可以优化的地方。
服务无法正常关闭。所以我编写了一个测试示例,并且运行良好。
示例代码如下
import pythoncom import win32serviceutil import win32service import win32event import servicemanager import socket import time import DataTransToMongo import sys class TestService(win32serviceutil.ServiceFramework): _svc_name_ = 'TestService' _svc_display_name_ = 'TestService' def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) socket.setdefaulttimeout(60) 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_, '')) self.main() def main(self): f = open('D:\\test.txt', 'a') rc = None while rc != win32event.WAIT_OBJECT_0: f.write('Test Service \n') f.flush() #block for 24*60*60 seconds and wait for a stop event #it is used for a one-day loop rc = win32event.WaitForSingleObject(self.hWaitStop, 24*60*60*1000) f.write('shut down \n') f.close() if __name__ == '__main__': if len(sys.argv) == 1: servicemanager.Initialize() servicemanager.PrepareToHostSingle(TestService) servicemanager.StartServiceCtrlDispatcher() else: win32serviceutil.HandleCommandLine(TestService)
历史
- 2016 年 8 月 1 日:初始版本
- 2016 年 8 月 9 日:修复无法关闭的错误。( unclosable => 无法关闭 ^^)