Merge pull request #718 from christianlouis/perf-upload-15584535240168516797

 Optimize file upload endpoint to use asynchronous aiofiles
This commit is contained in:
Christian Krakau-Louis
2026-03-16 10:55:57 +01:00
committed by GitHub
3 changed files with 6 additions and 4 deletions
+4 -3
View File
@@ -11,6 +11,7 @@ import zipfile
from datetime import datetime, timezone
from typing import Annotated, List, Optional
import aiofiles
from fastapi import APIRouter, Depends, File, HTTPException, Query, Request, UploadFile, status
from fastapi.responses import StreamingResponse
from sqlalchemy import asc, desc
@@ -1277,7 +1278,7 @@ async def ui_upload(request: Request, db: DbSession, file: UploadFile = File(...
# enforcing the size limit during the read so memory usage stays bounded.
try:
written_size = 0
with open(target_path, "wb") as f:
async with aiofiles.open(target_path, "wb") as f:
chunk_size = 65536 # 64 KB chunks
while True:
chunk = await file.read(chunk_size)
@@ -1286,14 +1287,14 @@ async def ui_upload(request: Request, db: DbSession, file: UploadFile = File(...
written_size += len(chunk)
if written_size > max_size:
# Exceeded limit mid-stream; clean up and reject
f.close()
await f.close()
os.remove(target_path)
raise HTTPException(
status_code=413,
detail=f"File too large: exceeded {max_size} bytes during upload. "
f"See SECURITY_AUDIT.md for configuration details.",
)
f.write(chunk)
await f.write(chunk)
except HTTPException:
raise
except Exception as e:
+1
View File
@@ -58,3 +58,4 @@ sentry-sdk[fastapi,celery,sqlalchemy]>=2.20.0,<3.0.0
# GraphQL API
strawberry-graphql[fastapi]>=0.243.0,<1.0.0
aiofiles>=24.1.0 # Asynchronous file I/O support
+1 -1
View File
@@ -345,7 +345,7 @@ class TestUploadErrorHandling:
def test_upload_disk_write_failure(self, client: TestClient):
"""Test handling of disk write failures."""
with patch("builtins.open", side_effect=IOError("Disk full")):
with patch("aiofiles.open", side_effect=IOError("Disk full")):
pdf_content = b"%PDF-1.4\n%EOF"
response = client.post(