fix(storage): #106.5 — serve_blob probes S3 sub-backend, not dual disk-OR-S3 exists
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 6s
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 6s
באג-אינטראקציה שהתגלה לפני ה-flip ל-dual: DualBackend.exists() מחזיר True אם הקובץ על **הדיסק או** ב-S3. serve_blob בדק backend.exists() ואז הנפיק presigned — כך שתחת dual, קובץ שקיים-רק-בדיסק (mirror שנכשל / מחוץ לסט-ההגירה) היה מקבל redirect ל-presigned-URL שמחזיר 404 מ-MinIO, במקום fallback-לדיסק. תיקון: serve_blob בודק קיום ב-**S3 ספציפית** — `s3 = getattr(backend, "s3", backend)` (DualBackend.s3, או ה-S3Backend עצמו תחת s3) — כך שקובץ disk-only נופל ל-FileResponse אמיתי. תואם-לאחור ל-filesystem/s3 (getattr מחזיר את ה-backend עצמו). invariants: INV-STG6 (presigned רק כשהאובייקט באמת ב-S3) · INV-G10 (אפס שינוי תחת filesystem). tests: 6 (2 חדשות — dual מ-S3-sub-backend present→redirect / absent→disk-fallback). py_compile OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
13
web/app.py
13
web/app.py
@@ -2789,14 +2789,21 @@ async def serve_blob(
|
||||
from pathlib import Path as _Path
|
||||
backend = storage.get_storage()
|
||||
if backend.name != "filesystem":
|
||||
# Presign ONLY when the object is actually in S3. Under ``dual`` the
|
||||
# generic ``exists`` is disk-OR-S3, so a disk-only file (failed mirror /
|
||||
# outside the migration set) would otherwise be redirected to a presigned
|
||||
# URL that 404s on MinIO. Probe the S3 sub-backend specifically
|
||||
# (DualBackend.s3 — or the S3 backend itself under ``s3``) so disk-only
|
||||
# files fall back to a real disk read.
|
||||
s3 = getattr(backend, "s3", backend)
|
||||
try:
|
||||
key = storage.normalize_key(path)
|
||||
if await backend.exists(key, bucket=bucket):
|
||||
url = await backend.presign_get(key, bucket=bucket, download_name=filename)
|
||||
if await s3.exists(key, bucket=bucket):
|
||||
url = await s3.presign_get(key, bucket=bucket, download_name=filename)
|
||||
return RedirectResponse(url, status_code=302)
|
||||
except Exception: # noqa: BLE001 — never 500 on a key/presign hiccup; fall back to disk
|
||||
logger.exception("serve_blob: presign failed for %s; falling back to disk", path)
|
||||
# not in object storage (dual fallback) — serve the disk copy if present
|
||||
# not in object storage (dual disk-fallback) — serve the disk copy if present
|
||||
if not _Path(path).exists():
|
||||
raise HTTPException(404, "קובץ לא נמצא")
|
||||
return FileResponse(path, media_type=media_type, filename=filename)
|
||||
|
||||
Reference in New Issue
Block a user