perf: cache public activity aggregates
This commit is contained in:
+13
-2
@@ -26,6 +26,7 @@ from .importer import ImportAlreadyRunning, ImportSourceError, import_records, n
|
||||
from .logging_config import configure_logging
|
||||
from .models import Bait, BaitKind, CatchReport, CommunityImportRun, DataSource, ExternalObservation, Fish, ModerationEvent, ModerationStatus, OfficialRecordImport, SourceType, Spot, SubmissionAttempt, Waterbody
|
||||
from .readiness import readiness_report
|
||||
from .public_cache import public_cache
|
||||
from .schemas import ActivityOut, AdminCatchReportOut, BaitOut, CatchOut, CatchReportAccepted, CatchReportCreate, CatchReportCreated, ExternalObservationDecision, ExternalObservationMapping, ExternalObservationOut, ExternalObservationPublished, FishOut, ImportRunOut, ModerationUpdate, OfficialRecordOut, PublicObservationOut, SourceStatusOut, SpotOut, WaterbodyOut
|
||||
from .storage import ScreenshotError, client as storage_client, delete_screenshot, signed_screenshot_url, upload_screenshot
|
||||
|
||||
@@ -110,7 +111,7 @@ def baits(db: Db, limit: int = Query(200, ge=1, le=500), offset: int = Query(0,
|
||||
|
||||
@app.get("/api/v1/activity", response_model=list[ActivityOut])
|
||||
def activity(
|
||||
db: Db, hours: int = Query(24),
|
||||
db: Db, response: Response, hours: int = Query(24),
|
||||
waterbody: str | None = None, fish: str | None = None,
|
||||
method: str | None = None,
|
||||
sort: Literal["activity", "confidence", "freshness"] = "activity",
|
||||
@@ -118,6 +119,12 @@ def activity(
|
||||
) -> list[ActivityOut]:
|
||||
if hours not in {6, 12, 24, 72}:
|
||||
raise HTTPException(status_code=422, detail="hours must be one of: 6, 12, 24, 72")
|
||||
response.headers["Cache-Control"] = f"public, max-age={settings.public_cache_seconds}"
|
||||
cache_key = ("activity", hours, waterbody, fish, method, sort, limit, offset)
|
||||
cached = public_cache.get(cache_key, settings.public_cache_seconds)
|
||||
if cached is not None:
|
||||
response.headers["X-Cache"] = "HIT"
|
||||
return cached
|
||||
rows = activity_rows(db, hours=hours, waterbody=waterbody, fish=fish, method=method)
|
||||
keys = {
|
||||
"activity": lambda r: (r.activity_score, r.confidence_score, r.last_confirmed_at, str(r.spot_id)),
|
||||
@@ -125,7 +132,8 @@ def activity(
|
||||
"freshness": lambda r: (r.last_confirmed_at, r.activity_score, r.confidence_score, str(r.spot_id)),
|
||||
}
|
||||
rows.sort(key=keys[sort], reverse=True)
|
||||
return rows[offset:offset + limit]
|
||||
response.headers["X-Cache"] = "MISS"
|
||||
return public_cache.set(cache_key, rows[offset:offset + limit])
|
||||
|
||||
|
||||
def _spot_or_404(db: Session, spot_id: UUID) -> Spot:
|
||||
@@ -372,6 +380,7 @@ def admin_publish_external_observation(
|
||||
report = publish_observation(db, observation)
|
||||
except ExternalReviewError as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
public_cache.invalidate()
|
||||
return ExternalObservationPublished(observation_id=observation.id, catch_report_id=report.id, status=observation.status)
|
||||
|
||||
|
||||
@@ -454,6 +463,7 @@ def moderate_report(report_id: UUID, payload: ModerationUpdate, db: Db, moderato
|
||||
report.moderation_status = ModerationStatus(payload.status)
|
||||
db.add(ModerationEvent(catch_report=report, created_at=datetime.now(timezone.utc), previous_status=previous, new_status=report.moderation_status, moderator=moderator, reason=payload.reason))
|
||||
db.commit()
|
||||
public_cache.invalidate()
|
||||
return CatchReportCreated(id=report.id, moderation_status=report.moderation_status.value)
|
||||
|
||||
|
||||
@@ -476,6 +486,7 @@ def delete_report(report_id: UUID, db: Db, moderator: Annotated[str, Depends(_ad
|
||||
report.raw_payload = None
|
||||
db.add(ModerationEvent(catch_report=report, created_at=report.deleted_at, previous_status=previous, new_status=ModerationStatus.rejected, moderator=moderator, reason="user report deleted and anonymized"))
|
||||
db.commit()
|
||||
public_cache.invalidate()
|
||||
return Response(status_code=204)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user