Open Closed

Inability to use sqlOptions.EnableRetryOnFailure() causes unstable cloud behavior #9538


User avatar
0
Vince.Scholt created

Azure and Microsoft recommend the use of retry functionality when accessing databases in the cloud. When trying to use sqlOptions.EnableRetryOnFailure() in an ABP project, it causes OpenIddict inside ABP to misbehave due to the database queries not being wrapped in a way that allows the auto-retry to function. As a result, either we have to wrap each and every database use in the application, or not use retry functionality at all. Neither is a viable solution for a production environment in the cloud.

In responce i tried to work around it by having 2 DBContexts pointing to the same database, one for the tools, the other with auto retry for our own code. Sadly this then failed to resolve DBContexts to i assume this is not a possible route either.

Is there a viable workaround for this hat we are not aware of? Otherwise we will have to stop using ABP altogether just for being incompatible with cloud stability. Resouces referenced: No Support 1 No support 2 No Support 3 Microsoft Recommendations


7 Answer(s)
  • User Avatar
    -1
    AI-Bot created
    Support Team ABP Agent
    • ABP Framework currently does not natively support global EnableRetryOnFailure for all database operations, especially for OpenIddict and some internal modules. This is a known limitation, as documented in the following discussions:

    • The root cause is that OpenIddict (and some other ABP modules) use their own DbContext or transaction management, which may not be compatible with EF Core's built-in connection resiliency when EnableRetryOnFailure is enabled globally. This can lead to unexpected behavior or errors.

    • As of ABP v9.1.3, there is no official workaround that enables seamless, global retry logic for all database operations—including those performed by OpenIddict—without risking side effects or instability.

    • The only reliable approaches currently are:

      1. Manually wrap critical database operations in your own retry logic where possible.
      2. Avoid enabling EnableRetryOnFailure globally if you rely on OpenIddict or other ABP modules that are not compatible.
      3. Monitor ABP's GitHub and release notes for future updates, as this is a recognized issue and may be addressed in upcoming versions.
    • For general EF Core connection resiliency recommendations, see the official Microsoft documentation:

    • If global retry support is a strict requirement for your production environment, you may need to consider alternative authentication modules or frameworks until ABP provides full compatibility.

    Sources:

    • https://abp.io/support/questions/7848/Database-exceptions-while-running-in-Azure-how-to-handle-without-EnableRetryOnFailure
    • https://github.com/abpframework/abp/issues/17479
    • https://abp.io/support/questions/3781/EnableRetryOnFailure
    • https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    Vince.Scholt created

    Kindly piss off with your AI generated answer of reitterating stuff i already knew and demonstrated👍

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    In responce i tried to work around it by having 2 DBContexts pointing to the same database, one for the tools, the other with auto retry for our own code. Sadly this then failed to resolve DBContexts to i assume this is not a possible route either.

    It seems possible. Can you share your custom code?

    If you get any exception, please share the error logs.

    Thanks.

  • User Avatar
    0
    Vince.Scholt created

    [liming.ma@volosoft.com] said: It seems possible. Can you share your custom code?

    If you get any exception, please share the error logs.

    Not as much custom code, as trying to add a 2nd nearly identical DbContext. For now i have just duplicated the 1st dbContext, because it seems near impossible to get them to inherit from one another, purely due to the type being different.

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        IServiceCollection services = context.Services;
    
        services.AddAbpDbContext<MyDbContext>(options =>
        {
            /* Remove "includeAllEntities: true" to create
             * default repositories only for aggregate roots */
            options.AddDefaultRepositories(includeAllEntities: true);
        });
        
        services.AddAbpDbContext<MyRetryDbContext>(options =>
        {
            /* Remove "includeAllEntities: true" to create
             * default repositories only for aggregate roots */
            options.AddDefaultRepositories(includeAllEntities: true);
        });
    
        Configure<AbpDbContextOptions>(options =>
        {
            options.Configure<MyDbContext>(c =>
            {
    #if DEBUG
                c.UseSqlServer()
                .AddInterceptors(ignoringIdentityResolutionInterceptor)
                .EnableSensitiveDataLogging();
    #else
                c.UseSqlServer()
                .AddInterceptors(ignoringIdentityResolutionInterceptor);
    #endif
            });
            
            options.Configure<MyRetryDbContext>(c =>
            {
    #if DEBUG
                c.UseSqlServer(sqlOptions =>
                    {
                        sqlOptions.EnableRetryOnFailure();
                    })
                    .AddInterceptors(ignoringIdentityResolutionInterceptor)
                    .EnableSensitiveDataLogging();
    #else
                c.UseSqlServer(sqlOptions =>
                    {
                        sqlOptions.EnableRetryOnFailure();
                    })
                .AddInterceptors(ignoringIdentityResolutionInterceptor);
    #endif
            });
        });
    

    As a result everything i do is met with this exception, even though it worked fine with just 1 config. And i am not sure how to debug it, as all examples i found did not use the 2 near identical dbcontexts.

     Volo.Abp.AbpException: No configuration found for Microsoft.EntityFrameworkCore.DbContext, Microsoft.EntityFrameworkCore, Version=9.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60! Use services.Configure<AbpDbContextOptions>(...) to configure it.
       at Volo.Abp.EntityFrameworkCore.DependencyInjection.DbContextOptionsFactory.Configure[TDbContext](AbpDbContextOptions options, AbpDbContextConfigurationContext`1 context)
       at Volo.Abp.EntityFrameworkCore.DependencyInjection.DbContextOptionsFactory.Create[TDbContext](IServiceProvider serviceProvider)
       at Autofac.Extensions.DependencyInjection.AutofacRegistration.&lt;&gt;c__DisplayClass5_0.&lt;Register&gt;b__1(IComponentContext context, IEnumerable`1 parameters)
       at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
       at Autofac.Core.Activators.Delegate.DelegateActivator.&lt;ConfigurePipeline&gt;b__2_0(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Middleware.DelegateMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext context)
       at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext context)
       at Autofac.Extensions.DependencyInjection.KeyedServiceMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext context)
       at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       --- End of inner exception stack trace ---
       at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext context)
       at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext context)
       at Autofac.Core.Resolving.Middleware.RegistrationPipelineInvokeMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext context)
       at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext context)
       at Autofac.Core.Resolving.Middleware.ScopeSelectionMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext context)
       at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext context, Action`1 next)
       at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.&lt;&gt;c__DisplayClass14_0.&lt;BuildPipeline&gt;b__1(ResolveRequestContext context)
       at Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext context)
       at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, ResolveRequest& request)
       at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest& request)
       at Autofac.Core.Resolving.ResolveOperation.Execute(ResolveRequest& request)
       at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(ResolveRequest& request)
       at Autofac.Core.Lifetime.LifetimeScope.Autofac.IComponentContext.ResolveComponent(ResolveRequest& request)
       at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
       at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType)
       at Autofac.Extensions.DependencyInjection.AutofacServiceProvider.GetRequiredService(Type serviceType)
       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
       at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork)
       at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.CreateDbContextAsync(IUnitOfWork unitOfWork, String connectionStringName, String connectionString)
       at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.GetDbContextAsync()
       at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.GetDbSetAsync()
       at Volo.Abp.BackgroundJobs.EntityFrameworkCore.EfCoreBackgroundJobRepository.GetWaitingListQueryAsync(Int32 maxResultCount)
       at Volo.Abp.BackgroundJobs.EntityFrameworkCore.EfCoreBackgroundJobRepository.GetWaitingListAsync(Int32 maxResultCount, 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.BackgroundJobs.BackgroundJobStore.GetWaitingJobsAsync(Int32 maxResultCount)
       at Volo.Abp.BackgroundJobs.BackgroundJobWorker.DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
       at Volo.Abp.BackgroundJobs.BackgroundJobWorker.DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
       at Volo.Abp.BackgroundWorkers.Hangfire.HangfirePeriodicBackgroundWorkerAdapter`1.DoWorkAsync(CancellationToken cancellationToken)
       at InvokeStub_TaskAwaiter.GetResult(Object, Object, IntPtr*)
       at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
    
    

    Hope you can shed some light on this!

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The new MyRetryDbContext should not be used with ABP AddAbpDbContext/Repository, etc..

    You can use the AddDbContext method to add it to the Dependency Injection system and configure it to enable EnableRetryOnFailure. Then inject AddDbContext into your service and use it.

    This will lose some features of ABP. But still can use it to query and add/update new entites.

    Thanks.

  • User Avatar
    0
    Vince.Scholt created

    What features would we lose over it then? Because we use a lot of them. I think i am most worried about behavioral changes like UOW or authentication/permissions etc.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Only Data Access is affected. You need to use MyRetryDbContext to manage transactions and perform CRUD operations on the entities.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on July 11, 2025, 11:35