python - 从 Windows 服务内部设置环境变量
问题描述
我想从窗口服务内部设置一个环境变量。我的第一次尝试是使用 os.environ['flag']='1'。这适用于 cmd shell,但是当我将它放在服务主体中时,它什么也不做。
这是一个简化的代码,它创建了一个只是尝试更改此变量的值的 Windows 服务。它尝试将“1”写入名为 test_flag 的环境变量,休眠 60 秒,然后将其写回“0”。这样做的想法是让服务内部的过程以某种方式开始运行并监视 flag_test 是否在特定时间间隔内返回“0”(某种超时)。如果不是程序挂起,我将需要重新启动服务。我知道这并不漂亮,但我的想法已经用完了(真正的问题是 asyncio 任务挂起而没有抛出任何异常)。
我也尝试使用 win32api.SetEnvironmentVariable ,它也不起作用。
import threading
import win32api
import win32service
import win32serviceutil
import win32event
import os
from time import sleep
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
os.environ['test_flag']='1'
# initializing classes
sleep(60)
os.environ['test_flag']='0'
# 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:
# We are forcefully quitting
pass
except Exception:
pass
# 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)
class envvar_service(win32serviceutil.ServiceFramework):
_svc_name_ = "py_varenv_test"
_svc_display_name_ = "ENVVAR test"
_svc_description_ = "Service test use of os.environ"
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)
self.worker = WorkerThread(self.hWaitDone)
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 = 600000 # 60 seconds / 1 minute
self.worker = WorkerThread(self.hWaitDone)
self.worker.start()
self.worker.setDaemon=True
while True:
# Wait for service stop signal
rc = win32event.WaitForMultipleObjects([self.hWaitStop, self.hWaitDone],False,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
self.worker = WorkerThread(self.hWaitDone)
self.worker.setDaemon=True
self.worker.start()
def ctrlHandler(ctrlType):
return True
if __name__ == '__main__':
win32api.SetConsoleCtrlHandler(ctrlHandler, True)
win32serviceutil.HandleCommandLine(envvar_service)
解决方案
我认为您无法从服务中更改环境,因为这是另一个过程。您应该使用一些进程间通信来告诉主进程设置环境。
我认为最简单的方法是使用multiprocessing.Queue
.
您创建一个队列并将队列作为参数提供给服务。
服务将数据放入队列 ( queue.put(data)
)
主进程中的一个线程从队列 ( data = queue.read()
) 中读取并相应地设置环境变量。
如果您想等待正在设置的变量,您可以使用 multiprocessing.Event
请参阅多处理和 threading.Thread 文档。
https://docs.python.org/3/library/multiprocessing.html https://docs.python.org/3/library/threading.html
您必须使用多处理模块中的事件和队列类,而不是线程模块!
推荐阅读
- postgresql - 如何通过保持某些列值相同并更新其他列值来更新多行?
- reactjs - 在反应项目中在哪里导入可动手做的 css 文件
- html - 如何将文本和图像换行在同一行 - Wordpress
- angular - 如何创建我的 Angular 应用程序的副本(使用 firebase)
- javascript - TypeScript 找不到命名空间
- charts - 如何在 Google 条形图中绘制具有特定值的附加水平网格线(不是平均值)
- javascript - 为什么 React material-ui modal 不能正确打开?
- javascript - 当我搜索 Giphy API 时,搜索字段变为空
- oracle - 18c 与 19c 上的 Oracle 编号问题
- json - 如何在 Angular 8 中运行循环并读取 URL?