Skip to content

fix(MongoDb): Treat an already initiated replica set as success - #1731

Open
arnelirobles wants to merge 1 commit into
testcontainers:developfrom
arnelirobles:bugfix/1722-replica-set-reinitiate
Open

fix(MongoDb): Treat an already initiated replica set as success#1731
arnelirobles wants to merge 1 commit into
testcontainers:developfrom
arnelirobles:bugfix/1722-replica-set-reinitiate

Conversation

@arnelirobles

@arnelirobles arnelirobles commented Aug 7, 2026

Copy link
Copy Markdown

Fixes #1722

The problem

UnsafeStartAsync invokes the startup callback on every start, so a reused container runs InitiateReplicaSetAsync against a replica set that is already initiated.

The script it runs is not idempotent:

var r = rs.initiate({_id:"rs0", members:[{_id:0, host:"127.0.0.1:27017"}]});
quit(r.ok === 1 ? 0 : 1);

On a set that already exists, rs.initiate throws rather than returning a result, so var r is never assigned and mongosh exits non-zero:

MongoServerError: already initialized
  code: 23
  codeName: 'AlreadyInitialized'

WaitStrategy.WaitUntilAsync then retries the script on its interval. The default wait strategy timeout is one hour, which is why the reporter saw the same mongosh exec repeat "without ever resolving".

The fix

Catch the error and treat AlreadyInitialized as success, so the startup callback is idempotent:

try { var r = rs.initiate({...}); quit(r.ok === 1 ? 0 : 1); }
catch (e) { quit(e.codeName === "AlreadyInitialized" ? 0 : 1); }

Any other server error still exits non-zero and is still retried, so a genuinely failing initiation behaves as before.

Testing

MongoDbReplicaSetReuseTest.ReusedContainerStartsAgain starts the same replica set container twice with WithReuse(true), asserts the second start reused the first container, and asserts the replica set is healthy afterwards.

  • Before the change: times out (bounded to 3 minutes in the test so a regression fails rather than hangs).
  • After the change: passes in about 7 seconds.
  • Full Testcontainers.MongoDb.Tests suite: 19 passed, 0 failed.

The test bounds its own wait because the default wait strategy timeout is one hour; without a bound a regression would stall a CI run rather than fail it.

A related defect, not addressed here

While testing this I first wrote the regression test as a stop/start restart rather than reuse, and hit a different problem in WaitIndicateReadiness:

var (stdout, stderr) = await container.GetLogsAsync(since: container.StoppedTime, timestampsEnabled: false);
return _count.Equals(... .Count(line => line.Contains("Waiting for connections")));

It asserts the count is exactly 1 or 2 over logs taken since StoppedTime, which is not restart-safe in either direction:

  • After a restart the window spans the previous and the new boot, so the count exceeds _count and the equality can never hold. The container start hangs.
  • A single stale "Waiting for connections" line from the previous run can satisfy the check before the new mongod is listening, so the start returns early and the next command fails with MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017.

I have kept that out of this pull request since it is a separate defect with its own design question, and raised it separately. Happy to pick it up if you would like it fixed the same way.

Summary by CodeRabbit

  • Bug Fixes

    • Improved MongoDB replica-set startup when reusing or restarting containers.
    • Recognizes an already-initialized replica set as successful, allowing startup callbacks to run safely.
    • Other initialization failures continue to be reported.
  • Tests

    • Added coverage verifying reusable MongoDB replica-set containers can start again successfully and retain replica-set status.

The startup callback runs on every start, so a reused container runs the
replica set initiate script against a set that is already initiated. mongosh
throws MongoServerError (code 23, AlreadyInitialized) rather than returning a
result, so the script exits non-zero and the wait strategy retries it until it
times out. The default timeout is one hour, so the caller appears to hang.

Catch that error and exit zero, which makes the callback idempotent.

Adds a reuse test that starts the same replica set container twice. It times
out before this change and completes in a few seconds after it.
@netlify

netlify Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploy Preview for testcontainers-dotnet ready!

Name Link
🔨 Latest commit 3a5e858
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-dotnet/deploys/6a75ead5ac1b60000851c7b2
😎 Deploy Preview https://deploy-preview-1731--testcontainers-dotnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fa1ea94a-fe5e-42ae-b44a-d4bd14926cb1

📥 Commits

Reviewing files that changed from the base of the PR and between 1d329ad and 3a5e858.

📒 Files selected for processing (3)
  • src/Testcontainers.MongoDb/MongoDbBuilder.cs
  • tests/Testcontainers.MongoDb.Tests/MongoDbReplicaSetReuseTest.cs
  • tests/Testcontainers.MongoDb.Tests/Usings.cs

Walkthrough

MongoDB replica-set initialization now succeeds when MongoDB reports AlreadyInitialized. An integration test verifies that reusable containers start again, reuse the same container, and report a valid replica-set status.

Changes

MongoDB replica-set reuse

Layer / File(s) Summary
Replica-set initialization handling
src/Testcontainers.MongoDb/MongoDbBuilder.cs
The initialization script treats AlreadyInitialized as successful and returns failure for other initialization errors or unsuccessful results.
Reusable container integration validation
tests/Testcontainers.MongoDb.Tests/MongoDbReplicaSetReuseTest.cs, tests/Testcontainers.MongoDb.Tests/Usings.cs
The test starts a reusable replica-set container twice, verifies reuse, checks rs.status().ok, and adds the required global imports.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: bug

Suggested reviewers: hofmeisteran

Poem

A rabbit watched Mongo start twice,
“Already initialized” now rolls like dice.
The same small container springs to life,
Replica status shines without strife.
Hop, hop—reuse is nice!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary fix for already initialized MongoDB replica sets.
Description check ✅ Passed The description explains the problem, fix, rationale, linked issue, testing, and intentionally excluded defect.
Linked Issues check ✅ Passed The changes satisfy issue #1722 by making reused replica-set startup succeed and adding a regression test for repeated starts.
Out of Scope Changes check ✅ Passed The implementation and regression test remain focused on idempotent replica-set initialization for reused MongoDB containers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: MongoDB withReuse and withReplica keeps on trying to execute command without ever resolving

1 participant