Base solution for your next web application

Activities of "twig202"

I have a background job that runs every 3 minutes:

using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Threading.BackgroundWorkers;
using Abp.Threading.Timers;
using Force.MultiTenancy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Force.Api.Gemini
{
    public class GeminiBackgroundWorker : PeriodicBackgroundWorkerBase, ISingletonDependency
    {
        private const int CheckPeriodAsMilliseconds = 1 * 60 * 3 * 1000; //3 minutes

        private readonly IGeminiManager _geminiManager;
        private readonly IRepository<Tenant> _tenantRepository;

        public GeminiBackgroundWorker(
            AbpTimer timer,
            IGeminiManager geminiManager,
            IRepository<Tenant> tenantRepository)
            : base(timer)
        {
            _geminiManager = geminiManager;
            _tenantRepository = tenantRepository;

            Timer.RunOnStart = true;
            Timer.Period = CheckPeriodAsMilliseconds;
        }


        protected override void DoWork()
        {
            Logger.Info("----GeminiBackgroundWorker.DoWork----------------");

            _geminiManager.ProcessGeminiUpdates();

        }
    }
}

The first time it runs it gets the correct data from the database. Then, when it runs again, it doesn't get the newly update data. It seems to me that is using an out of date conext or something.


        [UnitOfWork]
        public virtual async Task ProcessGeminiUpdates()
        {

            try
            {

                Logger.Info("----GeminiManager.ProcessGemini-----------START-----");

                var updatesNeeded = from o in _geminiUpdateRepository.GetAll()

                                    join o1 in _wellLoadRepository.GetAll() on o.WellLoadId equals o1.Id into j1
                                    from s1 in j1.DefaultIfEmpty()

                                    join o2 in _customerRepository.GetAll() on s1.CustomerId equals o2.Id into j2
                                    from s2 in j2.DefaultIfEmpty()

                                    where
                                        !o.Processed &&

                                        s1.DispatchInitials == null &&

                                        s2.GeminiEnabled && s2.GeminiPassword != null && s2.GeminiUsername != null && s2.GeminiClientSecret != null

                                    select new GeminiAuthInputDto
                                    {
                                        CustomerId = s1.CustomerId.Value,
                                        GeminiClientId = s2.GeminiClientId,
                                        GeminiClientSecret = s2.GeminiClientSecret,
                                        GeminiPassword = s2.GeminiPassword,
                                        GeminiSubscriptionKey = s2.GeminiSubscriptionKey,
                                        GeminiUsername = s2.GeminiUsername,
                                        GeminiEnabled = s2.GeminiEnabled,
                                        WellLoadId = s1.Id
                                    };

                var customers = await updatesNeeded.ToListAsync();

                Logger.Info("----GeminiManager.ProcessGemini Customers -----------Count: " + customers.Count() + "-----");

                if (customers != null && customers.Count > 0)
                    foreach (var customer in customers.GroupBy(x => x.CustomerId).Distinct())
                    {
                        Logger.Info("----GeminiManager.ProcessGemini FOREACH Customer-----------START-----");
                        var customerDto = customers.Where(x => x.CustomerId == customer.Key).FirstOrDefault();

                        var wellLoadsToProcess = customers.Where(x => x.CustomerId == customerDto.CustomerId).Select(x => x.WellLoadId).ToList();

                        await ProcessWellLoadsForCustomer(customerDto, wellLoadsToProcess);
                        Logger.Info("----GeminiManager.ProcessGemini FOREACH Customer-----------END-----");
                    }

                Logger.Info("----GeminiManager.ProcessGemini-----------END-----");
            }
            catch (Exception e)
            {
                Logger.Info("----ProcessGeminiUpdates.Exception-----------" + e.Message + "-----");
            }
        }

What needs to be implemented to get the new data from the database every time it runs the background job?

  • What is your product version?
    • Zero 5.4
    • Abp.AspNetZeroCore 1.1.3
    • Abp.ZeroCore 3.7.2
  • What is your product type (Angular or MVC)?
    • MVC
  • What is product framework type (.net framework or .net core)?
    • .NET Core
  • What is ABP Framework version?
    • Abp 3.7.2

The following issue happens about once every 6-8 weeks. Not always the same user.

I used the Rad Tool to create AppServices etc. with the standard Create function below, somehow an the App Service is inserting TWO rows with the exact same data (exepct the PK Id (int) field).

I've added to the create code to use a Tenant Specific Sequential ID, that increments and stores the value in a table.

       [AbpAuthorize(AppPermissions.Entities_PurchaseOrders_Create)]
        private async Task Create(CreateOrEditPurchaseOrderDto input)
        {
            var purchaseOrder = ObjectMapper.Map<PurchaseOrder>(input);

            if (AbpSession.TenantId != null)
            {
                purchaseOrder.TenantId = (int)AbpSession.TenantId;
            }

            purchaseOrder.SequentialId = await _sequenceManager.GetPurchaseOrderSequence();

            if (input.PurchaseOrderStatus == (int)PurchaseOrderStatus.Closed)
                purchaseOrder.ClosedByUserId = AbpSession.UserId;

            await _purchaseOrderRepository.InsertAsync(purchaseOrder);
        }

SequenceManager below handles 9 other tables and AppServices that have this Tenant specific SequentialId.


        public async Task<int> GetPurchaseOrderSequence()
        {
            return await GetSequence(_purchaseOrderSequence);
        }
        
        private async Task<int> GetSequence(string sequenceEntity)
        {
            using (_unitOfWorkManager.Current.SetTenantId(AbpSession.TenantId.Value))
            {
                var sequence = await _repository.FirstOrDefaultAsync(x => x.Entity == sequenceEntity);
                if (sequence == null)
                    sequence = new SequentialId() { Entity = sequenceEntity, Sequence = 1 };
                else
                    sequence.Sequence = sequence.Sequence + 1;

                await _repository.InsertOrUpdateAsync(sequence);

                await _unitOfWorkManager.Current.SaveChangesAsync();

                return sequence.Sequence;
            }
        }

The SequenceManager is NOT decorated with any UnitOfWork attributes or anything like that.

Can anyone help me solve this issue that has been plaguing the app for the last year or so? EDIT: I can never recreate the issue (trying to double click the Create Modal etc.)

  • What is your product version?
    • Zero 5.4
    • Abp.AspNetZeroCore 1.1.3
    • Abp.ZeroCore 3.7.2
  • What is your product type (Angular or MVC)?
    • MVC
  • What is product framework type (.net framework or .net core)?
    • .NET Core
  • What is ABP Framework version?
    • Abp 3.7.2
Showing 1 to 2 of 2 entries