upstream: Optional[aiohttp.ClientWebSocketResponse] = None session: Optional[ClientSession] = None try: # Небольшая задержка — Proxmox API иногда возвращает внутреннюю # ошибку "name '_client' is not defined" при слишком быстрых # последовательных запросах (race в API). 1 секунды обычно хватает. if auth_kind == "cookie": await asyncio.sleep(1.0) session = ClientSession() # Пробуем WebSocket-handshake с retry на случай race condition в Proxmox API. last_exc: Optional[Exception] = None for attempt in range(1, 4): try: resp = await session.get( upstream_url, headers=headers, allow_redirects=False, ssl=False if not settings.pve_verify_ssl else None, ) logger.info( "console_ws: attempt=%s initial GET status=%s, location=%s, body=%s", attempt, resp.status, resp.headers.get("Location", ""), (await resp.text())[:200], ) if resp.status in (301, 302, 303, 307, 308): location = resp.headers.get("Location", "") upstream_url = _rewrite_redirect(location, fallback_host) logger.info("console_ws: rewritten URL to %s", upstream_url) await resp.release() break elif resp.status == 101: await resp.release() break elif resp.status == 502 and "name '_client' is not defined" in (await resp.text()): # Известная внутренняя ошибка Proxmox — подождём и повторим. await resp.release() logger.warning( "console_ws: Proxmox вернул race condition 502, " "попытка %s/3 через 2с", attempt, ) if attempt < 3: await asyncio.sleep(2.0) continue else: body = await resp.text() await resp.release() raise aiohttp.ClientResponseError( request_info=resp.request_info, history=resp.history, status=resp.status, message=body[:120], headers=resp.headers, ) except Exception as exc: last_exc = exc logger.warning("console_ws: attempt %s ошибка: %s", attempt, exc) if attempt < 3: await asyncio.sleep(2.0) continue else: # Все попытки исчерпаны. raise last_exc or RuntimeError("не удалось открыть WebSocket к Proxmox") upstream = await session.ws_connect( upstream_url, headers=headers, ssl=False if not settings.pve_verify_ssl else None, autoclose=False, autoping=True, max_msg_size=8 * 1024 * 1024, ) logger.info("console_ws: upstream connected")