diff --git a/backend/app/tg/login_flow.py b/backend/app/tg/login_flow.py index e9fef7c..d709389 100644 --- a/backend/app/tg/login_flow.py +++ b/backend/app/tg/login_flow.py @@ -271,16 +271,23 @@ async def _cancel_code(db, login_id: str, row) -> None: """Попытка auth.cancelCode у Telegram (только если есть RAM-клиент и - phone_code_hash); любая ошибка не мешает локальной очистке.""" + phone_code_hash); любая ошибка не мешает локальной очистке. + + Таймаут 5 с обязателен: коннект, на котором не дошёл код, может быть + «полумёртвый» — без таймаута DELETE/отмена зависнет на мёртвом соединении + (кнопка «Отменить логин» выглядит как никогда не работающая).""" client = _manager().pending_client(login_id) if client is None or not (row["phone"] and row["phone_code_hash"]): return try: - await client(functions.auth.CancelCodeRequest( - phone=row["phone"], phone_code_hash=row["phone_code_hash"], - )) - except Exception as exc: # noqa: BLE001 — код уже истёк/сессия потеряна - print(f"[login] cancel_code({login_id}) failed: {type(exc).__name__}", flush=True) + await asyncio.wait_for( + client(functions.auth.CancelCodeRequest( + phone=row["phone"], phone_code_hash=row["phone_code_hash"], + )), + timeout=5, + ) + except (Exception, asyncio.TimeoutError) as exc: # noqa: BLE001 + print(f"[login] cancel_code({login_id}): {type(exc).__name__} — чистим локально", flush=True) # --- QR-вход (Login via QR, обходит лимиты send_code_request/PHONE_CODE_FLOOD) --- @@ -373,8 +380,8 @@ except (asyncio.TimeoutError, TimeoutError): # токен умер — сгенерировать новый и ждать дальше try: - await qr.recreate() - except Exception as exc: # noqa: BLE001 + await asyncio.wait_for(qr.recreate(), timeout=10) + except (Exception, asyncio.TimeoutError) as exc: # noqa: BLE001 print(f"[login] qr recreate({login_id}): {type(exc).__name__}", flush=True) return except errors.SessionPasswordNeededError: