From cc6a606a4656813f1cc76416edf50ccc4085588a Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Fri, 30 Jun 2023 16:27:23 +0200 Subject: [PATCH 01/15] Initial start implementing hosting support --- Akka.Persistence.MongoDb.sln | 10 +- .../Akka.Persistence.MongoDb.Hosting.csproj | 16 ++ ...AkkaPersistenceMongoDbHostingExtensions.cs | 214 ++++++++++++++++++ .../MongoDbJournalOptions.cs | 78 +++++++ .../MongoDbSnapshotOptions.cs | 72 ++++++ .../MongoDbSettings.cs | 4 + 6 files changed, 392 insertions(+), 2 deletions(-) create mode 100644 src/Akka.Persistence.MongoDb.Hosting/Akka.Persistence.MongoDb.Hosting.csproj create mode 100644 src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs create mode 100644 src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs create mode 100644 src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs diff --git a/Akka.Persistence.MongoDb.sln b/Akka.Persistence.MongoDb.sln index b3f311a..fed2341 100644 --- a/Akka.Persistence.MongoDb.sln +++ b/Akka.Persistence.MongoDb.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29306.81 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33723.286 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.MongoDb", "src\Akka.Persistence.MongoDb\Akka.Persistence.MongoDb.csproj", "{E945AABA-2779-41E8-9B43-8898FFD64F22}" EndProject @@ -15,6 +15,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{BE1178E1 build.sh = build.sh EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.MongoDb.Hosting", "src\Akka.Persistence.MongoDb.Hosting\Akka.Persistence.MongoDb.Hosting.csproj", "{72B8C165-FE00-465F-A2E9-60B4B79F81AF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,6 +31,10 @@ Global {0F9B9BC6-9F86-40E8-BA9B-D27BF3AC7970}.Debug|Any CPU.Build.0 = Debug|Any CPU {0F9B9BC6-9F86-40E8-BA9B-D27BF3AC7970}.Release|Any CPU.ActiveCfg = Release|Any CPU {0F9B9BC6-9F86-40E8-BA9B-D27BF3AC7970}.Release|Any CPU.Build.0 = Release|Any CPU + {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Akka.Persistence.MongoDb.Hosting/Akka.Persistence.MongoDb.Hosting.csproj b/src/Akka.Persistence.MongoDb.Hosting/Akka.Persistence.MongoDb.Hosting.csproj new file mode 100644 index 0000000..9a02ec8 --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting/Akka.Persistence.MongoDb.Hosting.csproj @@ -0,0 +1,16 @@ + + + + + $(NetStandardLibVersion) + latest + + + + + + + + + + \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs b/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs new file mode 100644 index 0000000..62b17fe --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs @@ -0,0 +1,214 @@ +using System; +using Akka.Actor; +using Akka.Hosting; +using Akka.Persistence.Hosting; + +#nullable enable +namespace Akka.Persistence.MongoDb.Hosting; + +public static class AkkaPersistenceMongoDbHostingExtensions +{ + /// + /// Adds Akka.Persistence.SqlServer support to this . + /// + /// + /// The builder instance being configured. + /// + /// + /// Connection string used for database access. + /// + /// + /// + /// Determines which settings should be added by this method call. + /// + /// Default: + /// + /// + /// + /// Should the SQL store table be initialized automatically. + /// + /// Default: false + /// + /// + /// + /// An used to configure an instance. + /// + /// Default: null + /// + /// + /// + /// The configuration identifier for the plugins + /// + /// Default: "sql-server" + /// + /// + /// + /// A bool flag to set the plugin as the default persistence plugin for the + /// + /// Default: true + /// + /// + /// The same instance originally passed in. + /// + /// + /// Thrown when is set and is set to + /// + /// + public static AkkaConfigurationBuilder WithMongoDbPersistence( + this AkkaConfigurationBuilder builder, + string connectionString, + + PersistenceMode mode = PersistenceMode.Both, + bool autoInitialize = true, + Action? journalBuilder = null, + string pluginIdentifier = "mongodb", + bool isDefaultPlugin = true) + { + if (mode == PersistenceMode.SnapshotStore && journalBuilder is { }) + throw new Exception( + $"{nameof(journalBuilder)} can only be set when {nameof(mode)} is set to either {PersistenceMode.Both} or {PersistenceMode.Journal}"); + + var journalOpt = new MongoDbJournalOptions(isDefaultPlugin, pluginIdentifier) + { + ConnectionString = connectionString, + AutoInitialize = autoInitialize, + }; + + var adapters = new AkkaPersistenceJournalBuilder(journalOpt.Identifier, builder); + journalBuilder?.Invoke(adapters); + journalOpt.Adapters = adapters; + + var snapshotOpt = new MongoDbSnapshotOptions(isDefaultPlugin, pluginIdentifier) + { + ConnectionString = connectionString, + AutoInitialize = autoInitialize, + }; + + return mode switch + { + PersistenceMode.Journal => builder.WithMongoDbPersistence(journalOpt, null), + PersistenceMode.SnapshotStore => builder.WithMongoDbPersistence(null, snapshotOpt), + PersistenceMode.Both => builder.WithMongoDbPersistence(journalOpt, snapshotOpt), + _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, "Invalid PersistenceMode defined.") + }; + } + + /// + /// Adds Akka.Persistence.MongoDb support to this . At least one of the + /// configurator delegate needs to be populated else this method will throw an exception. + /// + /// + /// The builder instance being configured. + /// + /// + /// + /// An that modifies an instance of , + /// used to configure the journal plugin + /// + /// Default: null + /// + /// + /// + /// An that modifies an instance of , + /// used to configure the snapshot store plugin + /// + /// Default: null + /// + /// + /// + /// A bool flag to set the plugin as the default persistence plugin for the + /// + /// Default: true + /// + /// + /// The same instance originally passed in. + /// + /// + /// Thrown when both and are null. + /// + public static AkkaConfigurationBuilder WithMongoDbPersistence( + this AkkaConfigurationBuilder builder, + Action? journalOptionConfigurator = null, + Action? snapshotOptionConfigurator = null, + bool isDefaultPlugin = true) + { + if (journalOptionConfigurator is null && snapshotOptionConfigurator is null) + throw new ArgumentException( + $"{nameof(journalOptionConfigurator)} and {nameof(snapshotOptionConfigurator)} could not both be null"); + + MongoDbJournalOptions? journalOptions = null; + if (journalOptionConfigurator is { }) + { + journalOptions = new MongoDbJournalOptions(isDefaultPlugin); + journalOptionConfigurator(journalOptions); + } + + MongoDbSnapshotOptions? snapshotOptions = null; + if (snapshotOptionConfigurator is { }) + { + snapshotOptions = new MongoDbSnapshotOptions(isDefaultPlugin); + snapshotOptionConfigurator(snapshotOptions); + } + + return builder.WithMongoDbPersistence(journalOptions, snapshotOptions); + } + + /// + /// Adds Akka.Persistence.MongoDb support to this . At least one of the options + /// have to be populated else this method will throw an exception. + /// + /// + /// The builder instance being configured. + /// + /// + /// + /// An instance of , used to configure the journal plugin + /// + /// Default: null + /// + /// + /// + /// An instance of , used to configure the snapshot store plugin + /// + /// Default: null + /// + /// + /// The same instance originally passed in. + /// + /// + /// Thrown when both and are null. + /// + public static AkkaConfigurationBuilder WithMongoDbPersistence( + this AkkaConfigurationBuilder builder, + MongoDbJournalOptions? journalOptions = null, + MongoDbSnapshotOptions? snapshotOptions = null) + { + if (journalOptions is null && snapshotOptions is null) + throw new ArgumentException( + $"{nameof(journalOptions)} and {nameof(snapshotOptions)} could not both be null"); + + return (journalOptions, snapshotOptions) switch + { + (null, null) => + throw new ArgumentException( + $"{nameof(journalOptions)} and {nameof(snapshotOptions)} could not both be null"), + + (_, null) => + builder + .AddHocon(journalOptions.ToConfig(), HoconAddMode.Prepend) + .AddHocon(journalOptions.DefaultConfig, HoconAddMode.Append), + + (null, _) => + builder + .AddHocon(snapshotOptions.ToConfig(), HoconAddMode.Prepend) + .AddHocon(snapshotOptions.DefaultConfig, HoconAddMode.Append), + + (_, _) => + builder + .AddHocon(journalOptions.ToConfig(), HoconAddMode.Prepend) + .AddHocon(snapshotOptions.ToConfig(), HoconAddMode.Prepend) + .AddHocon(journalOptions.DefaultConfig, HoconAddMode.Append) + .AddHocon(snapshotOptions.DefaultConfig, HoconAddMode.Append), + }; + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs new file mode 100644 index 0000000..1e1f0a0 --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs @@ -0,0 +1,78 @@ +using System; +using System.Text; +using Akka.Configuration; +using Akka.Hosting; +using Akka.Persistence.Hosting; + +#nullable enable +namespace Akka.Persistence.MongoDb.Hosting; + +public class MongoDbJournalOptions : JournalOptions +{ + private static readonly Config Default = MongoDbPersistence.DefaultConfiguration() + .GetConfig(MongoDbJournalSettings.JournalConfigPath); + + public MongoDbJournalOptions() : this(true) + { + } + + public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : base(isDefault) + { + Identifier = identifier; + } + + /// + /// Connection string used to access the MongoDb, also specifies the database. + /// + public string ConnectionString { get; set; } = ""; + + /// + /// Flag determining in in case of event journal or metadata table missing, they should be automatically initialized. + /// + public bool AutoInitialize { get; set; } = true; + + /// + /// Name of the collection for the event journal or snapshots + /// + public string Collection { get; set; } = "EventJournal"; + + /// + /// Name of the collection for the event journal metadata + /// + public string MetadataCollection { get; set; } = "Metadata"; + + /// + /// Transaction + /// + public bool UseWriteTransaction { get; set; } + + /// + /// When true, enables BSON serialization (which breaks features like Akka.Cluster.Sharding, AtLeastOnceDelivery, and so on.) + /// + public bool LegacySerialization { get; set; } = false; + + /// + /// Timeout for individual database operations. + /// + /// + /// Defaults to 10s. + /// + public TimeSpan CallTimeout { get; } = TimeSpan.FromSeconds(10); + + + public override string Identifier { get; set; } + protected override Config InternalDefaultConfig { get; } = Default; + + protected override StringBuilder Build(StringBuilder sb) + { + sb.AppendLine($"connection-string = {ConnectionString.ToHocon()}"); + sb.AppendLine($"use-write-transaction = {(UseWriteTransaction ? "on" : "off")}"); + sb.AppendLine($"auto-initialize = {(AutoInitialize ? "on" : "off")}"); + sb.AppendLine($"collection = {Collection.ToHocon()}"); + sb.AppendLine($"metadata-collection = {MetadataCollection.ToHocon()}"); + sb.AppendLine($"legacy-serialization = {(LegacySerialization ? "on" : "off")}"); + sb.AppendLine($"call-timeout = {CallTimeout.ToHocon()}"); + + return base.Build(sb); + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs new file mode 100644 index 0000000..fdf776f --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs @@ -0,0 +1,72 @@ +using System; +using System.Text; +using Akka.Configuration; +using Akka.Hosting; +using Akka.Persistence.Hosting; + +#nullable enable +namespace Akka.Persistence.MongoDb.Hosting; + +public class MongoDbSnapshotOptions : SnapshotOptions +{ + private static readonly Config Default = MongoDbPersistence.DefaultConfiguration() + .GetConfig(MongoDbSnapshotSettings.SnapshotStoreConfigPath); + + public MongoDbSnapshotOptions() : this(true) + { + } + + public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : base(isDefault) + { + Identifier = identifier; + } + + /// + /// Connection string used to access the MongoDb, also specifies the database. + /// + public string ConnectionString { get; set; } = ""; + + /// + /// Flag determining in in case of event journal or metadata table missing, they should be automatically initialized. + /// + public bool AutoInitialize { get; set; } = true; + + /// + /// Name of the collection for the event journal or snapshots + /// + public string Collection { get; set; } = "EventJournal"; + + /// + /// Transaction + /// + public bool UseWriteTransaction { get; set; } + + /// + /// When true, enables BSON serialization (which breaks features like Akka.Cluster.Sharding, AtLeastOnceDelivery, and so on.) + /// + public bool LegacySerialization { get; } = false; + + /// + /// Timeout for individual database operations. + /// + /// + /// Defaults to 10s. + /// + public TimeSpan CallTimeout { get; } = TimeSpan.FromSeconds(10); + + + public override string Identifier { get; set; } + protected override Config InternalDefaultConfig { get; } = Default; + + protected override StringBuilder Build(StringBuilder sb) + { + sb.AppendLine($"connection-string = {ConnectionString.ToHocon()}"); + sb.AppendLine($"use-write-transaction = {(UseWriteTransaction ? "on" : "off")}"); + sb.AppendLine($"auto-initialize = {(AutoInitialize ? "on" : "off")}"); + sb.AppendLine($"collection = {Collection.ToHocon()}"); + sb.AppendLine($"legacy-serialization = {(LegacySerialization ? "on" : "off")}"); + sb.AppendLine($"call-timeout = {CallTimeout.ToHocon()}"); + + return base.Build(sb); + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb/MongoDbSettings.cs b/src/Akka.Persistence.MongoDb/MongoDbSettings.cs index 82003c8..59d4490 100644 --- a/src/Akka.Persistence.MongoDb/MongoDbSettings.cs +++ b/src/Akka.Persistence.MongoDb/MongoDbSettings.cs @@ -64,6 +64,8 @@ protected MongoDbSettings(Config config) /// public class MongoDbJournalSettings : MongoDbSettings { + public const string JournalConfigPath = "akka.persistence.journal.mongodb"; + public string MetadataCollection { get; private set; } public MongoDbJournalSettings(Config config) : base(config) @@ -81,6 +83,8 @@ public MongoDbJournalSettings(Config config) : base(config) /// public class MongoDbSnapshotSettings : MongoDbSettings { + public const string SnapshotStoreConfigPath = "akka.persistence.snapshot-store.mongodb"; + public MongoDbSnapshotSettings(Config config) : base(config) { if (config == null) From 4eb0e7dd0b2245fd2b0f3c0e449c7c0be6191eb7 Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Fri, 30 Jun 2023 18:39:19 +0200 Subject: [PATCH 02/15] Get the tests started. A couple still need to be done --- Akka.Persistence.MongoDb.sln | 8 +- ...a.Persistence.MongoDb.Hosting.Tests.csproj | 22 +++ .../MongoDbJournalOptionsSpec.cs | 167 ++++++++++++++++++ .../MongoDbSnapshotOptionsSpec.cs | 144 +++++++++++++++ .../MongoDbJournalOptions.cs | 8 +- .../MongoDbSnapshotOptions.cs | 12 +- 6 files changed, 346 insertions(+), 15 deletions(-) create mode 100644 src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj create mode 100644 src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs create mode 100644 src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs diff --git a/Akka.Persistence.MongoDb.sln b/Akka.Persistence.MongoDb.sln index fed2341..4c6140b 100644 --- a/Akka.Persistence.MongoDb.sln +++ b/Akka.Persistence.MongoDb.sln @@ -15,7 +15,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{BE1178E1 build.sh = build.sh EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.MongoDb.Hosting", "src\Akka.Persistence.MongoDb.Hosting\Akka.Persistence.MongoDb.Hosting.csproj", "{72B8C165-FE00-465F-A2E9-60B4B79F81AF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.MongoDb.Hosting", "src\Akka.Persistence.MongoDb.Hosting\Akka.Persistence.MongoDb.Hosting.csproj", "{72B8C165-FE00-465F-A2E9-60B4B79F81AF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.MongoDb.Hosting.Tests", "src\Akka.Persistence.MongoDb.Hosting.Tests\Akka.Persistence.MongoDb.Hosting.Tests.csproj", "{7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -35,6 +37,10 @@ Global {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Release|Any CPU.Build.0 = Release|Any CPU + {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj b/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj new file mode 100644 index 0000000..028aa59 --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj @@ -0,0 +1,22 @@ + + + + + $(NetTestVersion);$(NetCoreTestVersion) + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs new file mode 100644 index 0000000..83660ac --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs @@ -0,0 +1,167 @@ +using Akka.Configuration; +using FluentAssertions; +using Xunit; + +namespace Akka.Persistence.MongoDb.Hosting.Tests +{ + public class MongoDbJournalOptionsSpec + { + + [Fact(DisplayName = "MongoDbJournalOptions as default plugin should generate plugin setting")] + public void DefaultPluginJournalOptionsTest() + { + var options = new MongoDbJournalOptions(true); + var config = options.ToConfig(); + + config.GetString("akka.persistence.journal.plugin").Should().Be("akka.persistence.journal.mongodb"); + config.HasPath("akka.persistence.journal.mongodb").Should().BeTrue(); + } + + [Fact(DisplayName = "Empty MongoDbJournalOptions should equal empty config with default fallback")] + public void DefaultJournalOptionsTest() + { + var options = new MongoDbJournalOptions(false); + var emptyRootConfig = options.ToConfig().WithFallback(options.DefaultConfig); + var baseRootConfig = Config.Empty + .WithFallback(MongoDbPersistence.DefaultConfiguration()); + + emptyRootConfig.GetString("akka.persistence.journal.plugin").Should().Be(baseRootConfig.GetString("akka.persistence.journal.plugin")); + + var config = emptyRootConfig.GetConfig("akka.persistence.journal.mongodb"); + var baseConfig = baseRootConfig.GetConfig("akka.persistence.journal.mongodb"); + config.Should().NotBeNull(); + baseConfig.Should().NotBeNull(); + + AssertJournalConfig(config, baseConfig); + } + + [Fact(DisplayName = "Empty MongoDbJournalOptions with custom identifier should equal empty config with default fallback")] + public void CustomIdJournalOptionsTest() + { + var options = new MongoDbJournalOptions(false, "custom"); + var emptyRootConfig = options.ToConfig().WithFallback(options.DefaultConfig); + var baseRootConfig = Config.Empty + .WithFallback(MongoDbPersistence.DefaultConfiguration()); + + emptyRootConfig.GetString("akka.persistence.journal.plugin").Should().Be(baseRootConfig.GetString("akka.persistence.journal.plugin")); + + var config = emptyRootConfig.GetConfig("akka.persistence.journal.custom"); + var baseConfig = baseRootConfig.GetConfig("akka.persistence.journal.mongodb"); + config.Should().NotBeNull(); + baseConfig.Should().NotBeNull(); + + AssertJournalConfig(config, baseConfig); + } + +// [Fact(DisplayName = "MongoDbJournalOptions should generate proper config")] +// public void JournalOptionsTest() +// { +// var options = new MongoDbJournalOptions(true) +// { +// Identifier = "custom", +// AutoInitialize = true, +// ConnectionString = "testConnection", +// Collection = "testCollection", +// MetadataCollection = "metadataCollection", +// UseWriteTransaction = true, +// LegacySerialization = true, +// CallTimeout = TimeSpan.FromHours(2) +// }; +// options.Adapters.AddWriteEventAdapter("mapper1", new[] { typeof(EventAdapters.Event1) }); +// options.Adapters.AddReadEventAdapter("reader1", new[] { typeof(EventAdapters.Event1) }); +// options.Adapters.AddEventAdapter("combo", boundTypes: new[] { typeof(EventAdapters.Event2) }); +// options.Adapters.AddWriteEventAdapter("tagger", boundTypes: new[] { typeof(EventAdapters.Event1), typeof(EventAdapters.Event2) }); + +// var baseConfig = options.ToConfig(); + +// baseConfig.GetString("akka.persistence.journal.plugin").Should().Be("akka.persistence.journal.custom"); + +// var config = baseConfig.GetConfig("akka.persistence.journal.custom"); +// config.Should().NotBeNull(); +// config.GetString("connection-string").Should().Be(options.ConnectionString); +// config.GetTimeSpan("connection-timeout").Should().Be(options.ConnectionTimeout); +// config.GetString("schema-name").Should().Be(options.SchemaName); +// config.GetString("table-name").Should().Be(options.TableName); +// config.GetBoolean("auto-initialize").Should().Be(options.AutoInitialize); +// config.GetString("metadata-table-name").Should().Be(options.MetadataTableName); +// config.GetBoolean("sequential-access").Should().Be(options.SequentialAccess); +// config.GetString("stored-as").Should().Be(options.StoredAs.ToHocon()); +// config.GetBoolean("use-bigint-identity-for-ordering-column").Should().Be(options.UseBigIntIdentityForOrderingColumn); + +// config.GetStringList($"event-adapter-bindings.\"{typeof(EventAdapters.Event1).TypeQualifiedName()}\"").Should() +// .BeEquivalentTo("mapper1", "reader1", "tagger"); +// config.GetStringList($"event-adapter-bindings.\"{typeof(EventAdapters.Event2).TypeQualifiedName()}\"").Should() +// .BeEquivalentTo("combo", "tagger"); + +// config.GetString("event-adapters.mapper1").Should().Be(typeof(EventAdapters.EventMapper1).TypeQualifiedName()); +// config.GetString("event-adapters.reader1").Should().Be(typeof(EventAdapters.ReadAdapter).TypeQualifiedName()); +// config.GetString("event-adapters.combo").Should().Be(typeof(EventAdapters.ComboAdapter).TypeQualifiedName()); +// config.GetString("event-adapters.tagger").Should().Be(typeof(EventAdapters.Tagger).TypeQualifiedName()); + +// } + +// const string Json = @" +//{ +// ""Logging"": { +// ""LogLevel"": { +// ""Default"": ""Information"", +// ""Microsoft.AspNetCore"": ""Warning"" +// } +// }, +// ""Akka"": { +// ""JournalOptions"": { +// ""StoredAs"": ""JsonB"", +// ""UseBigIntIdentityForOrderingColumn"": true, + +// ""ConnectionString"": ""Server=localhost,1533;Database=Akka;User Id=sa;"", +// ""ConnectionTimeout"": ""00:00:55"", +// ""SchemaName"": ""schema"", +// ""TableName"" : ""journal"", +// ""MetadataTableName"": ""meta"", +// ""SequentialAccess"": false, + +// ""IsDefaultPlugin"": false, +// ""Identifier"": ""custom"", +// ""AutoInitialize"": true, +// ""Serializer"": ""hyperion"" +// } +// } +//}"; + +// [Fact(DisplayName = "MongoDbJournalOptions should be bindable to IConfiguration")] +// public void JournalOptionsIConfigurationBindingTest() +// { +// using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); +// var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); + +// var options = jsonConfig.GetSection("Akka:JournalOptions").Get(); +// options.IsDefaultPlugin.Should().BeFalse(); +// options.Identifier.Should().Be("custom"); +// options.AutoInitialize.Should().BeTrue(); +// options.Serializer.Should().Be("hyperion"); +// options.ConnectionString.Should().Be("Server=localhost,1533;Database=Akka;User Id=sa;"); +// options.ConnectionTimeout.Should().Be(55.Seconds()); +// options.SchemaName.Should().Be("schema"); +// options.TableName.Should().Be("journal"); +// options.MetadataTableName.Should().Be("meta"); +// options.SequentialAccess.Should().BeFalse(); + +// options.StoredAs.Should().Be(StoredAsType.JsonB); +// options.UseBigIntIdentityForOrderingColumn.Should().BeTrue(); +// } + + + private static void AssertJournalConfig(Config underTest, Config reference) + { + underTest.GetString("class").Should().Be(reference.GetString("class")); + underTest.GetString("connection-string").Should().Be(reference.GetString("connection-string")); + underTest.GetBoolean("use-write-transaction").Should().Be(reference.GetBoolean("use-write-transaction")); + underTest.GetBoolean("auto-initialize").Should().Be(reference.GetBoolean("auto-initialize")); + underTest.GetString("plugin-dispatcher").Should().Be(reference.GetString("plugin-dispatcher")); + underTest.GetString("collection").Should().Be(reference.GetString("collection")); + underTest.GetString("metadata-collection").Should().Be(reference.GetString("metadata-collection")); + underTest.GetBoolean("legacy-serialization").Should().Be(reference.GetBoolean("legacy-serialization")); + underTest.GetTimeSpan("call-timeout").Should().Be(reference.GetTimeSpan("call-timeout")); + } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs new file mode 100644 index 0000000..fd5a5be --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs @@ -0,0 +1,144 @@ +using System; +using Akka.Configuration; +using FluentAssertions; +using Xunit; + +namespace Akka.Persistence.MongoDb.Hosting.Tests +{ + public class MongoDbSnapshotOptionsSpec + { + [Fact(DisplayName = "MongoDbSnapshotOptions as default plugin should generate plugin setting")] + public void DefaultPluginSnapshotOptionsTest() + { + var options = new MongoDbSnapshotOptions(true); + var config = options.ToConfig(); + + config.GetString("akka.persistence.snapshot-store.plugin").Should().Be("akka.persistence.snapshot-store.mongodb"); + config.HasPath("akka.persistence.snapshot-store.mongodb").Should().BeTrue(); + } + + [Fact(DisplayName = "Empty MongoDbSnapshotOptions with default fallback should return default config")] + public void DefaultSnapshotOptionsTest() + { + var options = new MongoDbSnapshotOptions(false); + var emptyRootConfig = options.ToConfig().WithFallback(options.DefaultConfig); + var baseRootConfig = Config.Empty + .WithFallback(MongoDbPersistence.DefaultConfiguration()); + + emptyRootConfig.GetString("akka.persistence.snapshot-store.plugin").Should().Be(baseRootConfig.GetString("akka.persistence.snapshot-store.plugin")); + + var config = emptyRootConfig.GetConfig("akka.persistence.snapshot-store.mongodb"); + var baseConfig = baseRootConfig.GetConfig("akka.persistence.snapshot-store.mongodb"); + config.Should().NotBeNull(); + baseConfig.Should().NotBeNull(); + + config.GetString("class").Should().Be(baseConfig.GetString("class")); + config.GetString("connection-string").Should().Be(baseConfig.GetString("connection-string")); + config.GetBoolean("use-write-transaction").Should().Be(baseConfig.GetBoolean("use-write-transaction")); + config.GetBoolean("auto-initialize").Should().Be(baseConfig.GetBoolean("auto-initialize")); + config.GetString("plugin-dispatcher").Should().Be(baseConfig.GetString("plugin-dispatcher")); + config.GetString("collection").Should().Be(baseConfig.GetString("collection")); + config.GetBoolean("legacy-serialization").Should().Be(baseConfig.GetBoolean("legacy-serialization")); + config.GetTimeSpan("call-timeout").Should().Be(baseConfig.GetTimeSpan("call-timeout")); + } + + [Fact(DisplayName = "Empty MongoDbSnapshotOptions with custom identifier should equal empty config with default fallback")] + public void CustomIdSnapshotOptionsTest() + { + var options = new MongoDbSnapshotOptions(false, "custom"); + var emptyRootConfig = options.ToConfig().WithFallback(options.DefaultConfig); + var baseRootConfig = Config.Empty + .WithFallback(MongoDbPersistence.DefaultConfiguration()); + + emptyRootConfig.GetString("akka.persistence.snapshot-store.plugin").Should().Be(baseRootConfig.GetString("akka.persistence.snapshot-store.plugin")); + + var config = emptyRootConfig.GetConfig("akka.persistence.snapshot-store.custom"); + var baseConfig = baseRootConfig.GetConfig("akka.persistence.snapshot-store.mongodb"); + config.Should().NotBeNull(); + baseConfig.Should().NotBeNull(); + + config.GetString("class").Should().Be(baseConfig.GetString("class")); + config.GetString("connection-string").Should().Be(baseConfig.GetString("connection-string")); + config.GetBoolean("use-write-transaction").Should().Be(baseConfig.GetBoolean("use-write-transaction")); + config.GetBoolean("auto-initialize").Should().Be(baseConfig.GetBoolean("auto-initialize")); + config.GetString("plugin-dispatcher").Should().Be(baseConfig.GetString("plugin-dispatcher")); + config.GetString("collection").Should().Be(baseConfig.GetString("collection")); + config.GetBoolean("legacy-serialization").Should().Be(baseConfig.GetBoolean("legacy-serialization")); + config.GetTimeSpan("call-timeout").Should().Be(baseConfig.GetTimeSpan("call-timeout")); + } + + [Fact(DisplayName = "MongoDbSnapshotOptions should generate proper config")] + public void SnapshotOptionsTest() + { + var options = new MongoDbSnapshotOptions(true) + { + Identifier = "custom", + AutoInitialize = true, + ConnectionString = "testConnection", + Collection = "testCollection", + UseWriteTransaction = true, + LegacySerialization = true, + CallTimeout = TimeSpan.FromHours(2) + }; + + var baseConfig = options.ToConfig() + .WithFallback(MongoDbPersistence.DefaultConfiguration()); + + baseConfig.GetString("akka.persistence.snapshot-store.plugin").Should().Be("akka.persistence.snapshot-store.custom"); + + var config = baseConfig.GetConfig("akka.persistence.snapshot-store.custom"); + config.Should().NotBeNull(); + config.GetString("connection-string").Should().Be(options.ConnectionString); + config.GetBoolean("auto-initialize").Should().Be(options.AutoInitialize); + config.GetString("collection").Should().Be(options.Collection); + config.GetBoolean("use-write-transaction").Should().Be(options.UseWriteTransaction); + config.GetBoolean("legacy-serialization").Should().Be(options.LegacySerialization); + config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout); + } + +// [Fact(DisplayName = "MongoDbSnapshotOptions should be bindable to IConfiguration")] +// public void SnapshotOptionsIConfigurationBindingTest() +// { +// const string json = @" +//{ +// ""Logging"": { +// ""LogLevel"": { +// ""Default"": ""Information"", +// ""Microsoft.AspNetCore"": ""Warning"" +// } +// }, +// ""Akka"": { +// ""SnapshotOptions"": { +// ""StoredAs"": ""JsonB"", + +// ""ConnectionString"": ""Server=localhost,1533;Database=Akka;User Id=sa;"", +// ""ConnectionTimeout"": ""00:00:55"", +// ""SchemaName"": ""schema"", +// ""TableName"" : ""snapshot"", +// ""SequentialAccess"": false, + +// ""IsDefaultPlugin"": false, +// ""Identifier"": ""CustomSnapshot"", +// ""AutoInitialize"": true, +// ""Serializer"": ""hyperion"" +// } +// } +//}"; +// using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); +// var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); + +// var options = jsonConfig.GetSection("Akka:SnapshotOptions").Get(); +// options.IsDefaultPlugin.Should().BeFalse(); +// options.Identifier.Should().Be("CustomSnapshot"); +// options.AutoInitialize.Should().BeTrue(); +// options.Serializer.Should().Be("hyperion"); +// options.ConnectionString.Should().Be("Server=localhost,1533;Database=Akka;User Id=sa;"); +// options.ConnectionTimeout.Should().Be(55.Seconds()); +// options.SchemaName.Should().Be("schema"); +// options.TableName.Should().Be("snapshot"); +// options.SequentialAccess.Should().BeFalse(); + +// options.StoredAs.Should().Be(StoredAsType.JsonB); +// } + } +} \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs index 1e1f0a0..96dab5c 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs @@ -19,6 +19,7 @@ public MongoDbJournalOptions() : this(true) public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : base(isDefault) { Identifier = identifier; + AutoInitialize = true; } /// @@ -26,11 +27,6 @@ public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : ba /// public string ConnectionString { get; set; } = ""; - /// - /// Flag determining in in case of event journal or metadata table missing, they should be automatically initialized. - /// - public bool AutoInitialize { get; set; } = true; - /// /// Name of the collection for the event journal or snapshots /// @@ -57,7 +53,7 @@ public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : ba /// /// Defaults to 10s. /// - public TimeSpan CallTimeout { get; } = TimeSpan.FromSeconds(10); + public TimeSpan CallTimeout { get; set; } = TimeSpan.FromSeconds(10); public override string Identifier { get; set; } diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs index fdf776f..c652133 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs @@ -19,6 +19,7 @@ public MongoDbSnapshotOptions() : this(true) public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : base(isDefault) { Identifier = identifier; + AutoInitialize = true; } /// @@ -26,15 +27,10 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b /// public string ConnectionString { get; set; } = ""; - /// - /// Flag determining in in case of event journal or metadata table missing, they should be automatically initialized. - /// - public bool AutoInitialize { get; set; } = true; - /// /// Name of the collection for the event journal or snapshots /// - public string Collection { get; set; } = "EventJournal"; + public string Collection { get; set; } = "SnapshotStore"; /// /// Transaction @@ -44,7 +40,7 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b /// /// When true, enables BSON serialization (which breaks features like Akka.Cluster.Sharding, AtLeastOnceDelivery, and so on.) /// - public bool LegacySerialization { get; } = false; + public bool LegacySerialization { get; set; } = false; /// /// Timeout for individual database operations. @@ -52,7 +48,7 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b /// /// Defaults to 10s. /// - public TimeSpan CallTimeout { get; } = TimeSpan.FromSeconds(10); + public TimeSpan CallTimeout { get; set; } = TimeSpan.FromSeconds(10); public override string Identifier { get; set; } From a45b91be76ded26895f8f230ddfb2e93a9111adb Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Fri, 30 Jun 2023 18:45:00 +0200 Subject: [PATCH 03/15] Bit more clean up --- .../MongoDbJournalOptionsSpec.cs | 213 +++++++++--------- 1 file changed, 102 insertions(+), 111 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs index 83660ac..03dd6a6 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs @@ -1,4 +1,7 @@ -using Akka.Configuration; +using System; +using Akka.Configuration; +using Akka.Persistence.Journal; +using Akka.Util; using FluentAssertions; using Xunit; @@ -32,7 +35,15 @@ public void DefaultJournalOptionsTest() config.Should().NotBeNull(); baseConfig.Should().NotBeNull(); - AssertJournalConfig(config, baseConfig); + config.GetString("class").Should().Be(baseConfig.GetString("class")); + config.GetString("connection-string").Should().Be(baseConfig.GetString("connection-string")); + config.GetBoolean("use-write-transaction").Should().Be(baseConfig.GetBoolean("use-write-transaction")); + config.GetBoolean("auto-initialize").Should().Be(baseConfig.GetBoolean("auto-initialize")); + config.GetString("plugin-dispatcher").Should().Be(baseConfig.GetString("plugin-dispatcher")); + config.GetString("collection").Should().Be(baseConfig.GetString("collection")); + config.GetString("metadata-collection").Should().Be(baseConfig.GetString("metadata-collection")); + config.GetBoolean("legacy-serialization").Should().Be(baseConfig.GetBoolean("legacy-serialization")); + config.GetTimeSpan("call-timeout").Should().Be(baseConfig.GetTimeSpan("call-timeout")); } [Fact(DisplayName = "Empty MongoDbJournalOptions with custom identifier should equal empty config with default fallback")] @@ -50,118 +61,98 @@ public void CustomIdJournalOptionsTest() config.Should().NotBeNull(); baseConfig.Should().NotBeNull(); - AssertJournalConfig(config, baseConfig); + config.GetString("class").Should().Be(baseConfig.GetString("class")); + config.GetString("connection-string").Should().Be(baseConfig.GetString("connection-string")); + config.GetBoolean("use-write-transaction").Should().Be(baseConfig.GetBoolean("use-write-transaction")); + config.GetBoolean("auto-initialize").Should().Be(baseConfig.GetBoolean("auto-initialize")); + config.GetString("plugin-dispatcher").Should().Be(baseConfig.GetString("plugin-dispatcher")); + config.GetString("collection").Should().Be(baseConfig.GetString("collection")); + config.GetString("metadata-collection").Should().Be(baseConfig.GetString("metadata-collection")); + config.GetBoolean("legacy-serialization").Should().Be(baseConfig.GetBoolean("legacy-serialization")); + config.GetTimeSpan("call-timeout").Should().Be(baseConfig.GetTimeSpan("call-timeout")); } -// [Fact(DisplayName = "MongoDbJournalOptions should generate proper config")] -// public void JournalOptionsTest() -// { -// var options = new MongoDbJournalOptions(true) -// { -// Identifier = "custom", -// AutoInitialize = true, -// ConnectionString = "testConnection", -// Collection = "testCollection", -// MetadataCollection = "metadataCollection", -// UseWriteTransaction = true, -// LegacySerialization = true, -// CallTimeout = TimeSpan.FromHours(2) -// }; -// options.Adapters.AddWriteEventAdapter("mapper1", new[] { typeof(EventAdapters.Event1) }); -// options.Adapters.AddReadEventAdapter("reader1", new[] { typeof(EventAdapters.Event1) }); -// options.Adapters.AddEventAdapter("combo", boundTypes: new[] { typeof(EventAdapters.Event2) }); -// options.Adapters.AddWriteEventAdapter("tagger", boundTypes: new[] { typeof(EventAdapters.Event1), typeof(EventAdapters.Event2) }); - -// var baseConfig = options.ToConfig(); - -// baseConfig.GetString("akka.persistence.journal.plugin").Should().Be("akka.persistence.journal.custom"); - -// var config = baseConfig.GetConfig("akka.persistence.journal.custom"); -// config.Should().NotBeNull(); -// config.GetString("connection-string").Should().Be(options.ConnectionString); -// config.GetTimeSpan("connection-timeout").Should().Be(options.ConnectionTimeout); -// config.GetString("schema-name").Should().Be(options.SchemaName); -// config.GetString("table-name").Should().Be(options.TableName); -// config.GetBoolean("auto-initialize").Should().Be(options.AutoInitialize); -// config.GetString("metadata-table-name").Should().Be(options.MetadataTableName); -// config.GetBoolean("sequential-access").Should().Be(options.SequentialAccess); -// config.GetString("stored-as").Should().Be(options.StoredAs.ToHocon()); -// config.GetBoolean("use-bigint-identity-for-ordering-column").Should().Be(options.UseBigIntIdentityForOrderingColumn); - -// config.GetStringList($"event-adapter-bindings.\"{typeof(EventAdapters.Event1).TypeQualifiedName()}\"").Should() -// .BeEquivalentTo("mapper1", "reader1", "tagger"); -// config.GetStringList($"event-adapter-bindings.\"{typeof(EventAdapters.Event2).TypeQualifiedName()}\"").Should() -// .BeEquivalentTo("combo", "tagger"); - -// config.GetString("event-adapters.mapper1").Should().Be(typeof(EventAdapters.EventMapper1).TypeQualifiedName()); -// config.GetString("event-adapters.reader1").Should().Be(typeof(EventAdapters.ReadAdapter).TypeQualifiedName()); -// config.GetString("event-adapters.combo").Should().Be(typeof(EventAdapters.ComboAdapter).TypeQualifiedName()); -// config.GetString("event-adapters.tagger").Should().Be(typeof(EventAdapters.Tagger).TypeQualifiedName()); - -// } - -// const string Json = @" -//{ -// ""Logging"": { -// ""LogLevel"": { -// ""Default"": ""Information"", -// ""Microsoft.AspNetCore"": ""Warning"" -// } -// }, -// ""Akka"": { -// ""JournalOptions"": { -// ""StoredAs"": ""JsonB"", -// ""UseBigIntIdentityForOrderingColumn"": true, - -// ""ConnectionString"": ""Server=localhost,1533;Database=Akka;User Id=sa;"", -// ""ConnectionTimeout"": ""00:00:55"", -// ""SchemaName"": ""schema"", -// ""TableName"" : ""journal"", -// ""MetadataTableName"": ""meta"", -// ""SequentialAccess"": false, - -// ""IsDefaultPlugin"": false, -// ""Identifier"": ""custom"", -// ""AutoInitialize"": true, -// ""Serializer"": ""hyperion"" -// } -// } -//}"; - -// [Fact(DisplayName = "MongoDbJournalOptions should be bindable to IConfiguration")] -// public void JournalOptionsIConfigurationBindingTest() -// { -// using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); -// var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); - -// var options = jsonConfig.GetSection("Akka:JournalOptions").Get(); -// options.IsDefaultPlugin.Should().BeFalse(); -// options.Identifier.Should().Be("custom"); -// options.AutoInitialize.Should().BeTrue(); -// options.Serializer.Should().Be("hyperion"); -// options.ConnectionString.Should().Be("Server=localhost,1533;Database=Akka;User Id=sa;"); -// options.ConnectionTimeout.Should().Be(55.Seconds()); -// options.SchemaName.Should().Be("schema"); -// options.TableName.Should().Be("journal"); -// options.MetadataTableName.Should().Be("meta"); -// options.SequentialAccess.Should().BeFalse(); - -// options.StoredAs.Should().Be(StoredAsType.JsonB); -// options.UseBigIntIdentityForOrderingColumn.Should().BeTrue(); -// } - - - private static void AssertJournalConfig(Config underTest, Config reference) + [Fact(DisplayName = "MongoDbJournalOptions should generate proper config")] + public void JournalOptionsTest() { - underTest.GetString("class").Should().Be(reference.GetString("class")); - underTest.GetString("connection-string").Should().Be(reference.GetString("connection-string")); - underTest.GetBoolean("use-write-transaction").Should().Be(reference.GetBoolean("use-write-transaction")); - underTest.GetBoolean("auto-initialize").Should().Be(reference.GetBoolean("auto-initialize")); - underTest.GetString("plugin-dispatcher").Should().Be(reference.GetString("plugin-dispatcher")); - underTest.GetString("collection").Should().Be(reference.GetString("collection")); - underTest.GetString("metadata-collection").Should().Be(reference.GetString("metadata-collection")); - underTest.GetBoolean("legacy-serialization").Should().Be(reference.GetBoolean("legacy-serialization")); - underTest.GetTimeSpan("call-timeout").Should().Be(reference.GetTimeSpan("call-timeout")); + var options = new MongoDbJournalOptions(true) + { + Identifier = "custom", + AutoInitialize = true, + ConnectionString = "testConnection", + Collection = "testCollection", + MetadataCollection = "metadataCollection", + UseWriteTransaction = true, + LegacySerialization = true, + CallTimeout = TimeSpan.FromHours(2) + }; + + var baseConfig = options.ToConfig(); + + baseConfig.GetString("akka.persistence.journal.plugin").Should().Be("akka.persistence.journal.custom"); + + var config = baseConfig.GetConfig("akka.persistence.journal.custom"); + config.Should().NotBeNull(); + config.GetString("connection-string").Should().Be(options.ConnectionString); + config.GetBoolean("auto-initialize").Should().Be(options.AutoInitialize); + config.GetString("collection").Should().Be(options.Collection); + config.GetString("metadata-collection").Should().Be(options.MetadataCollection); + config.GetBoolean("use-write-transaction").Should().Be(options.UseWriteTransaction); + config.GetBoolean("legacy-serialization").Should().Be(options.LegacySerialization); + config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout); + } + + // const string Json = @" + //{ + // ""Logging"": { + // ""LogLevel"": { + // ""Default"": ""Information"", + // ""Microsoft.AspNetCore"": ""Warning"" + // } + // }, + // ""Akka"": { + // ""JournalOptions"": { + // ""StoredAs"": ""JsonB"", + // ""UseBigIntIdentityForOrderingColumn"": true, + + // ""ConnectionString"": ""Server=localhost,1533;Database=Akka;User Id=sa;"", + // ""ConnectionTimeout"": ""00:00:55"", + // ""SchemaName"": ""schema"", + // ""TableName"" : ""journal"", + // ""MetadataTableName"": ""meta"", + // ""SequentialAccess"": false, + + // ""IsDefaultPlugin"": false, + // ""Identifier"": ""custom"", + // ""AutoInitialize"": true, + // ""Serializer"": ""hyperion"" + // } + // } + //}"; + + // [Fact(DisplayName = "MongoDbJournalOptions should be bindable to IConfiguration")] + // public void JournalOptionsIConfigurationBindingTest() + // { + // using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); + // var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); + + // var options = jsonConfig.GetSection("Akka:JournalOptions").Get(); + // options.IsDefaultPlugin.Should().BeFalse(); + // options.Identifier.Should().Be("custom"); + // options.AutoInitialize.Should().BeTrue(); + // options.Serializer.Should().Be("hyperion"); + // options.ConnectionString.Should().Be("Server=localhost,1533;Database=Akka;User Id=sa;"); + // options.ConnectionTimeout.Should().Be(55.Seconds()); + // options.SchemaName.Should().Be("schema"); + // options.TableName.Should().Be("journal"); + // options.MetadataTableName.Should().Be("meta"); + // options.SequentialAccess.Should().BeFalse(); + + // options.StoredAs.Should().Be(StoredAsType.JsonB); + // options.UseBigIntIdentityForOrderingColumn.Should().BeTrue(); + // } + + } } \ No newline at end of file From cff5a0238f81033228bb6732076064567bc515b1 Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Sun, 2 Jul 2023 17:33:26 +0200 Subject: [PATCH 04/15] Final Tests --- .../MongoDbJournalOptionsSpec.cs | 101 ++++++++---------- .../MongoDbSnapshotOptionsSpec.cs | 89 +++++++-------- 2 files changed, 92 insertions(+), 98 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs index 03dd6a6..2817690 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs @@ -1,15 +1,16 @@ using System; +using System.IO; +using System.Text; using Akka.Configuration; -using Akka.Persistence.Journal; -using Akka.Util; using FluentAssertions; +using FluentAssertions.Extensions; +using Microsoft.Extensions.Configuration; using Xunit; namespace Akka.Persistence.MongoDb.Hosting.Tests { public class MongoDbJournalOptionsSpec { - [Fact(DisplayName = "MongoDbJournalOptions as default plugin should generate plugin setting")] public void DefaultPluginJournalOptionsTest() { @@ -103,56 +104,48 @@ public void JournalOptionsTest() } - // const string Json = @" - //{ - // ""Logging"": { - // ""LogLevel"": { - // ""Default"": ""Information"", - // ""Microsoft.AspNetCore"": ""Warning"" - // } - // }, - // ""Akka"": { - // ""JournalOptions"": { - // ""StoredAs"": ""JsonB"", - // ""UseBigIntIdentityForOrderingColumn"": true, - - // ""ConnectionString"": ""Server=localhost,1533;Database=Akka;User Id=sa;"", - // ""ConnectionTimeout"": ""00:00:55"", - // ""SchemaName"": ""schema"", - // ""TableName"" : ""journal"", - // ""MetadataTableName"": ""meta"", - // ""SequentialAccess"": false, - - // ""IsDefaultPlugin"": false, - // ""Identifier"": ""custom"", - // ""AutoInitialize"": true, - // ""Serializer"": ""hyperion"" - // } - // } - //}"; - - // [Fact(DisplayName = "MongoDbJournalOptions should be bindable to IConfiguration")] - // public void JournalOptionsIConfigurationBindingTest() - // { - // using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); - // var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); - - // var options = jsonConfig.GetSection("Akka:JournalOptions").Get(); - // options.IsDefaultPlugin.Should().BeFalse(); - // options.Identifier.Should().Be("custom"); - // options.AutoInitialize.Should().BeTrue(); - // options.Serializer.Should().Be("hyperion"); - // options.ConnectionString.Should().Be("Server=localhost,1533;Database=Akka;User Id=sa;"); - // options.ConnectionTimeout.Should().Be(55.Seconds()); - // options.SchemaName.Should().Be("schema"); - // options.TableName.Should().Be("journal"); - // options.MetadataTableName.Should().Be("meta"); - // options.SequentialAccess.Should().BeFalse(); - - // options.StoredAs.Should().Be(StoredAsType.JsonB); - // options.UseBigIntIdentityForOrderingColumn.Should().BeTrue(); - // } - - + const string Json = @" + { + ""Logging"": { + ""LogLevel"": { + ""Default"": ""Information"", + ""Microsoft.AspNetCore"": ""Warning"" + } + }, + ""Akka"": { + ""JournalOptions"": { + ""ConnectionString"": ""mongodb://localhost:27017"", + ""UseWriteTransaction"": ""true"", + ""Identifier"": ""custommongodb"", + ""AutoInitialize"": true, + ""IsDefaultPlugin"": false, + + ""Collection"": ""CustomEnventJournalCollection"", + ""MetadataCollection"": ""CustomMetadataCollection"", + ""LegacySerialization"" : ""true"", + ""CallTimeout"": ""00:10:00"", + ""Serializer"": ""hyperion"", + } + } + }"; + + [Fact(DisplayName = "MongoDbJournalOptions should be bindable to IConfiguration")] + public void JournalOptionsIConfigurationBindingTest() + { + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); + var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); + + var options = jsonConfig.GetSection("Akka:JournalOptions").Get(); + options.ConnectionString.Should().Be("mongodb://localhost:27017"); + options.UseWriteTransaction.Should().BeTrue(); + options.Identifier.Should().Be("custommongodb"); + options.AutoInitialize.Should().BeTrue(); + options.IsDefaultPlugin.Should().BeFalse(); + options.Collection.Should().Be("CustomEnventJournalCollection"); + options.MetadataCollection.Should().Be("CustomMetadataCollection"); + options.LegacySerialization.Should().BeTrue(); + options.CallTimeout.Should().Be(10.Minutes()); + options.Serializer.Should().Be("hyperion"); + } } } \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs index fd5a5be..3543f2d 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs @@ -1,6 +1,10 @@ using System; +using System.IO; +using System.Text; using Akka.Configuration; using FluentAssertions; +using FluentAssertions.Extensions; +using Microsoft.Extensions.Configuration; using Xunit; namespace Akka.Persistence.MongoDb.Hosting.Tests @@ -96,49 +100,46 @@ public void SnapshotOptionsTest() config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout); } -// [Fact(DisplayName = "MongoDbSnapshotOptions should be bindable to IConfiguration")] -// public void SnapshotOptionsIConfigurationBindingTest() -// { -// const string json = @" -//{ -// ""Logging"": { -// ""LogLevel"": { -// ""Default"": ""Information"", -// ""Microsoft.AspNetCore"": ""Warning"" -// } -// }, -// ""Akka"": { -// ""SnapshotOptions"": { -// ""StoredAs"": ""JsonB"", - -// ""ConnectionString"": ""Server=localhost,1533;Database=Akka;User Id=sa;"", -// ""ConnectionTimeout"": ""00:00:55"", -// ""SchemaName"": ""schema"", -// ""TableName"" : ""snapshot"", -// ""SequentialAccess"": false, - -// ""IsDefaultPlugin"": false, -// ""Identifier"": ""CustomSnapshot"", -// ""AutoInitialize"": true, -// ""Serializer"": ""hyperion"" -// } -// } -//}"; -// using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); -// var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); - -// var options = jsonConfig.GetSection("Akka:SnapshotOptions").Get(); -// options.IsDefaultPlugin.Should().BeFalse(); -// options.Identifier.Should().Be("CustomSnapshot"); -// options.AutoInitialize.Should().BeTrue(); -// options.Serializer.Should().Be("hyperion"); -// options.ConnectionString.Should().Be("Server=localhost,1533;Database=Akka;User Id=sa;"); -// options.ConnectionTimeout.Should().Be(55.Seconds()); -// options.SchemaName.Should().Be("schema"); -// options.TableName.Should().Be("snapshot"); -// options.SequentialAccess.Should().BeFalse(); - -// options.StoredAs.Should().Be(StoredAsType.JsonB); -// } + [Fact(DisplayName = "MongoDbSnapshotOptions should be bindable to IConfiguration")] + public void SnapshotOptionsIConfigurationBindingTest() + { + const string json = @" + { + ""Logging"": { + ""LogLevel"": { + ""Default"": ""Information"", + ""Microsoft.AspNetCore"": ""Warning"" + } + }, + ""Akka"": { + ""SnapshotOptions"": { + ""ConnectionString"": ""mongodb://localhost:27017"", + ""UseWriteTransaction"": ""true"", + ""Identifier"": ""custommongodb"", + ""AutoInitialize"": true, + ""IsDefaultPlugin"": false, + + ""Collection"": ""CustomEnventJournalCollection"", + ""LegacySerialization"" : ""true"", + ""CallTimeout"": ""00:10:00"", + ""Serializer"": ""hyperion"", + } + } + }"; + + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); + + var options = jsonConfig.GetSection("Akka:SnapshotOptions").Get(); + options.ConnectionString.Should().Be("mongodb://localhost:27017"); + options.UseWriteTransaction.Should().BeTrue(); + options.Identifier.Should().Be("custommongodb"); + options.AutoInitialize.Should().BeTrue(); + options.IsDefaultPlugin.Should().BeFalse(); + options.Collection.Should().Be("CustomEnventJournalCollection"); + options.LegacySerialization.Should().BeTrue(); + options.CallTimeout.Should().Be(10.Minutes()); + options.Serializer.Should().Be("hyperion"); + } } } \ No newline at end of file From ec4ae98fdaee735ba73641b327f8ff22d7b0603e Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Sun, 2 Jul 2023 17:33:40 +0200 Subject: [PATCH 05/15] Whitespace clean up --- .../AkkaPersistenceMongoDbHostingExtensions.cs | 1 - src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs | 1 - src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs b/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs index 62b17fe..c5e8ed5 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs @@ -57,7 +57,6 @@ public static class AkkaPersistenceMongoDbHostingExtensions public static AkkaConfigurationBuilder WithMongoDbPersistence( this AkkaConfigurationBuilder builder, string connectionString, - PersistenceMode mode = PersistenceMode.Both, bool autoInitialize = true, Action? journalBuilder = null, diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs index 96dab5c..5607d76 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs @@ -55,7 +55,6 @@ public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : ba /// public TimeSpan CallTimeout { get; set; } = TimeSpan.FromSeconds(10); - public override string Identifier { get; set; } protected override Config InternalDefaultConfig { get; } = Default; diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs index c652133..02176e3 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs @@ -50,7 +50,6 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b /// public TimeSpan CallTimeout { get; set; } = TimeSpan.FromSeconds(10); - public override string Identifier { get; set; } protected override Config InternalDefaultConfig { get; } = Default; From 8ef8efd7e6faf6e8034a1315b597aa9754d789a4 Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Sun, 2 Jul 2023 17:33:49 +0200 Subject: [PATCH 06/15] Addition of a readme --- .../README.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/Akka.Persistence.MongoDb.Hosting/README.md diff --git a/src/Akka.Persistence.MongoDb.Hosting/README.md b/src/Akka.Persistence.MongoDb.Hosting/README.md new file mode 100644 index 0000000..dc6be96 --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Hosting/README.md @@ -0,0 +1,41 @@ +# Akka.Persistence.MongoDb.Hosting + +Akka.Hosting extension methods to add Akka.Persistence.MongoDb to an ActorSystem + +# Akka.Persistence.MongoDb Extension Methods + +## WithMongoDbPersistence() Method + +```csharp +public static AkkaConfigurationBuilder WithMongoDbPersistence( + this AkkaConfigurationBuilder builder, + string connectionString, + PersistenceMode mode = PersistenceMode.Both, + bool autoInitialize = true, + Action? journalBuilder = null, + string pluginIdentifier = "mongodb", + bool isDefaultPlugin = true); +``` + +### Parameters + +* `connectionString` __string__ + + Connection string used for database access. + +* `mode` __PersistenceMode__ + + Determines which settings should be added by this method call. __Default__: `PersistenceMode.Both` + + * `PersistenceMode.Journal`: Only add the journal settings + * `PersistenceMode.SnapshotStore`: Only add the snapshot store settings + * `PersistenceMode.Both`: Add both journal and snapshot store settings + +* `autoInitialize` __bool__ + + Should the Mongo Db store collection be initialized automatically. __Default__: `false` + +* `configurator` __Action\__ + + An Action delegate used to configure an `AkkaPersistenceJournalBuilder` instance. Used to configure [Event Adapters](https://getakka.net/articles/persistence/event-adapters.html) + From 469a32b5ad59211b0ed1901a5af82f6ca2e1f259 Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Sun, 2 Jul 2023 17:36:40 +0200 Subject: [PATCH 07/15] Adding NetFrameworkTestVersion --- .../Akka.Persistence.MongoDb.Hosting.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj b/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj index 028aa59..ccb3f85 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj @@ -2,7 +2,7 @@ - $(NetTestVersion);$(NetCoreTestVersion) + $(NetFrameworkTestVersion);$(NetTestVersion);$(NetCoreTestVersion) From fdd3debd282576f78f8e2ed4b807a77f3b976cad Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Sun, 2 Jul 2023 18:12:59 +0200 Subject: [PATCH 08/15] Changes due to not being able to use using declarations --- .../MongoDbJournalOptionsSpec.cs | 6 ++++-- .../MongoDbSnapshotOptionsSpec.cs | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs index 2817690..0c3e8e8 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs @@ -101,7 +101,6 @@ public void JournalOptionsTest() config.GetBoolean("use-write-transaction").Should().Be(options.UseWriteTransaction); config.GetBoolean("legacy-serialization").Should().Be(options.LegacySerialization); config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout); - } const string Json = @" @@ -132,7 +131,7 @@ public void JournalOptionsTest() [Fact(DisplayName = "MongoDbJournalOptions should be bindable to IConfiguration")] public void JournalOptionsIConfigurationBindingTest() { - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); + var stream = new MemoryStream(Encoding.UTF8.GetBytes(Json)); var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); var options = jsonConfig.GetSection("Akka:JournalOptions").Get(); @@ -146,6 +145,9 @@ public void JournalOptionsIConfigurationBindingTest() options.LegacySerialization.Should().BeTrue(); options.CallTimeout.Should().Be(10.Minutes()); options.Serializer.Should().Be("hyperion"); + + // Dispose called here as project not using latest language features. + stream.Dispose(); } } } \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs index 3543f2d..2ef643b 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs @@ -127,7 +127,7 @@ public void SnapshotOptionsIConfigurationBindingTest() } }"; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); + var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); var jsonConfig = new ConfigurationBuilder().AddJsonStream(stream).Build(); var options = jsonConfig.GetSection("Akka:SnapshotOptions").Get(); @@ -140,6 +140,9 @@ public void SnapshotOptionsIConfigurationBindingTest() options.LegacySerialization.Should().BeTrue(); options.CallTimeout.Should().Be(10.Minutes()); options.Serializer.Should().Be("hyperion"); + + // Dispose called here as project not using latest language features. + stream.Dispose(); } } } \ No newline at end of file From 6ffaaf107ba80d0ba3f97a3dad2b7a752fee7322 Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Wed, 12 Jul 2023 08:45:21 +0200 Subject: [PATCH 09/15] Clean up whitespace And to get the build to run again --- .../MongoDbJournalOptionsSpec.cs | 1 - .../MongoDbSnapshotOptionsSpec.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs index 0c3e8e8..333a7c6 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs @@ -118,7 +118,6 @@ public void JournalOptionsTest() ""Identifier"": ""custommongodb"", ""AutoInitialize"": true, ""IsDefaultPlugin"": false, - ""Collection"": ""CustomEnventJournalCollection"", ""MetadataCollection"": ""CustomMetadataCollection"", ""LegacySerialization"" : ""true"", diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs index 2ef643b..ec995f6 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs @@ -118,7 +118,6 @@ public void SnapshotOptionsIConfigurationBindingTest() ""Identifier"": ""custommongodb"", ""AutoInitialize"": true, ""IsDefaultPlugin"": false, - ""Collection"": ""CustomEnventJournalCollection"", ""LegacySerialization"" : ""true"", ""CallTimeout"": ""00:10:00"", From 655d3f7128ea2d1d9196860cc9e11eeb6848464d Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Mon, 17 Jul 2023 07:43:53 +0200 Subject: [PATCH 10/15] Explicitly set the default --- src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs | 2 +- src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs index 5607d76..5fd3b82 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs @@ -40,7 +40,7 @@ public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : ba /// /// Transaction /// - public bool UseWriteTransaction { get; set; } + public bool UseWriteTransaction { get; set; } = false; /// /// When true, enables BSON serialization (which breaks features like Akka.Cluster.Sharding, AtLeastOnceDelivery, and so on.) diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs index 02176e3..5636f09 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs @@ -35,7 +35,7 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b /// /// Transaction /// - public bool UseWriteTransaction { get; set; } + public bool UseWriteTransaction { get; set; } = false; /// /// When true, enables BSON serialization (which breaks features like Akka.Cluster.Sharding, AtLeastOnceDelivery, and so on.) From 38be7dff313135ff5ee85f9eeb33a2666f3c1c7e Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Mon, 17 Jul 2023 07:44:47 +0200 Subject: [PATCH 11/15] Move tests into current test project --- Akka.Persistence.MongoDb.sln | 6 ----- ...a.Persistence.MongoDb.Hosting.Tests.csproj | 22 ------------------- .../Akka.Persistence.MongoDb.Tests.csproj | 5 +++-- .../Hosting}/MongoDbJournalOptionsSpec.cs | 3 ++- .../Hosting}/MongoDbSnapshotOptionsSpec.cs | 0 5 files changed, 5 insertions(+), 31 deletions(-) delete mode 100644 src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj rename src/{Akka.Persistence.MongoDb.Hosting.Tests => Akka.Persistence.MongoDb.Tests/Hosting}/MongoDbJournalOptionsSpec.cs (98%) rename src/{Akka.Persistence.MongoDb.Hosting.Tests => Akka.Persistence.MongoDb.Tests/Hosting}/MongoDbSnapshotOptionsSpec.cs (100%) diff --git a/Akka.Persistence.MongoDb.sln b/Akka.Persistence.MongoDb.sln index 4c6140b..7ff99fb 100644 --- a/Akka.Persistence.MongoDb.sln +++ b/Akka.Persistence.MongoDb.sln @@ -17,8 +17,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{BE1178E1 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.MongoDb.Hosting", "src\Akka.Persistence.MongoDb.Hosting\Akka.Persistence.MongoDb.Hosting.csproj", "{72B8C165-FE00-465F-A2E9-60B4B79F81AF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.Persistence.MongoDb.Hosting.Tests", "src\Akka.Persistence.MongoDb.Hosting.Tests\Akka.Persistence.MongoDb.Hosting.Tests.csproj", "{7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -37,10 +35,6 @@ Global {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {72B8C165-FE00-465F-A2E9-60B4B79F81AF}.Release|Any CPU.Build.0 = Release|Any CPU - {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7DA742BE-BE29-48E3-AA6D-D06C9D7C6464}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj b/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj deleted file mode 100644 index ccb3f85..0000000 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/Akka.Persistence.MongoDb.Hosting.Tests.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - - $(NetFrameworkTestVersion);$(NetTestVersion);$(NetCoreTestVersion) - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj b/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj index b132dfd..91d24aa 100644 --- a/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj +++ b/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj @@ -1,7 +1,7 @@ - + - + $(NetFrameworkTestVersion);$(NetTestVersion);$(NetCoreTestVersion) @@ -18,6 +18,7 @@ + diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbJournalOptionsSpec.cs similarity index 98% rename from src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs rename to src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbJournalOptionsSpec.cs index 333a7c6..61a856b 100644 --- a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbJournalOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbJournalOptionsSpec.cs @@ -2,12 +2,13 @@ using System.IO; using System.Text; using Akka.Configuration; +using Akka.Persistence.MongoDb.Hosting; using FluentAssertions; using FluentAssertions.Extensions; using Microsoft.Extensions.Configuration; using Xunit; -namespace Akka.Persistence.MongoDb.Hosting.Tests +namespace Akka.Persistence.MongoDb.Tests.Hosting { public class MongoDbJournalOptionsSpec { diff --git a/src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbSnapshotOptionsSpec.cs similarity index 100% rename from src/Akka.Persistence.MongoDb.Hosting.Tests/MongoDbSnapshotOptionsSpec.cs rename to src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbSnapshotOptionsSpec.cs From 7c6a94eb4a25d3250bee4867964ea1a7a5d5847c Mon Sep 17 00:00:00 2001 From: Michael Buck Date: Mon, 17 Jul 2023 07:51:32 +0200 Subject: [PATCH 12/15] FluentAssertions version in Common props --- .../Akka.Persistence.MongoDb.Tests.csproj | 1 + src/common.props | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj b/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj index 91d24aa..7d7bdd5 100644 --- a/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj +++ b/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj @@ -6,6 +6,7 @@ + all diff --git a/src/common.props b/src/common.props index cac50d1..8a10f41 100644 --- a/src/common.props +++ b/src/common.props @@ -22,6 +22,7 @@ 2.4.2 17.6.3 1.5.8 + 6.11.0 From 90beb719ab5e46b6d5048e536ae128514a4aafa0 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Mon, 17 Jul 2023 21:59:03 +0700 Subject: [PATCH 13/15] Make sure that Persistence.Query default hocon configurations are loaded --- .../AkkaPersistenceMongoDbHostingExtensions.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs b/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs index c5e8ed5..b4b6ae5 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/AkkaPersistenceMongoDbHostingExtensions.cs @@ -195,7 +195,8 @@ public static AkkaConfigurationBuilder WithMongoDbPersistence( (_, null) => builder .AddHocon(journalOptions.ToConfig(), HoconAddMode.Prepend) - .AddHocon(journalOptions.DefaultConfig, HoconAddMode.Append), + .AddHocon(journalOptions.DefaultConfig, HoconAddMode.Append) + .AddHocon(MongoDbPersistence.DefaultConfiguration(), HoconAddMode.Append), (null, _) => builder @@ -207,7 +208,8 @@ public static AkkaConfigurationBuilder WithMongoDbPersistence( .AddHocon(journalOptions.ToConfig(), HoconAddMode.Prepend) .AddHocon(snapshotOptions.ToConfig(), HoconAddMode.Prepend) .AddHocon(journalOptions.DefaultConfig, HoconAddMode.Append) - .AddHocon(snapshotOptions.DefaultConfig, HoconAddMode.Append), + .AddHocon(snapshotOptions.DefaultConfig, HoconAddMode.Append) + .AddHocon(MongoDbPersistence.DefaultConfiguration(), HoconAddMode.Append), }; } } \ No newline at end of file From 472d99144cd3634a46ea5eec3cfa6a662883e2f4 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Mon, 17 Jul 2023 22:00:03 +0700 Subject: [PATCH 14/15] Switch to optional addition to prevent user config clobbering problem --- .../MongoDbJournalOptions.cs | 33 ++++++++++++------- .../MongoDbSnapshotOptions.cs | 25 +++++++++----- .../Hosting/MongoDbJournalOptionsSpec.cs | 6 ++-- .../Hosting/MongoDbSnapshotOptionsSpec.cs | 9 ++--- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs index 5fd3b82..1984dbf 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbJournalOptions.cs @@ -16,7 +16,7 @@ public MongoDbJournalOptions() : this(true) { } - public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : base(isDefault) + public MongoDbJournalOptions(bool isDefaultPlugin, string identifier = "mongodb") : base(isDefaultPlugin) { Identifier = identifier; AutoInitialize = true; @@ -30,22 +30,22 @@ public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : ba /// /// Name of the collection for the event journal or snapshots /// - public string Collection { get; set; } = "EventJournal"; + public string? Collection { get; set; } /// /// Name of the collection for the event journal metadata /// - public string MetadataCollection { get; set; } = "Metadata"; + public string? MetadataCollection { get; set; } /// /// Transaction /// - public bool UseWriteTransaction { get; set; } = false; + public bool? UseWriteTransaction { get; set; } /// /// When true, enables BSON serialization (which breaks features like Akka.Cluster.Sharding, AtLeastOnceDelivery, and so on.) /// - public bool LegacySerialization { get; set; } = false; + public bool? LegacySerialization { get; set; } /// /// Timeout for individual database operations. @@ -53,7 +53,7 @@ public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : ba /// /// Defaults to 10s. /// - public TimeSpan CallTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan? CallTimeout { get; set; } public override string Identifier { get; set; } protected override Config InternalDefaultConfig { get; } = Default; @@ -61,12 +61,21 @@ public MongoDbJournalOptions(bool isDefault, string identifier = "mongodb") : ba protected override StringBuilder Build(StringBuilder sb) { sb.AppendLine($"connection-string = {ConnectionString.ToHocon()}"); - sb.AppendLine($"use-write-transaction = {(UseWriteTransaction ? "on" : "off")}"); - sb.AppendLine($"auto-initialize = {(AutoInitialize ? "on" : "off")}"); - sb.AppendLine($"collection = {Collection.ToHocon()}"); - sb.AppendLine($"metadata-collection = {MetadataCollection.ToHocon()}"); - sb.AppendLine($"legacy-serialization = {(LegacySerialization ? "on" : "off")}"); - sb.AppendLine($"call-timeout = {CallTimeout.ToHocon()}"); + + if(Collection is not null) + sb.AppendLine($"collection = {Collection.ToHocon()}"); + + if(MetadataCollection is not null) + sb.AppendLine($"metadata-collection = {MetadataCollection.ToHocon()}"); + + if(CallTimeout is not null) + sb.AppendLine($"call-timeout = {CallTimeout.ToHocon()}"); + + if(UseWriteTransaction is not null) + sb.AppendLine($"use-write-transaction = {UseWriteTransaction.ToHocon()}"); + + if(LegacySerialization is not null) + sb.AppendLine($"legacy-serialization = {LegacySerialization.ToHocon()}"); return base.Build(sb); } diff --git a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs index 5636f09..d5ca43d 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs +++ b/src/Akka.Persistence.MongoDb.Hosting/MongoDbSnapshotOptions.cs @@ -30,17 +30,17 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b /// /// Name of the collection for the event journal or snapshots /// - public string Collection { get; set; } = "SnapshotStore"; + public string? Collection { get; set; } /// /// Transaction /// - public bool UseWriteTransaction { get; set; } = false; + public bool? UseWriteTransaction { get; set; } /// /// When true, enables BSON serialization (which breaks features like Akka.Cluster.Sharding, AtLeastOnceDelivery, and so on.) /// - public bool LegacySerialization { get; set; } = false; + public bool? LegacySerialization { get; set; } /// /// Timeout for individual database operations. @@ -48,7 +48,7 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b /// /// Defaults to 10s. /// - public TimeSpan CallTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan? CallTimeout { get; set; } public override string Identifier { get; set; } protected override Config InternalDefaultConfig { get; } = Default; @@ -56,11 +56,18 @@ public MongoDbSnapshotOptions(bool isDefault, string identifier = "mongodb") : b protected override StringBuilder Build(StringBuilder sb) { sb.AppendLine($"connection-string = {ConnectionString.ToHocon()}"); - sb.AppendLine($"use-write-transaction = {(UseWriteTransaction ? "on" : "off")}"); - sb.AppendLine($"auto-initialize = {(AutoInitialize ? "on" : "off")}"); - sb.AppendLine($"collection = {Collection.ToHocon()}"); - sb.AppendLine($"legacy-serialization = {(LegacySerialization ? "on" : "off")}"); - sb.AppendLine($"call-timeout = {CallTimeout.ToHocon()}"); + + if(UseWriteTransaction is not null) + sb.AppendLine($"use-write-transaction = {UseWriteTransaction.ToHocon()}"); + + if(Collection is not null) + sb.AppendLine($"collection = {Collection.ToHocon()}"); + + if(LegacySerialization is not null) + sb.AppendLine($"legacy-serialization = {LegacySerialization.ToHocon()}"); + + if(CallTimeout is not null) + sb.AppendLine($"call-timeout = {CallTimeout.ToHocon()}"); return base.Build(sb); } diff --git a/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbJournalOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbJournalOptionsSpec.cs index 61a856b..4defb24 100644 --- a/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbJournalOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbJournalOptionsSpec.cs @@ -99,9 +99,9 @@ public void JournalOptionsTest() config.GetBoolean("auto-initialize").Should().Be(options.AutoInitialize); config.GetString("collection").Should().Be(options.Collection); config.GetString("metadata-collection").Should().Be(options.MetadataCollection); - config.GetBoolean("use-write-transaction").Should().Be(options.UseWriteTransaction); - config.GetBoolean("legacy-serialization").Should().Be(options.LegacySerialization); - config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout); + config.GetBoolean("use-write-transaction").Should().Be(options.UseWriteTransaction.Value); + config.GetBoolean("legacy-serialization").Should().Be(options.LegacySerialization.Value); + config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout.Value); } const string Json = @" diff --git a/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbSnapshotOptionsSpec.cs b/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbSnapshotOptionsSpec.cs index ec995f6..fd02cd7 100644 --- a/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbSnapshotOptionsSpec.cs +++ b/src/Akka.Persistence.MongoDb.Tests/Hosting/MongoDbSnapshotOptionsSpec.cs @@ -2,12 +2,13 @@ using System.IO; using System.Text; using Akka.Configuration; +using Akka.Persistence.MongoDb.Hosting; using FluentAssertions; using FluentAssertions.Extensions; using Microsoft.Extensions.Configuration; using Xunit; -namespace Akka.Persistence.MongoDb.Hosting.Tests +namespace Akka.Persistence.MongoDb.Tests.Hosting { public class MongoDbSnapshotOptionsSpec { @@ -95,9 +96,9 @@ public void SnapshotOptionsTest() config.GetString("connection-string").Should().Be(options.ConnectionString); config.GetBoolean("auto-initialize").Should().Be(options.AutoInitialize); config.GetString("collection").Should().Be(options.Collection); - config.GetBoolean("use-write-transaction").Should().Be(options.UseWriteTransaction); - config.GetBoolean("legacy-serialization").Should().Be(options.LegacySerialization); - config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout); + config.GetBoolean("use-write-transaction").Should().Be(options.UseWriteTransaction.Value); + config.GetBoolean("legacy-serialization").Should().Be(options.LegacySerialization.Value); + config.GetTimeSpan("call-timeout").Should().Be(options.CallTimeout.Value); } [Fact(DisplayName = "MongoDbSnapshotOptions should be bindable to IConfiguration")] From f32eabee1cb402b3e69470201763bf96e3ec0c4c Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Mon, 17 Jul 2023 22:18:33 +0700 Subject: [PATCH 15/15] Improve documentation --- .../README.md | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Akka.Persistence.MongoDb.Hosting/README.md b/src/Akka.Persistence.MongoDb.Hosting/README.md index dc6be96..8305f8d 100644 --- a/src/Akka.Persistence.MongoDb.Hosting/README.md +++ b/src/Akka.Persistence.MongoDb.Hosting/README.md @@ -17,6 +17,21 @@ public static AkkaConfigurationBuilder WithMongoDbPersistence( bool isDefaultPlugin = true); ``` +```csharp +public static AkkaConfigurationBuilder WithMongoDbPersistence( + this AkkaConfigurationBuilder builder, + Action? journalOptionConfigurator = null, + Action? snapshotOptionConfigurator = null, + bool isDefaultPlugin = true) +``` + +```csharp +public static AkkaConfigurationBuilder WithMongoDbPersistence( + this AkkaConfigurationBuilder builder, + MongoDbJournalOptions? journalOptions = null, + MongoDbSnapshotOptions? snapshotOptions = null) +``` + ### Parameters * `connectionString` __string__ @@ -35,7 +50,38 @@ public static AkkaConfigurationBuilder WithMongoDbPersistence( Should the Mongo Db store collection be initialized automatically. __Default__: `false` -* `configurator` __Action\__ +* `journalBuilder` __Action\__ An Action delegate used to configure an `AkkaPersistenceJournalBuilder` instance. Used to configure [Event Adapters](https://getakka.net/articles/persistence/event-adapters.html) +* `journalConfigurator` __Action\__ + + An Action delegate to configure a `MongoDbJournalOptions` instance. + +* `snapshotConfigurator` __Action\__ + + An Action delegate to configure a `MongoDbSnapshotOptions` instance. + +* `journalOptions` __MongoDbJournalOptions__ + + An `MongoDbJournalOptions` instance to configure the SqlServer journal. + +* `snapshotOptions` __MongoDbSnapshotOptions__ + + An `MongoDbSnapshotOptions` instance to configure the SqlServer snapshot store. + +## Example + +```csharp +using var host = new HostBuilder() + .ConfigureServices((context, services) => + { + services.AddAkka("mongoDbDemo", (builder, provider) => + { + builder + .WithMongoDbPersistence("your-mongodb-connection-string"); + }); + }).Build(); + +await host.RunAsync(); +``` \ No newline at end of file