fix: сокеты dev не закрываются при недоступной БД поколений

This commit is contained in:
gglamer 2026-09-26 19:27:52 +00:00
commit 491655de5c
2 changed files with 32 additions and 1 deletions

View file

@ -72,7 +72,13 @@ async def _close_auth_state_unavailable(ws: WebSocket) -> None:
def _close_unverified_sockets() -> None: def _close_unverified_sockets() -> None:
for sockets in list(_active_sockets.values()): # Синтетический `dev` middleware пропускает без сверки поколения — и его
# сокеты не зависят от синхронизации с БД, иначе стенд без базы рвёт
# занятие через две секунды после старта.
synthetic = {"dev"} if get_settings().dev_auth_bypass else set()
for login, sockets in list(_active_sockets.items()):
if login in synthetic:
continue
for ws, loop in list(sockets.items()): for ws, loop in list(sockets.items()):
try: try:
if not loop.is_closed(): if not loop.is_closed():

View file

@ -674,3 +674,28 @@ def test_backup_error_redacts_database_credentials(monkeypatch):
detail = admin._safe_backup_error(admin.backup_service.BackupError(f"bad DSN: {dsn}")) detail = admin._safe_backup_error(admin.backup_service.BackupError(f"bad DSN: {dsn}"))
assert "supersecret" not in detail assert "supersecret" not in detail
assert dsn not in detail assert dsn not in detail
def test_stale_generation_sync_keeps_synthetic_dev_socket():
"""`dev` не хранится в users, и middleware не сверяет его поколение.
Закрывать его сокеты при недоступной БД — значит рвать занятие на
стенде без базы, хотя HTTP того же входа продолжает работать."""
class FakeWebSocket:
closed_with = None
async def close(self, code, reason):
self.closed_with = (code, reason)
async def run():
websocket = FakeWebSocket()
sockets = auth._active_sockets.setdefault("dev", weakref.WeakKeyDictionary())
sockets[websocket] = asyncio.get_running_loop()
try:
auth._close_unverified_sockets()
await asyncio.sleep(0)
await asyncio.sleep(0)
assert websocket.closed_with is None
finally:
sockets.pop(websocket, None)
asyncio.run(run())