Skip to content

MongoDB Replicaset support#16698

Open
artiomchi wants to merge 6 commits intomicrosoft:mainfrom
artiomchi:feat/add-mongodb-replicaset-support
Open

MongoDB Replicaset support#16698
artiomchi wants to merge 6 commits intomicrosoft:mainfrom
artiomchi:feat/add-mongodb-replicaset-support

Conversation

@artiomchi
Copy link
Copy Markdown

@artiomchi artiomchi commented May 2, 2026

Description

This PR modifies the MongoDB Builder to add support for building a single node replica set. This will allow applications using transactions or change streams to use MongoDB in Aspire.

I'm using the same approach as I used when building the Testcontainers.MongoDb library. Instead of building a separate container in a dockerfile, the standard mongo container is used. To start as a replicaset, a keyfile is generated and added to to the container. The healthcheck is used to ensure the replicaset is initialised on server startup. This keeps the implementation clean and doesn't require an additional dockerfile.

  • New WithReplicaSet() Extension Method on the builder
    • Configures Mongo to run as a single node replica set
    • Generates a new keyfile and stores it as a secret parameter
  • New Mongo health check
    • Falls back to simple connection checks for non replica sets
    • Ensures replSetInitiate command runs
    • Verifies primary node election
  • MongoDBServer resource updates
    • Adds ReplicaSetName property
    • Updates connection string to include directConnection=true parameter when replica set is enabled

Fixes #5238

Decision points

New health check

The new health check replaces the simple original health check and will only return healthy once the replica set is initialised. It is also used to call the rs.initiate() call in Mongo to initialise the replicaset.

Alternatives considered:

  • OnResourceReady callback fires after the health check passes - this would mark the resource as healthy before the replica set is ready
  • docker-entrypoint-initdb.d - tried in the past, this won't work as that script runs against a standalone mongod instance, and won't affect the main instance
  • Separate health check - this would require the main health check to pass, and would send conflicting signals
  • Additional resource that initialises the replicaset once the server is ready, then referencing that in applications - works, provides visibility in the dashboard that the replicaset is initialised separately, but adds unnecessary complexity to configuratio for the users in the AppHost, as well as in the dashboard. Doesn't bring any tangible value

Direct connection in connection string

Specifying the replicaset name in the connection string is explicitly discouraged by the MongoDB driver configuration, and can cause behavioural conflicts. Specifying directConnection=true in the connection string tells the MongoDB driver to connect directly to the specified host bypassing topology discovery. Since we only have a single node, this is more than enough. Additionally, the topology discovery would return the internal host address within the container, which wouldn't be accessible by the application.

Note

There may be an issue in Mongo 8.0 - 8.2 that causes Mongo to crash every ~30 seconds if replica set is initiated. Seems to be a compatibility issue with certain linux kernels. Switching to older Mongo versions (7.0) seems to completely bypass the issue. Not related to this PR or Aspire, purely a MongoDB regression.

ref:
bluewave-labs/Checkmate#3444
https://www.mongodb.com/community/forums/t/mongodb-8-x-and-linux-kernel-6-19/337547
stoatchat/self-hosted#268

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 2, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16698

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 16698"

Minor cleanup
@artiomchi artiomchi force-pushed the feat/add-mongodb-replicaset-support branch from 66c95f0 to 67db131 Compare May 2, 2026 16:57
@artiomchi artiomchi marked this pull request as ready for review May 2, 2026 16:58
Copilot AI review requested due to automatic review settings May 2, 2026 16:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds single-node replica set support for hosted MongoDB resources so transaction-dependent scenarios can run against the Aspire MongoDB container, and introduces tests for the new API and connection string behavior.

Changes:

  • Add WithReplicaSet(...) to configure MongoDB as a single-node replica set and expose ReplicaSetName.
  • Replace the default MongoDB health check with a custom health check that initializes the replica set and waits for primary election.
  • Add functional and unit tests covering the new API, container args, and connection string updates.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Aspire.Hosting.MongoDB.Tests/MongoDbFunctionalTests.cs Adds a functional test that verifies transactions succeed against a replica-set-enabled MongoDB resource.
tests/Aspire.Hosting.MongoDB.Tests/MongoDBPublicApiTests.cs Adds public API validation tests for WithReplicaSet and ReplicaSetName.
tests/Aspire.Hosting.MongoDB.Tests/AddMongoDBTests.cs Adds unit tests for replica set defaults, args, annotations, and connection string behavior.
src/Aspire.Hosting.MongoDB/api/Aspire.Hosting.MongoDB.cs Updates the shipped public API surface with WithReplicaSet and ReplicaSetName.
src/Aspire.Hosting.MongoDB/MongoDBServerResource.cs Extends the resource model and connection string generation for replica set mode.
src/Aspire.Hosting.MongoDB/MongoDBServerHealthCheck.cs Introduces a custom health check that initializes the replica set and checks primary readiness.
src/Aspire.Hosting.MongoDB/MongoDBBuilderExtensions.cs Registers the new health check and implements WithReplicaSet.

Comment thread src/Aspire.Hosting.MongoDB/MongoDBServerHealthCheck.cs Outdated
Comment thread tests/Aspire.Hosting.MongoDB.Tests/AddMongoDBTests.cs Outdated
Comment thread tests/Aspire.Hosting.MongoDB.Tests/MongoDbFunctionalTests.cs
@artiomchi artiomchi requested a review from Copilot May 2, 2026 17:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Comment thread src/Aspire.Hosting.MongoDB/MongoDBServerHealthCheck.cs Outdated
Comment thread src/Aspire.Hosting.MongoDB/MongoDBServerHealthCheck.cs
Comment thread src/Aspire.Hosting.MongoDB/MongoDBServerHealthCheck.cs Outdated
Comment thread src/Aspire.Hosting.MongoDB/MongoDBServerHealthCheck.cs
Comment thread src/Aspire.Hosting.MongoDB/MongoDBBuilderExtensions.cs Outdated
artiomchi added 2 commits May 2, 2026 18:34
…ead safe way

Disposing of the mongo cursor in the health check
new BsonDocument
{
["_id"] = 0,
["host"] = $"{resource.Name}:{targetPort}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

While it works for the simplest scenarios, the issue is that depending on which service is accessing the resource, it requires a different host name:

  • If the replica set is accessed from the Aspire container network, $"{resource.Name}:{targetPort}" should be fine, though more correct name would be $"{resource.Name}.dev.internal:{targetPort}". Ideally, the actual URL should be retrieved from the server's ConnectionStringExpression with the DefaultAspireContainerNetwork context.
  • If the replica set is accessed from the services running locally, not in a container, they should be resolved as $"localhost:{targetPort}". Or, more precisely, from the server's ConnectionStringExpression with the LocalhostNetwork context. It's possible to add manual hosts mapping, of cause, but it does not seem to be a good solution.

I guess, if Dev Tunnels are being used, the things might get even more complicated, but I have not tried it myself.

As far as I know, the only reliable solution for that is using MongoDB Horizons feature, but it makes things more complicated as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Nah, none of this should be a problem. The host name here is only for the internal replication engine initialisation.

For connections to the mongo database from the application, the regular connection string is used, with the addition of the directConnection=true param.

/// <param name="replicaSetName">The name of the replica set. Defaults to <c>rs0</c>.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
[AspireExport(Description = "Configures the MongoDB container to start as a single-node replica set")]
public static IResourceBuilder<MongoDBServerResource> WithReplicaSet(this IResourceBuilder<MongoDBServerResource> builder, string replicaSetName = "rs0")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

My concern is that this design does not allow to extend this feature beyond single-node replica sets.
In my opinion, having a replica set as a separate resource is a better option.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Is this needed though, for a local development database? This shouldn't be used to deploy a resilient production level database, that would require an entirely different ballgame

var targetPort = resource.PrimaryEndpoint.TargetPort ?? 27017;
var initCmd = new BsonDocument
{
["replSetInitiate"] = new BsonDocument
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It feels a bit like an abuse of the healthcheck. This logic can live in a separate event handler.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You might say that, but it's the cleaner way to do this, considering the alternatives, while keeping the design simple and unobtrusive. Happy to discuss further, but I've explained the design decisions for this in the PR body above

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.

MongoDB Transactions requires replicas

3 participants