- Add backend/jobs.py with enqueue_random_number_job function - Modify counter increment endpoint to enqueue job after incrementing - Add mock_enqueue_job fixture to conftest.py for all tests - Add test_increment_enqueues_job_with_user_id to verify correct user_id - Job is enqueued synchronously; failure causes request to fail
64 lines
2 KiB
Python
64 lines
2 KiB
Python
"""Counter routes."""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from auth import require_permission
|
|
from database import get_db
|
|
from jobs import enqueue_random_number_job
|
|
from models import Counter, CounterRecord, Permission, User
|
|
|
|
router = APIRouter(prefix="/api/counter", tags=["counter"])
|
|
|
|
|
|
async def get_or_create_counter(db: AsyncSession) -> Counter:
|
|
"""Get the singleton counter, creating it if it doesn't exist."""
|
|
result = await db.execute(select(Counter).where(Counter.id == 1))
|
|
counter = result.scalar_one_or_none()
|
|
if not counter:
|
|
counter = Counter(id=1, value=0)
|
|
db.add(counter)
|
|
await db.commit()
|
|
await db.refresh(counter)
|
|
return counter
|
|
|
|
|
|
@router.get("")
|
|
async def get_counter(
|
|
db: AsyncSession = Depends(get_db),
|
|
_current_user: User = Depends(require_permission(Permission.VIEW_COUNTER)),
|
|
) -> dict[str, int]:
|
|
"""Get the current counter value."""
|
|
counter = await get_or_create_counter(db)
|
|
return {"value": counter.value}
|
|
|
|
|
|
@router.post("/increment")
|
|
async def increment_counter(
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(require_permission(Permission.INCREMENT_COUNTER)),
|
|
) -> dict[str, int]:
|
|
"""Increment the counter, record the action, and enqueue a random number job."""
|
|
counter = await get_or_create_counter(db)
|
|
value_before = counter.value
|
|
counter.value += 1
|
|
|
|
record = CounterRecord(
|
|
user_id=current_user.id,
|
|
value_before=value_before,
|
|
value_after=counter.value,
|
|
)
|
|
db.add(record)
|
|
|
|
# Enqueue random number job - if this fails, the request fails
|
|
try:
|
|
await enqueue_random_number_job(current_user.id)
|
|
except Exception as e:
|
|
await db.rollback()
|
|
raise HTTPException(
|
|
status_code=500, detail=f"Failed to enqueue job: {e}"
|
|
) from e
|
|
|
|
await db.commit()
|
|
return {"value": counter.value}
|