Skip to content

Use transactions to coordinate updates to FrontierCollection, WordsCollection#4189

Draft
imnasnainaec wants to merge 3 commits intomasterfrom
mongo-transactions
Draft

Use transactions to coordinate updates to FrontierCollection, WordsCollection#4189
imnasnainaec wants to merge 3 commits intomasterfrom
mongo-transactions

Conversation

@imnasnainaec
Copy link
Collaborator

@imnasnainaec imnasnainaec commented Mar 3, 2026

Goals:

  • Add transactions to MongoDbContext (enabled by Convert MongoDB from standalone to replica set #4184)
  • MergeService, WordService: move the core of methods that involve multiple database updates into new methods in the WordRepository
    • Update interfaces and tests
  • WordRepository: Use a transaction around every coordinated change to both _words and _frontier

This change is Reviewable

Summary by CodeRabbit

  • Tests

    • Added mock implementations for database context and transaction testing.
  • Refactor

    • Enhanced transaction support for database operations, improving data consistency and atomicity for word repository operations.
    • Streamlined service logic by consolidating multi-step operations into single atomic transactions.

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

This PR refactors MongoDB transaction handling by introducing an explicit transaction abstraction (IMongoTransaction), updating the MongoDbContext to use session-based transactions, and modifying WordRepository to execute multi-collection operations atomically. New combined frontier operations (CreateAndDeleteFrontier, AddAndDeleteFrontier) are introduced to the repository layer, and WordService is simplified to use these atomic operations.

Changes

Cohort / File(s) Summary
Transaction Interfaces
Backend/Interfaces/IMongoDbContext.cs
New file-scoped namespace with IMongoDbContext interface (adds BeginTransaction method) and IMongoTransaction interface (Session property, CommitTransactionAsync, AbortTransactionAsync). Shifts from single context interface to separate transaction abstraction.
MongoDbContext Implementation
Backend/Contexts/MongoDbContext.cs
Adds Db property, constructor initialization from options, refactors BeginTransaction to use session-based transactions via StartSessionAsync, introduces private MongoTransactionWrapper nested class for session delegation, and updates Dispose logic.
Test Mocks
Backend.Tests/Mocks/MongoDbContextMock.cs, Backend.Tests/Mocks/WordRepositoryMock.cs
New MongoDbContextMock with IMongoDbContext implementation and private MongoTransactionMock. WordRepositoryMock adds CreateAndDeleteFrontier and AddAndDeleteFrontier methods for atomic frontier operations in tests.
Repository Interface & Implementation
Backend/Interfaces/IWordRepository.cs, Backend/Repositories/WordRepository.cs
IWordRepository adds two new methods: CreateAndDeleteFrontier and AddAndDeleteFrontier. WordRepository implements transactional patterns for Create (single and bulk), DeleteAllWords, and new frontier operations; introduces _dbContext field for explicit transaction usage.
Service Layer
Backend/Services/WordService.cs
DeleteFrontierWord and Update methods refactored to use new atomic repository operations (AddAndDeleteFrontier, CreateAndDeleteFrontier), removing intermediate DeleteFrontier calls. Eliminates private Add helper method.
Startup
Backend/Startup.cs
IUserRepository retrieval now uses a created async scope instead of direct root service access, disposing the scope after use.

Sequence Diagram

sequenceDiagram
    actor Client
    participant WordService as WordService
    participant WordRepository as WordRepository
    participant MongoDbContext as MongoDbContext
    participant MongoDB as MongoDB<br/>(Session/Transaction)

    Client->>WordService: Update(userId, word)
    WordService->>WordRepository: CreateAndDeleteFrontier(newWord, oldWordId)
    
    WordRepository->>MongoDbContext: BeginTransaction()
    MongoDbContext->>MongoDB: StartSessionAsync()
    MongoDB-->>MongoDbContext: IClientSessionHandle
    MongoDbContext->>MongoDB: Start Transaction
    MongoDB-->>MongoDbContext: IMongoTransaction
    MongoDbContext-->>WordRepository: IMongoTransaction
    
    WordRepository->>MongoDB: InsertOne(WordsCollection, newWord, session)
    MongoDB-->>WordRepository: Success
    WordRepository->>MongoDB: InsertOne(Frontier, newWord, session)
    MongoDB-->>WordRepository: Success
    WordRepository->>MongoDB: DeleteOne(Frontier, oldWord, session)
    MongoDB-->>WordRepository: Success
    
    WordRepository->>MongoDbContext: CommitTransactionAsync()
    MongoDbContext->>MongoDB: Commit Transaction
    MongoDB-->>MongoDbContext: Success
    MongoDbContext-->>WordRepository: Task Complete
    
    WordRepository-->>WordService: Word (committed)
    WordService-->>Client: Updated Word
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

🟥High

Suggested reviewers

  • jasonleenaylor

Poem

🐰 A rabbit hops with glee, through sessions fine and free,
Transactions now do gleam so bright, no partial updates in sight!
Atomic bounds embrace the way, frontier words can dance and sway,
Commit or abort! the session cries, as data truth before us flies. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately summarizes the main objective of the PR: introducing transactions to coordinate updates across FrontierCollection and WordsCollection in MongoDB.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mongo-transactions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@imnasnainaec

This comment was marked as resolved.

Copy link
Contributor

Copilot AI commented Mar 3, 2026

@imnasnainaec I've opened a new pull request, #4190, to work on those changes. Once the pull request is ready, I'll request review from you.

@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 10.00000% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.09%. Comparing base (0ce9ad4) to head (8cd0c28).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
Backend/Contexts/MongoDbContext.cs 0.00% 18 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master    #4189       +/-   ##
===========================================
+ Coverage   75.15%   86.09%   +10.94%     
===========================================
  Files         302       57      -245     
  Lines       11099     4862     -6237     
  Branches     1394      603      -791     
===========================================
- Hits         8341     4186     -4155     
+ Misses       2357      534     -1823     
+ Partials      401      142      -259     
Flag Coverage Δ
backend 86.09% <10.00%> (-0.43%) ⬇️
frontend ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@imnasnainaec
Copy link
Collaborator Author

@copilot Open a pull request onto this branch that resolves the final goal of this pr:

WordRepository: Use a transaction around every coordinated change to both _words and _frontier

Copy link
Contributor

Copilot AI commented Mar 4, 2026

@imnasnainaec I've opened a new pull request, #4191, to work on those changes. Once the pull request is ready, I'll request review from you.

@github-actions
Copy link

github-actions bot commented Mar 4, 2026

⚠️ Commit Message Format Issues ⚠️
commit 8cd0c28a26:
1: T1 Title exceeds max length (78>72): "Add MongoDB transactions to WordRepository multi-collection operations (#4191)"

@imnasnainaec imnasnainaec marked this pull request as ready for review March 4, 2026 19:23
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
Backend/Contexts/MongoDbContext.cs (1)

25-45: Consider implementing IAsyncDisposable for cleaner async cleanup.

The MongoTransactionWrapper uses synchronous Dispose() to clean up the session. Since all transaction operations are async, consider also implementing IAsyncDisposable to allow callers to use await using for more idiomatic async resource management.

♻️ Optional: Add IAsyncDisposable support
-    private class MongoTransactionWrapper(IClientSessionHandle session) : IMongoTransaction
+    private class MongoTransactionWrapper(IClientSessionHandle session) : IMongoTransaction, IAsyncDisposable
     {
         private readonly IClientSessionHandle _session = session;

         public IClientSessionHandle Session => _session;

         public Task CommitTransactionAsync()
         {
             return _session.CommitTransactionAsync();
         }

         public Task AbortTransactionAsync()
         {
             return _session.AbortTransactionAsync();
         }

         public void Dispose()
         {
             _session.Dispose();
         }
+
+        public ValueTask DisposeAsync()
+        {
+            _session.Dispose();
+            return ValueTask.CompletedTask;
+        }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend/Contexts/MongoDbContext.cs` around lines 25 - 45, The
MongoTransactionWrapper currently only implements Dispose() synchronously;
update the class declaration for MongoTransactionWrapper to also implement
IAsyncDisposable and add a DisposeAsync method that calls and awaits
_session.DisposeAsync() (returning a ValueTask), keeping the existing Dispose()
for backward compatibility (it can call
DisposeAsync().AsTask().GetAwaiter().GetResult() or simply call
_session.Dispose()); ensure signatures and references to Session,
CommitTransactionAsync, and AbortTransactionAsync remain unchanged so callers
can use await using with MongoTransactionWrapper.
Backend.Tests/Mocks/MongoDbContextMock.cs (1)

16-33: Consider the implications of Session returning null!.

The Session property returns null!, which could cause NullReferenceException if any test code attempts to use the session directly. Since the WordRepositoryMock doesn't use the session (it operates on in-memory collections), this works for current tests. However, if future tests need to verify session-based behavior, this mock would need enhancement.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Backend.Tests/Mocks/MongoDbContextMock.cs` around lines 16 - 33, The
MongoTransactionMock's Session property currently returns null! which risks
NullReferenceException in tests that access the session; update
MongoTransactionMock to return a minimal non-null IClientSessionHandle
implementation instead (e.g., add an inner sealed class MockClientSessionHandle
implementing IClientSessionHandle with no-op/throwing members as appropriate)
and have the Session property return an instance of that mock; this preserves
current behavior for in-memory tests while allowing future tests to inspect or
interact with the session via the new MockClientSessionHandle, and keep the
class name MongoTransactionMock and the Session property as the wiring point.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Backend.Tests/Mocks/MongoDbContextMock.cs`:
- Around line 16-33: The MongoTransactionMock's Session property currently
returns null! which risks NullReferenceException in tests that access the
session; update MongoTransactionMock to return a minimal non-null
IClientSessionHandle implementation instead (e.g., add an inner sealed class
MockClientSessionHandle implementing IClientSessionHandle with no-op/throwing
members as appropriate) and have the Session property return an instance of that
mock; this preserves current behavior for in-memory tests while allowing future
tests to inspect or interact with the session via the new
MockClientSessionHandle, and keep the class name MongoTransactionMock and the
Session property as the wiring point.

In `@Backend/Contexts/MongoDbContext.cs`:
- Around line 25-45: The MongoTransactionWrapper currently only implements
Dispose() synchronously; update the class declaration for
MongoTransactionWrapper to also implement IAsyncDisposable and add a
DisposeAsync method that calls and awaits _session.DisposeAsync() (returning a
ValueTask), keeping the existing Dispose() for backward compatibility (it can
call DisposeAsync().AsTask().GetAwaiter().GetResult() or simply call
_session.Dispose()); ensure signatures and references to Session,
CommitTransactionAsync, and AbortTransactionAsync remain unchanged so callers
can use await using with MongoTransactionWrapper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d608bccf-62e1-4a1a-a466-19db284a3a64

📥 Commits

Reviewing files that changed from the base of the PR and between 0ce9ad4 and 8cd0c28.

📒 Files selected for processing (8)
  • Backend.Tests/Mocks/MongoDbContextMock.cs
  • Backend.Tests/Mocks/WordRepositoryMock.cs
  • Backend/Contexts/MongoDbContext.cs
  • Backend/Interfaces/IMongoDbContext.cs
  • Backend/Interfaces/IWordRepository.cs
  • Backend/Repositories/WordRepository.cs
  • Backend/Services/WordService.cs
  • Backend/Startup.cs

@imnasnainaec imnasnainaec marked this pull request as draft March 5, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants