Skip to content

Commit a8b7aec

Browse files
author
maebahesioru
committed
fix: retry Camoufox launch up to 3 times on WebSocket endpoint timeout
If Camoufox fails to output WebSocket endpoint within timeout, kill the process and retry up to 3 times with 3s delay between attempts.
1 parent 53e31a3 commit a8b7aec

1 file changed

Lines changed: 56 additions & 45 deletions

File tree

src/launch_camoufox.py

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -719,55 +719,66 @@ def determine_proxy_configuration(internal_camoufox_proxy_arg=None):
719719
camoufox_popen_kwargs['creationflags'] = subprocess.CREATE_NO_WINDOW
720720
try:
721721
logger.info(f" 将执行 Camoufox 内部启动命令: {' '.join(camoufox_internal_cmd_args)}")
722-
camoufox_proc = subprocess.Popen(camoufox_internal_cmd_args, **camoufox_popen_kwargs)
723-
logger.info(f' Camoufox 内部进程已启动 (PID: {camoufox_proc.pid})。正在等待 WebSocket 端点输出 (最长 {ENDPOINT_CAPTURE_TIMEOUT} 秒)...')
724-
camoufox_output_q = queue.Queue()
725-
camoufox_stdout_reader = threading.Thread(target=_enqueue_output, args=(camoufox_proc.stdout, 'stdout', camoufox_output_q, camoufox_proc.pid), daemon=True)
726-
camoufox_stderr_reader = threading.Thread(target=_enqueue_output, args=(camoufox_proc.stderr, 'stderr', camoufox_output_q, camoufox_proc.pid), daemon=True)
727-
camoufox_stdout_reader.start()
728-
camoufox_stderr_reader.start()
729-
ws_capture_start_time = time.time()
730-
camoufox_ended_streams_count = 0
731-
while time.time() - ws_capture_start_time < ENDPOINT_CAPTURE_TIMEOUT:
732-
if camoufox_proc.poll() is not None:
733-
logger.error(f' Camoufox 内部进程 (PID: {camoufox_proc.pid}) 在等待 WebSocket 端点期间已意外退出,退出码: {camoufox_proc.poll()}。')
734-
break
735-
try:
736-
stream_name, line_from_camoufox = camoufox_output_q.get(timeout=0.2)
737-
if line_from_camoufox is None:
738-
camoufox_ended_streams_count += 1
739-
logger.debug(f' [InternalCamoufox-{stream_name}-PID:{camoufox_proc.pid}] 输出流已关闭 (EOF)。')
740-
if camoufox_ended_streams_count >= 2:
741-
logger.info(f' Camoufox 内部进程 (PID: {camoufox_proc.pid}) 的所有输出流均已关闭。')
722+
MAX_CAMOUFOX_RETRIES = 3
723+
for camoufox_attempt in range(MAX_CAMOUFOX_RETRIES):
724+
if camoufox_attempt > 0:
725+
logger.warning(f' 🔄 重试启动 Camoufox (第 {camoufox_attempt + 1}/{MAX_CAMOUFOX_RETRIES} 次)...')
726+
camoufox_proc = subprocess.Popen(camoufox_internal_cmd_args, **camoufox_popen_kwargs)
727+
logger.info(f' Camoufox 内部进程已启动 (PID: {camoufox_proc.pid})。正在等待 WebSocket 端点输出 (最长 {ENDPOINT_CAPTURE_TIMEOUT} 秒)...')
728+
camoufox_output_q = queue.Queue()
729+
camoufox_stdout_reader = threading.Thread(target=_enqueue_output, args=(camoufox_proc.stdout, 'stdout', camoufox_output_q, camoufox_proc.pid), daemon=True)
730+
camoufox_stderr_reader = threading.Thread(target=_enqueue_output, args=(camoufox_proc.stderr, 'stderr', camoufox_output_q, camoufox_proc.pid), daemon=True)
731+
camoufox_stdout_reader.start()
732+
camoufox_stderr_reader.start()
733+
ws_capture_start_time = time.time()
734+
camoufox_ended_streams_count = 0
735+
while time.time() - ws_capture_start_time < ENDPOINT_CAPTURE_TIMEOUT:
736+
if camoufox_proc.poll() is not None:
737+
logger.error(f' Camoufox 内部进程 (PID: {camoufox_proc.pid}) 在等待 WebSocket 端点期间已意外退出,退出码: {camoufox_proc.poll()}。')
738+
break
739+
try:
740+
stream_name, line_from_camoufox = camoufox_output_q.get(timeout=0.2)
741+
if line_from_camoufox is None:
742+
camoufox_ended_streams_count += 1
743+
logger.debug(f' [InternalCamoufox-{stream_name}-PID:{camoufox_proc.pid}] 输出流已关闭 (EOF)。')
744+
if camoufox_ended_streams_count >= 2:
745+
logger.info(f' Camoufox 内部进程 (PID: {camoufox_proc.pid}) 的所有输出流均已关闭。')
746+
break
747+
continue
748+
log_line_content = f'[InternalCamoufox-{stream_name}-PID:{camoufox_proc.pid}]: {line_from_camoufox.rstrip()}'
749+
if stream_name == 'stderr' or 'ERROR' in line_from_camoufox.upper() or '❌' in line_from_camoufox:
750+
logger.warning(log_line_content)
751+
else:
752+
logger.info(log_line_content)
753+
ws_match = ws_regex.search(line_from_camoufox)
754+
if ws_match:
755+
captured_ws_endpoint = ws_match.group(1)
756+
logger.info(f' ✅ 成功从 Camoufox 内部进程捕获到 WebSocket 端点: {captured_ws_endpoint[:40]}...')
742757
break
758+
except queue.Empty:
743759
continue
744-
log_line_content = f'[InternalCamoufox-{stream_name}-PID:{camoufox_proc.pid}]: {line_from_camoufox.rstrip()}'
745-
if stream_name == 'stderr' or 'ERROR' in line_from_camoufox.upper() or '❌' in line_from_camoufox:
746-
logger.warning(log_line_content)
747-
else:
748-
logger.info(log_line_content)
749-
ws_match = ws_regex.search(line_from_camoufox)
750-
if ws_match:
751-
captured_ws_endpoint = ws_match.group(1)
752-
logger.info(f' ✅ 成功从 Camoufox 内部进程捕获到 WebSocket 端点: {captured_ws_endpoint[:40]}...')
753-
break
754-
except queue.Empty:
755-
continue
756-
if camoufox_stdout_reader.is_alive():
757-
camoufox_stdout_reader.join(timeout=1.0)
758-
if camoufox_stderr_reader.is_alive():
759-
camoufox_stderr_reader.join(timeout=1.0)
760-
if not captured_ws_endpoint and (camoufox_proc and camoufox_proc.poll() is None):
761-
logger.error(f' ❌ 未能在 {ENDPOINT_CAPTURE_TIMEOUT} 秒内从 Camoufox 内部进程 (PID: {camoufox_proc.pid}) 捕获到 WebSocket 端点。')
762-
logger.error(' Camoufox 内部进程仍在运行,但未输出预期的 WebSocket 端点。请检查其日志或行为。')
760+
if camoufox_stdout_reader.is_alive():
761+
camoufox_stdout_reader.join(timeout=1.0)
762+
if camoufox_stderr_reader.is_alive():
763+
camoufox_stderr_reader.join(timeout=1.0)
764+
if captured_ws_endpoint:
765+
break
766+
# Failed - kill process and retry
767+
if camoufox_proc and camoufox_proc.poll() is None:
768+
logger.warning(f' ❌ 未能在 {ENDPOINT_CAPTURE_TIMEOUT} 秒内捕获到 WebSocket 端点,终止进程 (PID: {camoufox_proc.pid})...')
769+
camoufox_proc.terminate()
770+
try:
771+
camoufox_proc.wait(timeout=5)
772+
except subprocess.TimeoutExpired:
773+
camoufox_proc.kill()
774+
else:
775+
logger.warning(f' ❌ Camoufox 内部进程已退出,未能捕获到 WebSocket 端点。')
776+
if camoufox_attempt < MAX_CAMOUFOX_RETRIES - 1:
777+
time.sleep(3)
778+
if not captured_ws_endpoint:
779+
logger.error(f' ❌ Camoufox 在 {MAX_CAMOUFOX_RETRIES} 次尝试后均未能输出 WebSocket 端点。')
763780
cleanup()
764781
sys.exit(1)
765-
elif not captured_ws_endpoint and (camoufox_proc and camoufox_proc.poll() is not None):
766-
logger.error(f' ❌ Camoufox 内部进程已退出,且未能捕获到 WebSocket 端点。')
767-
sys.exit(1)
768-
elif not captured_ws_endpoint:
769-
logger.error(f' ❌ 未能捕获到 WebSocket 端点。')
770-
sys.exit(1)
771782
except Exception as e_launch_camoufox_internal:
772783
logger.critical(f' ❌ 在内部启动 Camoufox 或捕获其 WebSocket 端点时发生致命错误: {e_launch_camoufox_internal}', exc_info=True)
773784
cleanup()

0 commit comments

Comments
 (0)