"""Persistent server starter: spawns server with proper detachment on Windows. Uses subprocess.Popen with DETACHED_PROCESS + CREATE_NEW_PROCESS_GROUP flags so the child survives parent exit. The child's stdio is redirected to log files. """ import os import sys import subprocess import time import urllib.request WORKDIR = r"D:\opencode\captcha-solver-api" LOG_DIR = r"D:\opencode\logs" PYTHON = r"C:\Users\Administrator\AppData\Local\Programs\Python\Python312\python.exe" PORT = 8765 # Ensure log dir os.makedirs(LOG_DIR, exist_ok=True) log_path = os.path.join(LOG_DIR, "solver.log") err_path = os.path.join(LOG_DIR, "solver.err") # Kill existing subprocess.run( ["taskkill", "/F", "/IM", "python.exe", "/FI", f"WindowTitle eq captcha*"], capture_output=True ) time.sleep(1) # Brute force kill anything on the port out = subprocess.run( ["netstat", "-ano"], capture_output=True, text=True ) for line in out.stdout.splitlines(): if f":{PORT}" in line and "LISTENING" in line: parts = line.split() if parts: try: pid = int(parts[-1]) print(f"killing PID {pid} on port {PORT}") subprocess.run(["taskkill", "/F", "/PID", str(pid)], capture_output=True) except (ValueError, IndexError): pass # Spawn server fully detached log_f = open(log_path, "wb") err_f = open(err_path, "wb") # DETACHED_PROCESS = 0x00000008, CREATE_NEW_PROCESS_GROUP = 0x00000200 flags = 0x00000008 | 0x00000200 proc = subprocess.Popen( [PYTHON, "-u", "-m", "captcha_solver.main", "--port", str(PORT)], cwd=WORKDIR, stdout=log_f, stderr=err_f, stdin=subprocess.DEVNULL, creationflags=flags, close_fds=True, ) print(f"started PID {proc.pid}") # Wait for server to be ready print("waiting for server...") for i in range(60): time.sleep(1) try: with urllib.request.urlopen(f"http://localhost:{PORT}/health", timeout=2) as r: data = r.read().decode("utf-8") print(f"READY after {i+1}s") print(f"health: {data[:200]}") break except Exception: if i % 5 == 4: print(f" still waiting ({i+1}s)...") else: print("TIMEOUT after 60s") print("--- log ---") if os.path.exists(log_path): with open(log_path) as f: print(f.read()[-2000:]) print("--- err ---") if os.path.exists(err_path): with open(err_path) as f: print(f.read()[-2000:]) sys.exit(1)