fix(quota): prune quota history past a retention window
quota_events had no retention: one row per API spend plus a zero-unit row per live search, kept forever. The daily history cleanup (audit_gc) now also prunes it past quota_retention_days (a new Quota setting, default 365 so the admin usage view's longest window stays whole; 0 = forever). The floor of two days keeps today's rows, which the per-user search cap counts.
This commit is contained in:
+18
-2
@@ -7,11 +7,13 @@ always be allowed; expensive backfill must yield to the remaining budget.
|
||||
|
||||
import contextlib
|
||||
import contextvars
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Any, cast
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy import delete, func, select
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from sqlalchemy.engine import CursorResult
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import sysconfig
|
||||
@@ -96,6 +98,20 @@ def pacific_today():
|
||||
return datetime.now(_PACIFIC).date()
|
||||
|
||||
|
||||
def gc(db: Session, retention_days: int) -> int:
|
||||
"""Delete quota-history rows older than `retention_days` (<= 0 keeps them forever) and return how
|
||||
many went. Flushes only; the cleanup job commits. Today's rows are never in reach: the per-user
|
||||
search cap counts them, and the floor of two days outlasts any Pacific day (25 h at most)."""
|
||||
if retention_days <= 0:
|
||||
return 0
|
||||
cutoff = datetime.now(timezone.utc) - timedelta(days=max(2, retention_days))
|
||||
# A DELETE answers with a CursorResult; `execute` is typed as the general Result, without rowcount.
|
||||
result = cast(
|
||||
CursorResult[Any], db.execute(delete(QuotaEvent).where(QuotaEvent.created_at < cutoff))
|
||||
)
|
||||
return result.rowcount or 0
|
||||
|
||||
|
||||
def pacific_day_start_utc() -> datetime:
|
||||
"""UTC instant of the current Pacific day's midnight — aligns 'today' with the budget reset."""
|
||||
start = datetime.now(_PACIFIC).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
Reference in New Issue
Block a user