Skip to content

Commit 443d118

Browse files
Add client provider support (#794)
* Introduce mongo client provider * Properly conditionally activate the installers * Field annotation --------- Co-authored-by: Daniel Marbach <[email protected]>
1 parent 71e305c commit 443d118

File tree

19 files changed

+257
-111
lines changed

19 files changed

+257
-111
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#nullable enable
2+
3+
namespace NServiceBus.AcceptanceTests;
4+
5+
using System;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Threading.Tasks;
8+
using AcceptanceTesting;
9+
using EndpointTemplates;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using MongoDB.Driver;
12+
using NUnit.Framework;
13+
using Storage.MongoDB;
14+
15+
public class When_custom_provider_registered : NServiceBusAcceptanceTest
16+
{
17+
[Test]
18+
public async Task Should_be_used()
19+
{
20+
Context context = await Scenario.Define<Context>()
21+
.WithEndpoint<EndpointWithCustomProvider>(b => b.When(session => session.SendLocal(new StartSaga1 { DataId = Guid.NewGuid() })))
22+
.Done(c => c.SagaReceivedMessage)
23+
.Run();
24+
25+
Assert.That(context.ProviderWasCalled, Is.True);
26+
}
27+
28+
public class Context : ScenarioContext
29+
{
30+
public bool SagaReceivedMessage { get; set; }
31+
public bool ProviderWasCalled { get; set; }
32+
}
33+
34+
public class EndpointWithCustomProvider : EndpointConfigurationBuilder
35+
{
36+
public EndpointWithCustomProvider() =>
37+
EndpointSetup<DefaultServer>(config =>
38+
{
39+
config.RegisterComponents(c =>
40+
c.AddSingleton<IMongoClientProvider>(b => new CustomProvider(b.GetRequiredService<Context>())));
41+
});
42+
43+
public class JustASaga(Context testContext) : Saga<JustASagaData>, IAmStartedByMessages<StartSaga1>
44+
{
45+
public Task Handle(StartSaga1 message, IMessageHandlerContext context)
46+
{
47+
Data.DataId = message.DataId;
48+
testContext.SagaReceivedMessage = true;
49+
MarkAsComplete();
50+
return Task.CompletedTask;
51+
}
52+
53+
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<JustASagaData> mapper) => mapper.ConfigureMapping<StartSaga1>(m => m.DataId).ToSaga(s => s.DataId);
54+
}
55+
56+
public class CustomProvider(Context testContext) : IMongoClientProvider
57+
{
58+
[field: AllowNull, MaybeNull]
59+
public IMongoClient Client
60+
{
61+
get
62+
{
63+
if (field is not null)
64+
{
65+
return field;
66+
}
67+
68+
var containerConnectionString = Environment.GetEnvironmentVariable("NServiceBusStorageMongoDB_ConnectionString");
69+
70+
field = string.IsNullOrWhiteSpace(containerConnectionString) ? new MongoClient() : new MongoClient(containerConnectionString);
71+
testContext.ProviderWasCalled = true;
72+
return field;
73+
}
74+
}
75+
}
76+
77+
public class JustASagaData : ContainSagaData
78+
{
79+
public virtual Guid DataId { get; set; }
80+
}
81+
}
82+
83+
public class StartSaga1 : ICommand
84+
{
85+
public Guid DataId { get; set; }
86+
}
87+
}

src/NServiceBus.Storage.MongoDB.PersistenceTests/PersistenceTestsConfiguration.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using MongoDB.Bson;
88
using MongoDB.Bson.Serialization;
99
using MongoDB.Bson.Serialization.Serializers;
10-
using MongoDB.Driver;
1110
using NServiceBus.Outbox;
1211
using NServiceBus.Sagas;
1312
using Persistence;
@@ -40,15 +39,9 @@ public async Task Configure(CancellationToken cancellationToken = default)
4039
BsonSerializer.TryRegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
4140

4241
var memberMapCache = new MemberMapCache();
43-
var databaseSettings = new MongoDatabaseSettings
44-
{
45-
ReadConcern = ReadConcern.Majority,
46-
ReadPreference = ReadPreference.Primary,
47-
WriteConcern = WriteConcern.WMajority
48-
};
4942

