Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mongodb container and connection support #986

Merged
merged 16 commits into from
Dec 6, 2023

Conversation

ailtonguitar
Copy link
Contributor

@ailtonguitar ailtonguitar commented Nov 21, 2023

  • Adds MongoDB resources to connection and container

#694

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-integrations Issues pertaining to Aspire Integrations packages label Nov 21, 2023
@ailtonguitar
Copy link
Contributor Author

ailtonguitar commented Nov 21, 2023

@ailtonguitar please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@dotnet-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@dotnet-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@dotnet-policy-service agree company="Microsoft"

Contributor License Agreement

@dotnet-policy-service agree company="Microsoft"

@ailtonguitar ailtonguitar force-pushed the features/add-mongodb-support branch 4 times, most recently from 4d9b309 to 850b587 Compare November 22, 2023 10:30
@ailtonguitar ailtonguitar changed the title WIP: Features/add mongodb support Add mongodb container and connection support Nov 22, 2023
@ailtonguitar ailtonguitar changed the title Add mongodb container and connection support [WIP] Add mongodb container and connection support Nov 22, 2023
@ailtonguitar ailtonguitar force-pushed the features/add-mongodb-support branch 2 times, most recently from 5f7fd8a to b1be7c1 Compare November 22, 2023 12:06
@ailtonguitar ailtonguitar changed the title [WIP] Add mongodb container and connection support Add mongodb container and connection support Nov 22, 2023
@ailtonguitar ailtonguitar force-pushed the features/add-mongodb-support branch 3 times, most recently from 22c77d9 to 40d81ee Compare November 23, 2023 17:23
"MongoDB": {
"type": "object",
"properties": {
"ConnectionString": {
Copy link
Member

Choose a reason for hiding this comment

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

Is this the only setting worth exposing? There must be more 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @davidfowl !
I'll add more settings here.
Also, I've tried to add healthcheck support but the package AspNetCore.HealthChecks.MongoDb is not restored by the configured package sources. Is there any problem to use this package here?

Copy link
Member

Choose a reason for hiding this comment

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

The package will need to be added to our internal mirror.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've implemented a custom health check for that but if you prefer I can change it to use the package when it available.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@ailtonguitar ailtonguitar Nov 28, 2023

Choose a reason for hiding this comment

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

Hi @eerhardt I've already tried to use this health check but the package is not available.

Please see the previous comments.
#986 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

Ah, sorry I missed that. The package needs to be mirrored to our trusted feed. I'm doing that now. It should be done in a few minutes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've changed to use the package, please review.

@davidfowl davidfowl added the area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication label Nov 24, 2023
@ailtonguitar ailtonguitar force-pushed the features/add-mongodb-support branch 5 times, most recently from a0b42c3 to 74b9c9a Compare November 27, 2023 18:12
@eerhardt eerhardt self-assigned this Nov 27, 2023
"MongoDB": {
"type": "object",
"properties": {
"ConnectionString": {
Copy link
Member

Choose a reason for hiding this comment

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


<PropertyGroup>
<TargetFramework>$(NetCurrent)</TargetFramework>
<NoWarn>CS8002;CS1591</NoWarn>
Copy link
Member

Choose a reason for hiding this comment

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

Why are these being suppressed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because the official MongoDB.Driver package doesn't have a strongly name and it causes compilation errors.

https://jira.mongodb.org/browse/CSHARP-142

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've updated with the suggestion, can we close this one?

Copy link
Member

Choose a reason for hiding this comment

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

@jkotas @dsplaisted - are there any drawbacks/limitations/issues in .NET 8+ with using weak named assemblies?

One that @ericstj told me was:

CoreCLR will load any version of a weak named assembly. So even if you reference v2, if v1 happens to be lying around the runtime will load it and you'll get crazy errors later.

Our guidance https://learn.microsoft.com/en-us/dotnet/standard/library-guidance/strong-naming is that people consider strong naming their libraries. Although adding one is a binary breaking change.

Copy link
Member

Choose a reason for hiding this comment

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

CoreCLR will load any version of a weak named assembly. So even if you reference v2, if v1 happens to be lying around the runtime will load it and you'll get crazy errors later.

I didn't know that was the case, I'm kind of surprised by that.

Copy link
Member

Choose a reason for hiding this comment

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

Agree with concerns about Aspire being the canary here. Feels more like it should be a more centrally coordinated change across the suite of .NET products than something we just start doing. Suppressing the warning (given it's just a compiler-level thing) seems fine for us.

Copy link
Member

Choose a reason for hiding this comment

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

Feels more like it should be a more centrally coordinated change across the suite of .NET products than something we just start doing

I do not see what you would like to centrally coordinate. The strong name cannot be changed for anything existing, it would be breaking. The strong-name free world can be only enjoyed by brand new components, like Aspire.

If you do not want the Aspire to be first, it is ok. If the new components are not willing to do the jump, we will be stuck with strong naming forever for everything.

cc @davidfowl

Copy link
Member

Choose a reason for hiding this comment

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

Moving from ASP.NET Core 7 to ASP.NET Core 8 is a breaking change anyway though. Are you suggesting we wouldn't stop strong-naming those assemblies ever? We don't guarantee roll-forward across TFMs for apps works without recompilation.

That said, if the overall guidance is that new libraries targeting only modern .NET should not strong name their assemblies (and we update the docs to make that clearer), then I'm more inclined to try it in Aspire.

Copy link
Member

Choose a reason for hiding this comment

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

We don't guarantee roll-forward across TFMs for apps works without recompilation.

This applies to apps only, it does not apply to nuget packages. We do guarantee compatibility of public surface, so that packages targeting .NET 7 have a good chance of working on .NET 8.

Are you suggesting we wouldn't stop strong-naming those assemblies ever?

Never say never :-) .NET SDK and other tools do strong name matches in number of places. Removing strong name on existing assembly would break those tools when package targeting .NET 7 is used in .NET 8 app. We have not done analysis of what it would take to get all tools fixed.

Copy link
Member

Choose a reason for hiding this comment

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

we update the docs to make that clearer

dotnet/docs#38537

/// <summary>
/// Gets or sets a integer value that indicates the MongoDB health check timeout in milliseconds.
/// </summary>
public int? HealthCheckTimeout { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

We don't have this is our other database components, for example Npgsql. I wonder if we should.

Thoughts, @roji @ajcvickers @AndriySvyryd?

Comment on lines 157 to 171
private static void AddHealthCheck(
this IHostApplicationBuilder builder,
string connectionString,
string healthCheckName,
int? timeout)
{
builder.TryAddHealthCheck(
healthCheckName,
healthCheck => healthCheck.AddMongoDb(
connectionString,
healthCheckName,
null,
null,
timeout > 0 ? TimeSpan.FromMilliseconds(timeout.Value) : null));
}
Copy link
Member

Choose a reason for hiding this comment

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

Is this worth having a separate method to just call 1 method? Why not inline this code up where this method is called?

Copy link
Contributor Author

@ailtonguitar ailtonguitar Dec 4, 2023

Choose a reason for hiding this comment

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

I've changed the place where the check if the healthcheck is enable is done, so now it makes sense to have a method to encapsulate all the logic related to the healthcheck feature.
Please, check gain.

protected override void SetHealthCheck(MongoDBSettings options, bool enabled)
{
options.HealthCheckEnabled = enabled;
options.HealthCheckTimeout = 10;
Copy link
Member

Choose a reason for hiding this comment

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

Should we have a better default if we feel the need to set this everywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know if it can be applied everywhere, the idea here is to set a very short timeout to mongo health checkt and and avoid the tests to wait the default mongoclient timeout (30000).
But what is your idea?

tests/Aspire.MongoDB.Driver.Tests/ConformanceTests.cs Outdated Show resolved Hide resolved
@sebastienros
Copy link
Member

@ailtonguitar I pushed some changes. Please try to avoid force push if you can, I know it's your fork and you should do what pleases you with it, but I am afraid that is I do some changes they will be lost if you don't pay attention. It might also be nicer to understand the changes that you made overtime. And don't worry since we squash the commits before merging to main.

@sebastienros
Copy link
Member

@ailtonguitar While trying your PR I think I realize there is a flaw and a mismatch with the concept of "database". I believe you followed the pattern defined by the PostgreSQL component, and added an AddDatabase extension method on the host in the same way. Then from an app we call builder.AddMongoDBClient("mydatabase") to inject a IMongoClient instance for this named resource.

The issue with this model is that the current authentication only works with the "admin" database. If you try it you will see that passing anything else than "admin" as the database name will fail auth because the environment variables used are only defining a user for this db.

Once I used "admin" and resolved the client for it, I could then call GetDatabase("anythingelse").

So right now it looks like the argument in AddDatabase should not be used "in" the connection string, but only for the name of the connection string, and force "admin" in the actual connection string. When it's deployed it will matter to use something else than /admin in the connection string, but at that point the environment will provide the actual one.

@DamianEdwards
Copy link
Member

@sebastienros I'm not sure that's right. I'm pretty sure this behavior is the same as all the other database hosting extensions. See #1170 for a report of the same behavior. The app is responsible for ensuring the specified database name exists so that the login can succeed. In the case of EF Core, it actually detects this state when you call DbContext.Database.MigrateAsync and falls back to connecting to the default database depending on the provider so that it can then create the requested database.

Copy link
Member

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

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

I think this is getting pretty close to a mergeable state. @mitchdenny - are you good with the Hosting changes?

src/Aspire.Hosting/MongoDB/MongoDBDatabaseResource.cs Outdated Show resolved Hide resolved
src/Components/Aspire.MongoDB.Driver/README.md Outdated Show resolved Hide resolved
tests/Aspire.MongoDB.Driver.Tests/ConformanceTests.cs Outdated Show resolved Hide resolved
builder.TryAddHealthCheck(
healthCheckName,
healthCheck => healthCheck.AddMongoDb(
settings.ConnectionString,
Copy link
Member

Choose a reason for hiding this comment

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

Ideally this should use the same IMongoClient instance that is registered in DI. See https://github.com/dotnet/aspire/blob/main/src/Components/README.md#health-checks.

Consider whether the Health Check should reuse the same client object registered in DI by the component or not. Reusing the same client object has the advantages of getting the same configuration, logging, etc during the health check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The AspNetCore.HealthChecks.MongoDb does not support to pass an IMongoClient instance.
It is only possible to pass the connection string or the MongoClientSettings

Copy link
Contributor Author

@ailtonguitar ailtonguitar Dec 5, 2023

Choose a reason for hiding this comment

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

I've created a new PR to add support for receiving an IMongoClient instance when configuring the healthcheck

Xabaril/AspNetCore.Diagnostics.HealthChecks#2121

@sebastienros
Copy link
Member

sebastienros commented Dec 4, 2023

I created a PR that will create the database in the docker container automatically, and uses admin in the connection string as this is the authentication database. Without it the connection tries to authenticate using the account and database define in configuration but it doesn't work.

ailtonguitar#1

I didn't want to push this change directly in case someone has other suggestions.

Update: PR closed, not required anymore

Copy link
Member

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

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

I think this looks good for an initial implementation.

Thanks @ailtonguitar for this great contribution.

If my only question needs a code change, we can follow up with a separate PR for it.

/// <summary>
/// Gets or sets a integer value that indicates the MongoDB health check timeout in milliseconds.
/// </summary>
public int? HealthCheckTimeout { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

This may be a silly question, but if this isn't set, the health check never times out, right? How do we know if it is not healthy if the check never times out?

Copy link
Contributor Author

@ailtonguitar ailtonguitar Dec 6, 2023

Choose a reason for hiding this comment

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

I think that it will use the defined mongoclient timeout or the default value (30s).

@eerhardt
Copy link
Member

eerhardt commented Dec 6, 2023

@ailtonguitar - are you OK with the changes @sebastienros made?

@ailtonguitar
Copy link
Contributor Author

ailtonguitar commented Dec 6, 2023

@ailtonguitar - are you OK with the changes @sebastienros made?]

Hi @eerhardt ! Yes, fine by me!

@eerhardt eerhardt merged commit 55dd83a into dotnet:main Dec 6, 2023
8 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Apr 28, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication area-integrations Issues pertaining to Aspire Integrations packages
Projects
None yet
Development

Successfully merging this pull request may close these issues.