Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
finally:
if arq_pool is not None:
try:
await arq_pool.close()
await arq_pool.aclose()
except Exception as exc: # noqa: BLE001 — shutdown swallow
logger.warning("arq pool close raised during shutdown", error=str(exc))
# Cancel the capability check if it's still running on shutdown
Expand Down
21 changes: 21 additions & 0 deletions backend/tests/unit/test_main_lifespan.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def _patched_externals(monkeypatch: pytest.MonkeyPatch) -> dict[str, Any]:
import arq.connections

fake_pool = MagicMock()
fake_pool.aclose = AsyncMock(return_value=None)
fake_pool.close = AsyncMock(return_value=None)
monkeypatch.setattr(
arq.connections,
Expand Down Expand Up @@ -167,6 +168,26 @@ async def _fake_warmup(db_factory: Any, redis_client: Any) -> None:
# Warmup is gated off — coroutine NEVER called.
assert len(warmup_invocations) == 0, warmup_invocations

async def test_lifespan_closes_arq_pool_with_aclose(
self,
monkeypatch: pytest.MonkeyPatch,
_patched_externals: dict[str, Any],
) -> None:
"""Regression guard: Arq pool shutdown uses non-deprecated aclose()."""
monkeypatch.setenv("RELYLOOP_DISABLE_STARTUP_WARMUP", "1")

async def _fake_cap_noop(**_kwargs: Any) -> None:
return None

monkeypatch.setattr(app_main, "run_capability_check_background", _fake_cap_noop)

app = FastAPI()
async with app_main.lifespan(app):
await asyncio.sleep(0)

_patched_externals["pool"].aclose.assert_awaited_once()
_patched_externals["pool"].close.assert_not_called()


class TestLifespanShutdownCancels:
async def test_shutdown_cancels_warmup_task_if_running(
Expand Down
22 changes: 22 additions & 0 deletions backend/tests/unit/test_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import os
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock

import pytest

Expand Down Expand Up @@ -111,6 +112,27 @@ def test_worker_settings_has_on_startup_hook(_settings_env: None) -> None:
assert callable(WorkerSettings.on_startup)


async def test_on_shutdown_closes_arq_pool_with_aclose(_settings_env: None) -> None:
"""on_shutdown awaits ArqRedis.aclose() and avoids deprecated close()."""
from backend.workers.all import on_shutdown

fake_pool = MagicMock()
fake_pool.aclose = AsyncMock(return_value=None)
fake_pool.close = AsyncMock(return_value=None)

await on_shutdown({"arq_pool": fake_pool})

fake_pool.aclose.assert_awaited_once()
fake_pool.close.assert_not_called()


async def test_on_shutdown_without_pool_is_noop(_settings_env: None) -> None:
"""A missing Arq pool should not raise during worker shutdown."""
from backend.workers.all import on_shutdown

await on_shutdown({})


def test_worker_settings_redis_host_parsed(_settings_env: None) -> None:
"""RedisSettings.from_dsn should pull host=redis port=6379 db=0 from the URL."""
# Re-import so the class-level redis_settings is rebuilt with our env
Expand Down
2 changes: 1 addition & 1 deletion backend/workers/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ async def on_shutdown(ctx: dict[str, Any]) -> None:

arq_pool: ArqRedis | None = ctx.get("arq_pool")
if arq_pool is not None:
await arq_pool.close()
await arq_pool.aclose()


class WorkerSettings:
Expand Down
Loading