Base solution for your next web application
Open Closed

Connection leak/Connection pool issue with background job #10756


User avatar
0
omkarchoudhari created

Prerequisites

  • What is your product version?10.1
  • What is your product type (Angular or MVC)?Angular
  • What is product framework type (.net framework or .net core)?

Please review the issues we are facing in an Enterprise customer application related to connection pool etc. Please note this application is in the critical UAT stage

Our requirement is to have some 800 workflows which should be real-time. We implemented this using hangfire with,

  1. One background job which runs every 30 seconds to monitor the workflows. – This job checks if there are any active workflow in the DB. If yes, then it starts that workflow as a separate job.
  2. This monitor will create separate one-time background Jobs for each workflow – In separate workflow background job, we have operations related to DB. Fetching the records from DB and updating data back to DB So, let’s say if we have around 300 workflow active jobs at a time then we could have 300 background job executing at the same time and hitting to same DB .

Now we are facing connection leak/pool issues and application crashes with a few workflows running in the background.

Another requirement is to load the pages within 3-4 seconds. We tried some performance fixes and brought it near to 5-7 seconds. Is there any way to improve this further?

We are using AspnetZero 10.1 as of now. Can you please confirm if upgrading to the latest 10.5 will address our concerns above?

Looking forward to your urgent response @ismcagdas.. We can also discuss the issue over a meeting.

Thanks


10 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @omkarchoudhari

    I suggest you to upgrade ABP NuGet packages to 6.6.1 (or better 6.6.2 which we will release this week). After that, the performance of the web pages will increase. For background jobs, instead of using UnitOfWork attribute on your job methods, we suggest you to manually start a unitOfWork as shown below. The UnitOfWork attribute uses interception and it causes slowness and connection pool issues with high number of requests.

    using (var unitOfWork = _unitOfWorkManager.Begin())
            {
                // YOUR CODE HERE
    
                await unitOfWork.CompleteAsync();
            }
    
  • User Avatar
    0
    omkarchoudhari created

    Hello @ismcagdas,

    Does this mean upgrade to aspnetzero 10.5 version ? or Just upgrade only ABP Nuget packages ? How do we upgrade only Niget in the current aspnetzero version (we are using 10.1 version) ?

    Can you please guide us ?

    Thanks

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @omkarchoudhari

    Yes, only ABP NuGet packages. The fastest option is to search for "xxx" (the one you are using) in csproj files and replace it with 6.6.1. Please fo this operation by opening *.All.sln file.

  • User Avatar
    0
    omkarchoudhari created

    Thanks @ismcagdas . We are trying this.... Will let you know.

  • User Avatar
    0
    omkarchoudhari created

    Hello @ismcagdas,

    Tried updating all the Abp packages to 6.6.1.

    To fix build errors,

    1. Updated a few packages with dependency
    2. Made small change in EditionManager as below

    Then build succeeded, but getting below exception at runtime.

    Can you suggest what we can fix here ?

    Thanks

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    You need to add [UnitOfWork] attribute to DoWork method.

  • User Avatar
    0
    omkarchoudhari created

    Hello @ismcagdas,

    Updated UnitOfWork at two places. Now getting the below error.

    When checked, we couldn’t see such a file

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi **@omkarchoudhari **

    Sorry for my late reply. This happens mostly when you don't update some of the ABP NuGet packages. Could oyu check that on your solution ?

    Thanks,

  • User Avatar
    0
    ipservant created

    Hi, Sorry for digging this up, but I have a similar issue with Postgres and idle connections not freeing/closing (leading to PostgresException 53300), and I suspect background workers after reading this thread.

    So I understand that using [UnitOfWork] there is bad (which we did use), correct? We're still using version 8.1 of Zero (.net core).

    Our background worker has to check many records for all tenants, like so:

    public class XVerificationWorker : PeriodicBackgroundWorkerBase, ISingletonDependency
        {
            private readonly IRepository<Tenant> _tenantRepository;
            private readonly IUserEmailer _userEmailer;
            private readonly XService _xService;
            private readonly IUnitOfWorkManager _unitOfWorkManager;
            DateTime lastCheck = DateTime.UtcNow.Date.AddDays(-1);
            
            public XVerificationWorker(AbpTimer timer,
                XService xService,
                IRepository<Tenant> tenantRepository,
                IUserEmailer userEmailer,
                IUnitOfWorkManager unitOfWorkManager)
            : base(timer)
            {
                _tenantRepository = tenantRepository;
                _userEmailer = userEmailer;
                _xService = xService;
                //Timer.Period = 3600000;
                Timer.Period = 60;
                _unitOfWorkManager = unitOfWorkManager;
            }
            
            //[UnitOfWork] //Bad?!
            protected override void DoWork()
            {            
                if (lastCheck == DateTime.UtcNow.Date || DateTime.UtcNow.Hour < 1)
                    return;
    
                lastCheck = DateTime.UtcNow.Date;
                List<Tenant> affectedTenants = new List<Tenant>();
                using (var unitOfWork = _unitOfWorkManager.Begin())
                {
                    affectedTenants = _tenantRepository.GetAll().ToList();
                    unitOfWork.Dispose();
                }
    
                foreach (Tenant t in affectedTenants)
                {
                    try
                    {
                        using (var unitOfWork = _unitOfWorkManager.Begin())
                        {
                            //using (CurrentUnitOfWork.SetTenantId(t.Id))
                            using (_unitOfWorkManager.Current.SetTenantId(t.Id))
                            {
                                if (t.Id != 0)
                                    try
                                    {
                                        Task.WaitAll(_xService.FullXVerification());
                                    }
                                    catch (Exception ex)
                                    {
                                        Logger.Error(ex.Message, ex);
                                        Task.WaitAll(_userEmailer.TryToSendXVerificationFailedMail(ex.Message));
                                    }
                            }
    
                            Task.WaitAll(unitOfWork.CompleteAsync());
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex.Message, ex);
                    }
                }
            }
        }
    

    -> Is that good code now?

    Before, we were using it like so:

    [UnitOfWork]
    protected override void DoWork()
    {
    [...]
                foreach (Tenant t in affectedTenants)
                {
                [...]
                        using (CurrentUnitOfWork.SetTenantId(t.Id))
                        {
                            if (t.Id != 0)
                                try
                                {
                                    Task.WaitAll(_xService.FullXVerification());
                                }
                                catch (Exception ex)
                                {
                                    Logger.Error(ex.Message, ex);
                                    Task.WaitAll(_userEmailer.TryToSendXVerificationFailedMail(ex.Message));
                                }
                        }
                }
    }
    

    Thank you!

  • User Avatar
    0
    ipservant created

    After some more investigation and testing I don't think it's due to the background workers, we will probably open a new thread regarding the idle connections issue. Would still be nice to know the best practice for UoW in background jobs though :-)