make caching opt-in
This commit is contained in:
40
app/main.py
40
app/main.py
@@ -43,7 +43,9 @@ class ActivityResult:
|
||||
app = FastAPI(title=os.getenv("SERVICE_TITLE", "git-activity-merge"))
|
||||
|
||||
|
||||
def get_cache(settings: Settings = Depends(get_settings)) -> FileCache:
|
||||
def get_cache(settings: Settings = Depends(get_settings)) -> FileCache | None:
|
||||
if settings.cache_dir is None or settings.cache_ttl_seconds is None:
|
||||
return None
|
||||
return FileCache(cache_dir=settings.cache_dir, default_ttl_seconds=settings.cache_ttl_seconds)
|
||||
|
||||
|
||||
@@ -88,10 +90,14 @@ def _date_keys(from_date: date, to_date: date) -> list[str]:
|
||||
|
||||
|
||||
async def _fetch_with_cache(
|
||||
cache: FileCache,
|
||||
cache: FileCache | None,
|
||||
key: str,
|
||||
fetcher,
|
||||
) -> tuple[dict[str, int], bool]:
|
||||
if cache is None:
|
||||
fresh = await fetcher()
|
||||
return fresh, False
|
||||
|
||||
cached = cache.get_json(key, allow_stale=True)
|
||||
if cached and not cached.stale:
|
||||
return {k: int(v) for k, v in cached.value.items()}, False
|
||||
@@ -109,7 +115,7 @@ async def _fetch_with_cache(
|
||||
|
||||
async def collect_merged_activity(
|
||||
settings: Settings,
|
||||
cache: FileCache,
|
||||
cache: FileCache | None,
|
||||
options: QueryOptions,
|
||||
) -> ActivityResult:
|
||||
from_date, to_date, days_count = compute_date_range(options)
|
||||
@@ -178,7 +184,7 @@ async def health(settings: Settings = Depends(get_settings)) -> dict[str, str]:
|
||||
@app.get("/activity.json")
|
||||
async def activity_json(
|
||||
settings: Settings = Depends(get_settings),
|
||||
cache: FileCache = Depends(get_cache),
|
||||
cache: FileCache | None = Depends(get_cache),
|
||||
options: QueryOptions = Depends(get_query_options),
|
||||
) -> JSONResponse:
|
||||
try:
|
||||
@@ -203,7 +209,7 @@ async def activity_json(
|
||||
@app.get("/activity.svg")
|
||||
async def activity_svg(
|
||||
settings: Settings = Depends(get_settings),
|
||||
cache: FileCache = Depends(get_cache),
|
||||
cache: FileCache | None = Depends(get_cache),
|
||||
options: QueryOptions = Depends(get_query_options),
|
||||
) -> Response:
|
||||
try:
|
||||
@@ -213,9 +219,10 @@ async def activity_svg(
|
||||
raise HTTPException(status_code=502, detail="Failed to fetch activity data") from exc
|
||||
|
||||
cache_key = _image_cache_key("svg", options, result)
|
||||
cached = cache.get_json(cache_key)
|
||||
if cached is not None:
|
||||
return Response(content=str(cached.value), media_type="image/svg+xml")
|
||||
if cache is not None:
|
||||
cached = cache.get_json(cache_key)
|
||||
if cached is not None:
|
||||
return Response(content=str(cached.value), media_type="image/svg+xml")
|
||||
|
||||
daily_totals = _daily_totals(result.merged)
|
||||
total = sum(daily_totals.values())
|
||||
@@ -227,14 +234,15 @@ async def activity_svg(
|
||||
total_contributions=total,
|
||||
theme=options.theme,
|
||||
)
|
||||
cache.set_json(cache_key, svg)
|
||||
if cache is not None:
|
||||
cache.set_json(cache_key, svg)
|
||||
return Response(content=svg, media_type="image/svg+xml")
|
||||
|
||||
|
||||
@app.get("/activity.png")
|
||||
async def activity_png(
|
||||
settings: Settings = Depends(get_settings),
|
||||
cache: FileCache = Depends(get_cache),
|
||||
cache: FileCache | None = Depends(get_cache),
|
||||
options: QueryOptions = Depends(get_query_options),
|
||||
) -> Response:
|
||||
try:
|
||||
@@ -244,10 +252,11 @@ async def activity_png(
|
||||
raise HTTPException(status_code=502, detail="Failed to fetch activity data") from exc
|
||||
|
||||
cache_key = _image_cache_key("png", options, result)
|
||||
cached = cache.get_json(cache_key)
|
||||
if cached is not None:
|
||||
png_data = bytes.fromhex(str(cached.value))
|
||||
return Response(content=png_data, media_type="image/png")
|
||||
if cache is not None:
|
||||
cached = cache.get_json(cache_key)
|
||||
if cached is not None:
|
||||
png_data = bytes.fromhex(str(cached.value))
|
||||
return Response(content=png_data, media_type="image/png")
|
||||
|
||||
daily_totals = _daily_totals(result.merged)
|
||||
total = sum(daily_totals.values())
|
||||
@@ -264,5 +273,6 @@ async def activity_png(
|
||||
except Exception as exc:
|
||||
logger.exception("failed to render png")
|
||||
raise HTTPException(status_code=500, detail="PNG rendering failed") from exc
|
||||
cache.set_json(cache_key, png_data.hex())
|
||||
if cache is not None:
|
||||
cache.set_json(cache_key, png_data.hex())
|
||||
return Response(content=png_data, media_type="image/png")
|
||||
|
||||
Reference in New Issue
Block a user