rex/windows_service.py
Rama master · réplica de lectura del repositorio original.
"""Windows service wrapper for Rex lean nodes (pywin32 required)."""
from __future__ import annotations
import os
import subprocess
import sys
from typing import TYPE_CHECKING, Any
from rex.windows_service_paths import normalize_existing_executable
if sys.platform != "win32":
raise ImportError(
"rex.windows_service is only supported on Windows. "
"pywin32 is required: pip install pywin32"
)
try:
import servicemanager # noqa: E402
import win32event # noqa: E402
import win32service # noqa: E402
import win32serviceutil # noqa: E402
_PYWIN32_SERVICE_AVAILABLE = True
except ImportError: # pragma: no cover - pywin32 service components optional
servicemanager = None # optional Windows-only dependency
win32event = None # optional Windows-only dependency
win32service = None # optional Windows-only dependency
win32serviceutil = None # optional Windows-only dependency
_PYWIN32_SERVICE_AVAILABLE = False
DEFAULT_SERVICES = "event_bus,workflow_runner,memory_store,credential_manager"
DEFAULT_PORT = "8765"
_ServiceBase: Any
if TYPE_CHECKING:
import win32serviceutil as _win32serviceutil_t
_ServiceBase = _win32serviceutil_t.ServiceFramework
else:
_ServiceBase = win32serviceutil.ServiceFramework if _PYWIN32_SERVICE_AVAILABLE else object
class RexNodeService(_ServiceBase):
_svc_name_ = "RexLeanNode"
_svc_display_name_ = "Rex Lean Node"
_svc_description_ = "Rex AI Assistant lean node service."
def __init__(self, args):
super().__init__(args)
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
self.process: subprocess.Popen[bytes] | None = None
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.stop_event)
if self.process:
self.process.terminate()
def SvcDoRun(self):
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ""),
)
services = os.environ.get("REX_SERVICES", DEFAULT_SERVICES)
port = os.environ.get("REX_SERVICE_PORT", DEFAULT_PORT)
service_python = normalize_existing_executable(sys.executable)
cmd = [
str(service_python),
"-m",
"rex.app",
"--services",
services,
"--port",
port,
]
self.process = subprocess.Popen(cmd)
win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
def main() -> None:
if not _PYWIN32_SERVICE_AVAILABLE: # pragma: no cover
raise ImportError(
"pywin32 service components are required to run Rex as a Windows service. "
"Install via: pip install pywin32"
)
win32serviceutil.HandleCommandLine(RexNodeService)
if __name__ == "__main__":
main()