5043
SagaStorageFeature.RegisterSagaEntityClassMappings(SagaMetadataCollection, memberMapCache);
51-
await SagaInstaller.CreateInfrastructureForSagaDataTypes(ClientProvider.Client, databaseSettings, memberMapCache, databaseName,
44+
await SagaInstaller.CreateInfrastructureForSagaDataTypes(ClientProvider.Client, MongoPersistence.DefaultDatabaseSettings, memberMapCache, databaseName,
5245
MongoPersistence.DefaultCollectionNamingConvention, MongoPersistence.DefaultCollectionSettings, SagaMetadataCollection, cancellationToken);
5346

5447
SagaStorage = new SagaPersister(SagaPersister.DefaultVersionElementName, memberMapCache);
@@ -60,7 +53,7 @@ await SagaInstaller.CreateInfrastructureForSagaDataTypes(ClientProvider.Client,
6053
OutboxStorageFeature.RegisterOutboxClassMappings();
6154
await OutboxInstaller.CreateInfrastructureForOutboxTypes(ClientProvider.Client, databaseName, MongoPersistence.DefaultDatabaseSettings, MongoPersistence.DefaultCollectionNamingConvention, MongoPersistence.DefaultCollectionSettings, TimeSpan.FromDays(7), cancellationToken);
6255

63-
OutboxStorage = new OutboxPersister(ClientProvider.Client, databaseName, MongoPersistence.DefaultCollectionNamingConvention);
56+
OutboxStorage = new OutboxPersister(ClientProvider.Client, databaseName, MongoPersistence.DefaultDatabaseSettings, MongoPersistence.DefaultCollectionNamingConvention, MongoPersistence.DefaultCollectionSettings);
6457
}
6558

6659
public async Task Cleanup(CancellationToken cancellationToken = default) =>

src/NServiceBus.Storage.MongoDB.Tests/ApprovalFiles/APIApprovals.Approve.approved.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ namespace NServiceBus
2828
}
2929
namespace NServiceBus.Storage.MongoDB
3030
{
31+
public interface IMongoClientProvider
32+
{
33+
MongoDB.Driver.IMongoClient Client { get; }
34+
}
3135
public interface IMongoSynchronizedStorageSession
3236
{
3337
MongoDB.Driver.IClientSessionHandle? MongoSession { get; }

src/NServiceBus.Storage.MongoDB.Tests/Outbox/OutboxTestsConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public async Task Configure()
4141
await OutboxInstaller.CreateInfrastructureForOutboxTypes(ClientProvider.Client, DatabaseName, MongoPersistence.DefaultDatabaseSettings, CollectionNamingConvention,
4242
MongoPersistence.DefaultCollectionSettings, TimeSpan.FromHours(1));
4343

44-
OutboxStorage = new OutboxPersister(ClientProvider.Client, DatabaseName, CollectionNamingConvention);
44+
OutboxStorage = new OutboxPersister(ClientProvider.Client, DatabaseName, MongoPersistence.DefaultDatabaseSettings, CollectionNamingConvention, MongoPersistence.DefaultCollectionSettings);
4545
}
4646

4747
public async Task Cleanup() => await ClientProvider.Client.DropDatabaseAsync(DatabaseName);

src/NServiceBus.Storage.MongoDB.Tests/SubscriptionStorageTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ public async Task OneTimeSetUp()
1818
{
1919
DatabaseName = "Test_" + DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
2020

21-
var subscriptionCollection = ClientProvider.Client.GetDatabase(DatabaseName, MongoPersistence.DefaultDatabaseSettings)
22-
.GetCollection<EventSubscription>("eventsubscriptions", MongoPersistence.DefaultCollectionSettings);
23-
2421
await SubscriptionInstaller.CreateInfrastructureForSubscriptionTypes(ClientProvider.Client, MongoPersistence.DefaultDatabaseSettings, DatabaseName, MongoPersistence.DefaultCollectionSettings, _ => "eventsubscriptions");
2522

26-
var subscriptionPersister = new SubscriptionPersister(subscriptionCollection);
23+
var subscriptionPersister = new SubscriptionPersister(ClientProvider.Client, DatabaseName, MongoPersistence.DefaultDatabaseSettings,
24+
_ => "eventsubscriptions", MongoPersistence.DefaultCollectionSettings);
2725
storage = subscriptionPersister;
2826
}
2927

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace NServiceBus.Storage.MongoDB;
2+
3+
using System.Diagnostics.CodeAnalysis;
4+
using global::MongoDB.Driver;
5+
6+
sealed class DefaultMongoClientProvider : IMongoClientProvider
7+
{
8+
[field: AllowNull, MaybeNull]
9+
public IMongoClient Client
10+
{
11+
get
12+
{
13+
field ??= new MongoClient();
14+
return field;
15+
}
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace NServiceBus.Storage.MongoDB;
2+
3+
using global::MongoDB.Driver;
4+
5+
/// <summary>
6+
/// Provides a mongo client via dependency injection. A custom implementation can be registered on the container and will be picked up by the persistence.
7+
/// <remarks>
8+
/// The client provided will not be disposed by the persistence. It is the responsibility of the provider to take care of proper resource disposal if necessary.
9+
/// </remarks>
10+
/// </summary>
11+
public interface IMongoClientProvider
12+
{
13+
/// <summary>
14+
/// The mongo client to use.
15+
/// </summary>
16+
IMongoClient Client { get; }
17+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace NServiceBus.Storage.MongoDB;
2+
3+
using global::MongoDB.Driver;
4+
5+
class MongoClientProvidedByConfiguration(IMongoClient client) : IMongoClientProvider
6+
{
7+
public IMongoClient Client { get; } = client;
8+
}

src/NServiceBus.Storage.MongoDB/Configuration/MongoSettingsExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static PersistenceExtensions<MongoPersistence> MongoClient(
1919
ArgumentNullException.ThrowIfNull(persistenceExtensions);
2020
ArgumentNullException.ThrowIfNull(mongoClient);
2121

22-
persistenceExtensions.GetSettings().Set(SettingsKeys.MongoClient, () => mongoClient);
22+
persistenceExtensions.GetSettings().Set<IMongoClientProvider>(new MongoClientProvidedByConfiguration(mongoClient));
2323
return persistenceExtensions;
2424
}
2525

src/NServiceBus.Storage.MongoDB/Configuration/SettingsKeys.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ static class SettingsKeys
66
public const string VersionElementName = baseName + nameof(VersionElementName);
77
public const string CollectionNamingConvention = baseName + nameof(CollectionNamingConvention);
88
public const string DatabaseName = baseName + nameof(DatabaseName);
9-
public const string MongoClient = baseName + nameof(MongoClient);
109
public const string UseTransactions = baseName + nameof(UseTransactions);
1110
public const string TimeToKeepOutboxDeduplicationData = baseName + nameof(TimeToKeepOutboxDeduplicationData);
1211
}

0 commit comments

Comments
 (0)