Addon起動の環境問題

This commit is contained in:
Keisuke Hirata 2026-02-12 21:49:22 +09:00
parent a2131a962b
commit f2665a49dd

View File

@ -24,6 +24,8 @@ class InferenceClient:
def __init__(self): def __init__(self):
self.server_process: Optional[subprocess.Popen] = None self.server_process: Optional[subprocess.Popen] = None
self._server_lock = threading.Lock() self._server_lock = threading.Lock()
self.log_file = None
self.log_file_path = None
def start_server(self): def start_server(self):
"""Start the inference server process.""" """Start the inference server process."""
@ -52,28 +54,54 @@ class InferenceClient:
server_env[key] = value server_env[key] = value
print(f"[FaceMask] Loaded environment from: {env_file}") print(f"[FaceMask] Loaded environment from: {env_file}")
# Ensure PYTHONPATH includes project root # Clean PYTHONPATH to avoid conflicts with Nix Python packages
pythonpath = server_env.get('PYTHONPATH', '') # Only include project root to allow local imports
if pythonpath:
server_env['PYTHONPATH'] = f"{root_dir}:{pythonpath}"
else:
server_env['PYTHONPATH'] = root_dir server_env['PYTHONPATH'] = root_dir
# Remove Python-related environment variables that might cause conflicts
# These can cause venv to import packages from Nix instead of venv
env_vars_to_remove = [
'PYTHONUNBUFFERED',
'__PYVENV_LAUNCHER__', # macOS venv variable
'VIRTUAL_ENV', # Will be set by venv's Python automatically
]
for var in env_vars_to_remove:
server_env.pop(var, None)
# If there's a venv in the project, add it to PATH # If there's a venv in the project, add it to PATH
venv_bin = os.path.join(root_dir, ".venv", "bin") venv_bin = os.path.join(root_dir, ".venv", "bin")
if os.path.isdir(venv_bin): if os.path.isdir(venv_bin):
# Build a clean PATH with venv first, then essential system paths
# Filter out any Nix Python-specific paths to avoid version conflicts
current_path = server_env.get('PATH', '') current_path = server_env.get('PATH', '')
server_env['PATH'] = f"{venv_bin}:{current_path}" path_entries = current_path.split(':')
# Filter out Nix Python 3.11 paths
filtered_paths = [
p for p in path_entries
if not ('/python3.11/' in p.lower() or '/python3-3.11' in p.lower())
]
# Reconstruct PATH with venv first
clean_path = ':'.join([venv_bin] + filtered_paths)
server_env['PATH'] = clean_path
print(f"[FaceMask] Using venv from: {venv_bin}") print(f"[FaceMask] Using venv from: {venv_bin}")
# Prepare log file for server output
import tempfile
log_dir = tempfile.gettempdir()
self.log_file_path = os.path.join(log_dir, "facemask_server.log")
self.log_file = open(self.log_file_path, 'w', buffering=1) # Line buffered
print(f"[FaceMask] Server log: {self.log_file_path}")
# Start process with 'python' command (will use venv if PATH is set correctly) # Start process with 'python' command (will use venv if PATH is set correctly)
self.server_process = subprocess.Popen( self.server_process = subprocess.Popen(
["python", server_script], ["python", "-u", server_script], # -u for unbuffered output
cwd=root_dir, cwd=root_dir,
text=True, text=True,
env=server_env, env=server_env,
stdout=subprocess.PIPE, # Capture stdout stdout=self.log_file, # Write to log file
stderr=subprocess.PIPE, # Capture stderr stderr=subprocess.STDOUT, # Merge stderr into stdout
preexec_fn=os.setsid, # Create new process group preexec_fn=os.setsid, # Create new process group
) )
@ -85,22 +113,23 @@ class InferenceClient:
# Check if process died # Check if process died
if self.server_process.poll() is not None: if self.server_process.poll() is not None:
# Capture and display error output # Read error output from log file
try:
stdout, stderr = self.server_process.communicate(timeout=1)
except subprocess.TimeoutExpired:
stdout, stderr = "", ""
error_msg = f"Server failed to start (exit code: {self.server_process.returncode})" error_msg = f"Server failed to start (exit code: {self.server_process.returncode})"
print(f"[FaceMask] ERROR: {error_msg}") print(f"[FaceMask] ERROR: {error_msg}")
if stdout and stdout.strip(): try:
print("[FaceMask] Server stdout:") if self.log_file:
print(stdout.strip()) self.log_file.close()
with open(self.log_file_path, 'r') as f:
if stderr and stderr.strip(): log_content = f.read()
print("[FaceMask] Server stderr:") if log_content.strip():
print(stderr.strip()) print("[FaceMask] Server log:")
# Show last 50 lines
lines = log_content.strip().split('\n')
for line in lines[-50:]:
print(line)
except Exception as e:
print(f"[FaceMask] Could not read log file: {e}")
self.server_process = None self.server_process = None
raise RuntimeError(error_msg) raise RuntimeError(error_msg)
@ -108,19 +137,21 @@ class InferenceClient:
time.sleep(0.5) time.sleep(0.5)
# If we get here, startup timed out # If we get here, startup timed out
# Try to capture any partial output print("[FaceMask] Server startup timed out")
if self.server_process:
# Try to read partial log
try: try:
# Non-blocking read with short timeout if self.log_file:
stdout, stderr = self.server_process.communicate(timeout=0.1) self.log_file.close()
if stdout and stdout.strip(): with open(self.log_file_path, 'r') as f:
print("[FaceMask] Server stdout (partial):") log_content = f.read()
print(stdout.strip()) if log_content.strip():
if stderr and stderr.strip(): print("[FaceMask] Server log (partial):")
print("[FaceMask] Server stderr (partial):") lines = log_content.strip().split('\n')
print(stderr.strip()) for line in lines[-30:]:
except subprocess.TimeoutExpired: print(line)
pass # Process still running but not responding except Exception:
pass
raise RuntimeError("Server startup timed out") raise RuntimeError("Server startup timed out")
@ -137,6 +168,14 @@ class InferenceClient:
finally: finally:
self.server_process = None self.server_process = None
# Close log file
if self.log_file:
try:
self.log_file.close()
except Exception:
pass
self.log_file = None
def is_server_running(self) -> bool: def is_server_running(self) -> bool:
"""Check if server is responding.""" """Check if server is responding."""
try: try: