3 - feat: PyMongo Async Migration - #141
Open
deepansh96 wants to merge 18 commits into
Open
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Normalize all test file imports to use canonical top-level style (from database import ..., from routers import ...) instead of package-relative imports (from ..database import ...). Add a pre-commit hook that fails if banned mixed-root import pairs (e.g. from ..main / from app.main) reappear. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ation, pyobjectid Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pydantic_v2_compat, fixture paths Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migration is implemented — move plan to archive alongside other completed plans. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
suryabulusu
reviewed
Apr 20, 2026
| @@ -1 +1,2 @@ | |||
| MONGO_AUTH_CREDENTIALS="mongodb://127.0.0.1:27017" | |||
| MONGO_DB_NAME="quiz_test" | |||
Collaborator
There was a problem hiding this comment.
for local it can be 'quiz' only na
Collaborator
There was a problem hiding this comment.
Example: after ./startServerMac.sh --freshSync --source ..., Mongo restores data into quiz, while the backend now reads
from quiz_test, so quiz-frontend will look empty even though the sync succeeded. I’d
keep .env.example on quiz for local runtime and reserve quiz_test for the test
harness / CI only.
Collaborator
There was a problem hiding this comment.
- use MONGO_DB_NAME instead of hardcoded quiz in the mongosh drop
Collaborator
There was a problem hiding this comment.
- make mongorestore restore into the configured DB, not implicitly into quiz
…alph/pymongo-async-migration # Conflicts: # .env.example # .github/workflows/ci.yml # README.md # app/routers/quizzes.py # app/settings.py # app/tests/base.py # app/tests/test_pydantic_v2_compat.py # app/tests/test_session_answers.py # docs/ENV.md # terraform/prod/ecs.tf # terraform/testing/ecs.tf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
This PR makes our MongoDB calls non-blocking. Right now, every database call (like fetching a quiz or saving a session answer) freezes the FastAPI worker until MongoDB responds. With this change, the worker can handle other requests while waiting for the database, which means better performance under load.
What changed and why
1. New database setup (
app/database.py)Before: The app created a MongoDB connection the moment
database.pywas imported, and every file grabbed that connection directly.After: The connection is created only when the app starts up, managed through three simple functions:
init_db()— creates the connection on startupget_quiz_db()— gives you the database handle whenever you need itclose_db()— cleanly shuts down the connection on app exitThis also means importing
database.pyno longer has side effects, which makes testing much more predictable.2. App factory (
app/main.py)Before: The FastAPI app was created at import time as a global variable.
After: A
create_app()function builds the app. It uses FastAPI'slifespanto start and stop the database connection automatically. On startup, it pings MongoDB to make sure the connection works — if it can't reach the database, the app fails immediately instead of silently serving errors.3. All routers updated (6 files, 38 DB calls)
Every database call across all router files now uses
await. The patterns are straightforward:collection.find_one(...)→await collection.find_one(...)list(collection.find(...))→await collection.find(...).to_list(length=None)list(collection.aggregate(...))→cursor = await collection.aggregate(...); await cursor.to_list(length=None)4. MongoDB settings (
app/settings.py)A new
MongoSettingsclass keeps all Mongo config (MONGO_DB_NAME,MONGO_AUTH_CREDENTIALS, pool sizes) separate from the general app settings. It reads environment variables only when needed, never at import time — this prevents test configuration from being ignored.5. Test harness rewrite (
app/tests/base.py)Before: Tests shared the app's database connection and used hardcoded paths to find test data files.
After:
self.db) for setup and assertionsquiz_test(neverquiz) with a safety guard that refuses to touch production data6. Backfill script decoupled
backfill_time_limits_and_spent.pyused to share the app's database connection. Now it creates its own, so it keeps working independently of the async migration.7. Import cleanup
All test files now use consistent top-level imports (
from database import ...) instead of a mix of relative imports (from ..database import ...). A pre-commit hook prevents the old style from coming back.8. Infrastructure
MONGO_DB_NAMEto ECS containers, so the database name is explicit instead of being buried in the connection URIMONGO_DB_NAME=quiz_testset explicitlypymongo==4.16.0— versions before 4.15.1 have a timeout bug that hits our exact stack (AsyncMongoClient + uvicorn + FastAPI)9. Documentation
docs/pymongo-async-staging-smoke.mdwith a manual smoke test checklist for deployments.env.exampleincludes the newMONGO_DB_NAMEvariableTest plan
pytest)pre-commit run --all-files)terraform plansucceeds for testing and prod🤖 Generated with Claude Code