perf: isolate authentication database work (#311)
All checks were successful
CI / lint (pull_request) Successful in 31s
CI / build-frontend (pull_request) Successful in 4s

This commit is contained in:
timmy 2026-08-08 14:56:45 +00:00
parent 9189d13db9
commit d026bbd400
2 changed files with 170 additions and 5 deletions

View File

@ -586,7 +586,7 @@ async def sign_in(payload: DashboardSignIn, request: Request, response: Response
)
attempts = _login_attempt_store()
try:
retry_after = attempts.retry_after(source)
retry_after = await asyncio.to_thread(attempts.retry_after, source)
except LoginAttemptStoreError:
return JSONResponse(
{"detail": "Sign-in throttling is temporarily unavailable"},
@ -607,7 +607,7 @@ async def sign_in(payload: DashboardSignIn, request: Request, response: Response
payload.access_token, configured_token
):
try:
attempts.record_failure(source)
await asyncio.to_thread(attempts.record_failure, source)
except LoginAttemptStoreError:
return JSONResponse(
{"detail": "Sign-in throttling is temporarily unavailable"},
@ -616,7 +616,7 @@ async def sign_in(payload: DashboardSignIn, request: Request, response: Response
)
raise HTTPException(status_code=401, detail="Invalid access token")
try:
attempts.clear(source)
await asyncio.to_thread(attempts.clear, source)
except LoginAttemptStoreError:
return JSONResponse(
{"detail": "Sign-in throttling is temporarily unavailable"},
@ -624,7 +624,7 @@ async def sign_in(payload: DashboardSignIn, request: Request, response: Response
headers={"Cache-Control": "no-store"},
)
try:
signed, session = dashboard_auth.issue_session()
signed, session = await asyncio.to_thread(dashboard_auth.issue_session)
except dashboard_auth.SessionStoreError:
return JSONResponse(
{"detail": "Session registry is temporarily unavailable"},
@ -668,7 +668,7 @@ async def session_status(request: Request):
async def sign_out(request: Request, response: Response):
session = request.state.dashboard_session
try:
dashboard_auth.revoke_session(session)
await asyncio.to_thread(dashboard_auth.revoke_session, session)
except dashboard_auth.SessionStoreError:
return JSONResponse(
{"detail": "Session registry is temporarily unavailable"},

View File

@ -430,6 +430,171 @@ async def test_session_registry_latency_does_not_block_the_event_loop(access_con
assert heartbeat_elapsed < 0.08
@pytest.mark.anyio
async def test_sign_in_throttle_lookup_does_not_block_the_event_loop(
access_control, monkeypatch
):
class SlowAttempts:
def retry_after(self, source):
time.sleep(0.15)
return 17
monkeypatch.setattr(main, "_login_attempt_store", lambda: SlowAttempts())
transport = httpx.ASGITransport(app=main.app, client=("203.0.113.10", 1234))
async with httpx.AsyncClient(transport=transport, base_url="https://test") as client:
sign_in = asyncio.create_task(
client.post("/api/v1/session", json={"access_token": "wrong"})
)
await asyncio.sleep(0)
started = time.perf_counter()
await asyncio.sleep(0.01)
heartbeat_elapsed = time.perf_counter() - started
response = await sign_in
assert response.status_code == 429
assert response.headers["retry-after"] == "17"
assert heartbeat_elapsed < 0.08
@pytest.mark.anyio
async def test_failed_sign_in_recording_does_not_block_the_event_loop(
access_control, monkeypatch
):
class SlowAttempts:
def retry_after(self, source):
time.sleep(0.02)
return 0
def record_failure(self, source):
time.sleep(0.15)
monkeypatch.setattr(main, "_login_attempt_store", lambda: SlowAttempts())
transport = httpx.ASGITransport(app=main.app, client=("203.0.113.11", 1234))
async with httpx.AsyncClient(transport=transport, base_url="https://test") as client:
sign_in = asyncio.create_task(
client.post("/api/v1/session", json={"access_token": "wrong"})
)
await asyncio.sleep(0)
started = time.perf_counter()
await asyncio.sleep(0.04)
heartbeat_elapsed = time.perf_counter() - started
response = await sign_in
assert response.status_code == 401
assert heartbeat_elapsed < 0.08
@pytest.mark.anyio
async def test_successful_sign_in_throttle_clear_does_not_block_the_event_loop(
access_control, monkeypatch
):
class SlowAttempts:
def retry_after(self, source):
time.sleep(0.02)
return 0
def clear(self, source):
time.sleep(0.15)
monkeypatch.setattr(main, "_login_attempt_store", lambda: SlowAttempts())
transport = httpx.ASGITransport(app=main.app, client=("203.0.113.12", 1234))
async with httpx.AsyncClient(transport=transport, base_url="https://test") as client:
sign_in = asyncio.create_task(
client.post(
"/api/v1/session",
json={"access_token": "correct horse battery staple"},
)
)
await asyncio.sleep(0)
started = time.perf_counter()
await asyncio.sleep(0.04)
heartbeat_elapsed = time.perf_counter() - started
response = await sign_in
assert response.status_code == 200
assert heartbeat_elapsed < 0.08
@pytest.mark.anyio
async def test_session_activation_does_not_block_the_event_loop(
access_control, monkeypatch
):
class Attempts:
def retry_after(self, source):
time.sleep(0.02)
return 0
def clear(self, source):
return None
class SlowStore:
def activate(self, session_id, expires_at):
time.sleep(0.15)
monkeypatch.setattr(main, "_login_attempt_store", lambda: Attempts())
monkeypatch.setattr(main.dashboard_auth, "_session_store", lambda now=None: SlowStore())
transport = httpx.ASGITransport(app=main.app, client=("203.0.113.13", 1234))
async with httpx.AsyncClient(transport=transport, base_url="https://test") as client:
sign_in = asyncio.create_task(
client.post(
"/api/v1/session",
json={"access_token": "correct horse battery staple"},
)
)
await asyncio.sleep(0)
started = time.perf_counter()
await asyncio.sleep(0.04)
heartbeat_elapsed = time.perf_counter() - started
response = await sign_in
assert response.status_code == 200
assert any(
"stackchain_session=" in value
for value in response.headers.get_list("set-cookie")
)
assert heartbeat_elapsed < 0.08
@pytest.mark.anyio
async def test_single_session_revocation_does_not_block_the_event_loop(
access_control, monkeypatch
):
transport = httpx.ASGITransport(app=main.app)
async with httpx.AsyncClient(transport=transport, base_url="https://test") as client:
await client.post(
"/api/v1/session",
json={"access_token": "correct horse battery staple"},
)
csrf = client.cookies["stackchain_csrf"]
class SlowStore:
def is_active(self, session_id, expires_at):
time.sleep(0.02)
return True
def revoke(self, session_id):
time.sleep(0.15)
monkeypatch.setattr(
main.dashboard_auth, "_session_store", lambda now=None: SlowStore()
)
sign_out = asyncio.create_task(
client.delete(
"/api/v1/session",
headers={"Origin": "https://test", "X-CSRF-Token": csrf},
)
)
await asyncio.sleep(0)
started = time.perf_counter()
await asyncio.sleep(0.04)
heartbeat_elapsed = time.perf_counter() - started
response = await sign_out
assert response.status_code == 200
assert response.json()["authenticated"] is False
assert heartbeat_elapsed < 0.08
@pytest.mark.anyio
async def test_session_registry_read_failure_fails_closed_before_gitea(
access_control, monkeypatch