How does the ABP supports mongodb's multi-document transactions? I encountered the following problem when I specified the mongodb's connection string with "readPreference=secondaryPreferred", is there any solution to this issue, e.g., auto switch to ".WithReadPreference(ReadPreference.Primary)" when encountering a multi-document transaction and the connection string was specified with "readPreference=secondaryPreferred". I noticed that adding a tenant and adding a tenant's admin user is a multi-document transaction in your tenant module.
- ABP Framework version: v4.4.3
- UI type: Angular
- DB provider: MongoDB
- Tiered (MVC) or Identity Server Separated (Angular): yes
- Exception message and stack trace:
* Unhandled exception. System.InvalidOperationException: **Read preference in a transaction must be primary**.
at MongoDB.Driver.MongoCollectionImpl`1.CreateReadBinding(IClientSessionHandle session, ReadPreference readPreference)
at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperationAsync[TResult](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.AggregateAsync[TResult](IClientSessionHandle session, PipelineDefinition`2 pipeline, AggregateOptions options, CancellationToken cancellationToken)
at MongoDB.Driver.IAsyncCursorSourceExtensions.ToListAsync[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken)
at Volo.Abp.SettingManagement.MongoDB.MongoSettingRepository.GetListAsync(String providerName, String providerKey, CancellationToken cancellationToken)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Volo.Abp.SettingManagement.SettingManagementStore.SetCacheItemsAsync(String providerName, String providerKey, String currentName, SettingCacheItem currentCacheItem)
at Volo.Abp.SettingManagement.SettingManagementStore.GetCacheItemAsync(String name, String providerName, String providerKey)
at Volo.Abp.SettingManagement.SettingManagementStore.GetOrNullAsync(String name, String providerName, String providerKey)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Volo.Abp.Settings.TenantSettingValueProvider.GetOrNullAsync(SettingDefinition setting)
at Volo.Abp.Settings.SettingProvider.GetOrNullValueFromProvidersAsync(IEnumerable`1 providers, SettingDefinition setting)
at Volo.Abp.Settings.SettingProvider.GetOrNullAsync(String name)
at Volo.Abp.Settings.SettingProviderExtensions.GetAsync[T](ISettingProvider settingProvider, String name, T defaultValue)
at Volo.Abp.Identity.AbpIdentityOptionsManager.OverrideOptionsAsync(String name, IdentityOptions options)
at Volo.Abp.Identity.IdentityDataSeeder.SeedAsync(String adminEmail, String adminPassword, Nullable`1 tenantId)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Volo.Abp.Data.DataSeeder.SeedAsync(DataSeedContext context)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapter.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at TechInvest.Chat.Data.ChatDbMigrationService.SeedDataAsync(Tenant tenant) in /src/src/TechInvest.Chat.Domain/Data/ChatDbMigrationService.cs:line 97
at TechInvest.Chat.Data.ChatDbMigrationService.MigrateAsync() in /src/src/TechInvest.Chat.Domain/Data/ChatDbMigrationService.cs:line 47
at TechInvest.Chat.DbMigrator.DbMigratorHostedService.StartAsync(CancellationToken cancellationToken) in /src/src/TechInvest.Chat.DbMigrator/DbMigratorHostedService.cs:line 44
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
- Steps to reproduce the issue:"
1 Answer(s)
-
1
hi
auto switch to ".WithReadPreference(ReadPreference.Primary)" when encountering a multi-document transaction and the connection string was specified with "readPreference=secondaryPreferred". I noticed that adding a tenant and adding a tenant's admin user is a multi-document transaction in your tenant module.
Maybe you can consider to custom the
IConnectionStringResolver
.https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Data/Volo/Abp/Data/IConnectionStringResolver.cs