feat: replace libSQL/Turso with MongoDB Atlas for heartbeat storage#891
Conversation
- Add MongoDB Go driver v2 repository implementations for HeartbeatRepository and HeartbeatMonitorRepository interfaces - Create mongodb.go connection helper with Atlas support and index creation - Update DI container to wire MongoDB as the hedging secondary backend - Replace 'turso' case with 'mongodb' case for standalone MongoDB usage - Update integration test docker-compose to use mongo:7 instead of sqld - Update .env.test with MongoDB connection string HEARTBEAT_DB_BACKEND options: - 'hedging': PostgreSQL primary, MongoDB secondary (fail-open writes) - 'mongodb': MongoDB only - default: PostgreSQL only (GORM) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 45 |
| Duplication | 48 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
- Delete libsql.go, libsql_heartbeat_repository.go, libsql_heartbeat_monitor_repository.go - Remove TursoDB() method and tursoDB field from DI container - Remove unused database/sql import from container - Run go mod tidy to remove libsql-client-go dependency Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Greptile SummaryThis PR replaces the libSQL/Turso secondary backend with MongoDB Atlas for heartbeat storage, adding three new repository files, updating the DI container, and swapping the test environment's
Confidence Score: 3/5The MongoDB repository logic is sound but two present defects — a credential leak in error logs and a broken documentation link — should be fixed before merging. The new connection helper embeds the raw Atlas URI in a Ping error message that flows to the logger and Uptrace. The Vue settings page ships with a misspelled href that will 404 for every user clicking the Documentation button. api/pkg/repositories/mongodb.go (URI in error message) and web/pages/settings/index.vue (broken documentation link)
|
| Filename | Overview |
|---|---|
| api/pkg/repositories/mongodb.go | New MongoDB connection helper — Stable API v1, Ping, and auto-index creation. Connection URI is included verbatim in the Ping error message, risking credential exposure in logs. |
| api/pkg/repositories/mongo_heartbeat_repository.go | New MongoDB HeartbeatRepository — Store, Index, Last, and DeleteAllForUser implemented cleanly, consistent with GORM and libSQL counterparts. |
| api/pkg/repositories/mongo_heartbeat_monitor_repository.go | New MongoDB HeartbeatMonitorRepository — full interface implemented, structurally consistent with GORM and libSQL counterparts. |
| api/pkg/di/container.go | Adds MongoDB() singleton; swaps 'turso' case to 'mongodb' in both repository switch blocks. |
| tests/docker-compose.yml | Replaces sqld with mongo:7; adds proper mongosh healthcheck. |
| tests/.env.test | Replaces TURSO_DATABASE_DSN with MONGODB_URI; test-only credentials. |
| web/pages/settings/index.vue | Adds Documentation button with a typo in the href ('outgiong') that produces a broken link. |
Reviews (1): Last reviewed commit: "feat: replace libSQL/Turso with MongoDB ..." | Re-trigger Greptile
| if err = client.Ping(ctx, nil); err != nil { | ||
| return nil, stacktrace.Propagate(err, fmt.Sprintf("cannot ping MongoDB with URI [%s]", uri)) |
There was a problem hiding this comment.
Connection URI exposed in error logs
The Ping error includes the raw uri parameter. Atlas connection strings embed credentials directly in the URI, so if Ping fails the full string with username and password propagates to container.logger.Fatal and any wired log/error aggregator (Uptrace is already configured in this codebase). Consider omitting the URI from this error message — the caller already knows which env var to check.
There was a problem hiding this comment.
Fixed in cdac79a. Removed the URI from the Ping error message so credentials won't leak to logs or Uptrace. The error now just says \cannot ping MongoDB Atlas\ — the caller knows which env var to check.
| ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||
| defer cancel() | ||
|
|
||
| serverAPI := options.ServerAPI(options.ServerAPIVersion1) | ||
| opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI) | ||
|
|
||
| client, err := mongo.Connect(opts) | ||
| if err != nil { | ||
| return nil, stacktrace.Propagate(err, "cannot connect to MongoDB Atlas") | ||
| } | ||
|
|
||
| if err = client.Ping(ctx, nil); err != nil { | ||
| return nil, stacktrace.Propagate(err, fmt.Sprintf("cannot ping MongoDB with URI [%s]", uri)) | ||
| } | ||
|
|
||
| if err = createMongoIndexes(ctx, client); err != nil { | ||
| return nil, stacktrace.Propagate(err, "cannot create MongoDB indexes") | ||
| } | ||
|
|
||
| return client, nil | ||
| } |
There was a problem hiding this comment.
Shared context budget across Ping and index creation
A single 10-second context is created and then consumed sequentially by client.Ping and createMongoIndexes. On a cold Atlas connection, Ping can take several seconds, leaving less time for createMongoIndexes. If index creation is slow on first startup, the context will expire and startup will fail. Each operation should use its own independently-bounded context.
There was a problem hiding this comment.
Fixed in cdac79a. Separated into independent contexts: \pingCtx\ with 10s timeout and \indexCtx\ with 30s timeout. Each operation now has its own time budget so a slow Ping won't starve index creation.
…ent types - Add bson struct tags to entities.Heartbeat and entities.HeartbeatMonitor - Register custom UUID codec so uuid.UUID is stored as string _id in MongoDB - Remove intermediate heartbeatDocument/heartbeatMonitorDocument structs - MongoDB repositories now marshal/unmarshal entities directly Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove hardcoded mongoDBName constant - Parse appName query parameter from MONGODB_URI as the database name - NewMongoDB now returns (client, dbName, error) - Repository constructors accept dbName parameter - DI container caches and passes the DB name to repositories - Update test .env to include appName=httpsms in URI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- NewMongoDB now returns *mongo.Database instead of (*mongo.Client, dbName) - Repository constructors accept *mongo.Database instead of client + dbName - DI container caches the *mongo.Database singleton directly - Removes MongoDBName() helper - no longer needed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix typo in URL: outgiong -> outgoing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use otelmongo.NewMonitor() as the command monitor on the MongoDB client to automatically trace all database operations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove MongoDB URI from Ping error message to prevent credential exposure in logs and error aggregators - Use separate contexts for Ping (10s) and index creation (30s) so they don't share a timeout budget Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the sqld health check with a MongoDB mongosh ping check since the test infrastructure now uses mongo:7 instead of sqld. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Replace the libSQL/Turso database backend for heartbeat storage with MongoDB Atlas.
Changes
New files:
Modified files:
Configuration
\
HEARTBEAT_DB_BACKEND=hedging # PostgreSQL primary, MongoDB secondary (fail-open writes)
HEARTBEAT_DB_BACKEND=mongodb # MongoDB standalone
HEARTBEAT_DB_BACKEND= # PostgreSQL only (default, GORM)
\\
Requires \MONGODB_URI\ environment variable with the Atlas connection string.
Notes