From b290cffb989996c1cf8ffde444cad6130fef8249 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 09:36:33 +0000 Subject: [PATCH] Performance Optimization: Replace synchronous file upload read with async aiofiles Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> --- app/api/files.py | 7 ++++--- requirements.txt | 1 + tests/test_file_upload.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/api/files.py b/app/api/files.py index 2277e2e9..06435c9e 100644 --- a/app/api/files.py +++ b/app/api/files.py @@ -1,3 +1,4 @@ +import aiofiles """ File-related API endpoints """ @@ -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: diff --git a/requirements.txt b/requirements.txt index 3448ae0a..f65c9262 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/tests/test_file_upload.py b/tests/test_file_upload.py index 70826466..02cae836 100644 --- a/tests/test_file_upload.py +++ b/tests/test_file_upload.py @@ -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(