public async Task UpdateVoucherOperationsStatistic(UpdateVoucherOperationsStatistic partnerStatistic) { var lockValue = $"{partnerStatistic.PartnerId}_{partnerStatistic.OperationType}_{partnerStatistic.Currency}"; for (var i = 0; i < MaxAttemptsCount; ++i) { var locked = await _redisLocksService.TryAcquireLockAsync( lockValue, lockValue, _lockTimeOut); if (!locked) { await Task.Delay(_lockTimeOut); continue; } await _voucherOperationsStatisticRepository.UpdateByCurrencyAndOperationType(partnerStatistic); await _partnerVouchersDailyStatsRepository.UpdateByDateAndCurrencyAndOperationType(partnerStatistic); await _redisLocksService.ReleaseLockAsync(lockValue, lockValue); return; } throw new InvalidOperationException("Couldn't acquire a lock in Redis"); }
public async Task <VoucherReservationResult> ReserveVoucherAsync(Guid voucherCampaignId, Guid ownerId) { var campaign = await _campaignsRepository.GetByIdAsync(voucherCampaignId, false); if (campaign == null) { return new VoucherReservationResult { ErrorCode = ProcessingVoucherError.VoucherCampaignNotFound } } ; if (campaign.State != CampaignState.Published || DateTime.UtcNow < campaign.FromDate || campaign.ToDate.HasValue && campaign.ToDate.Value < DateTime.UtcNow) { return new VoucherReservationResult { ErrorCode = ProcessingVoucherError.VoucherCampaignNotActive } } ; if (campaign.VouchersTotalCount <= campaign.BoughtVouchersCount) { return new VoucherReservationResult { ErrorCode = ProcessingVoucherError.NoAvailableVouchers } } ; var voucherPriceIsZero = campaign.VoucherPrice == 0; var voucherCampaignIdStr = voucherCampaignId.ToString(); for (int i = 0; i < MaxAttemptsCount; ++i) { var locked = await _redisLocksService.TryAcquireLockAsync( voucherCampaignIdStr, ownerId.ToString(), _lockTimeOut); if (!locked) { await Task.Delay(_lockTimeOut); continue; } var vouchers = await _vouchersRepository.GetByCampaignIdAndStatusAsync(voucherCampaignId, VoucherStatus.InStock); Voucher voucher = null; if (vouchers.Any()) { try { voucher = vouchers.First(); if (voucherPriceIsZero) { voucher.Status = VoucherStatus.Sold; voucher.OwnerId = ownerId; voucher.PurchaseDate = DateTime.UtcNow; await _vouchersRepository.UpdateAsync(voucher); } else { await _vouchersRepository.ReserveAsync(voucher, ownerId); } } catch (Exception e) { _log.Error(e); await _redisLocksService.ReleaseLockAsync(voucherCampaignIdStr, ownerId.ToString()); return(new VoucherReservationResult { ErrorCode = ProcessingVoucherError.NoAvailableVouchers }); } } else { var vouchersPage = await _vouchersRepository.GetByCampaignIdAsync(voucherCampaignId, 0, 1); if (vouchersPage.TotalCount >= campaign.VouchersTotalCount) { await _redisLocksService.ReleaseLockAsync(voucherCampaignIdStr, ownerId.ToString()); return(new VoucherReservationResult { ErrorCode = ProcessingVoucherError.NoAvailableVouchers }); } var(validationCode, hash) = GenerateValidation(); voucher = new Voucher { CampaignId = voucherCampaignId, Status = voucherPriceIsZero ? VoucherStatus.Sold : VoucherStatus.Reserved, ValidationCodeHash = hash, OwnerId = ownerId, PurchaseDate = DateTime.UtcNow, }; voucher.Id = await _vouchersRepository.CreateAsync(voucher); voucher.ShortCode = GenerateShortCodeFromId(voucher.Id); await _vouchersRepository.UpdateAsync(voucher, validationCode); } await _redisLocksService.ReleaseLockAsync(voucherCampaignIdStr, ownerId.ToString()); if (voucherPriceIsZero) { await PublishVoucherSoldEvent(null, campaign, voucher); return(new VoucherReservationResult { ErrorCode = ProcessingVoucherError.None }); } var paymentRequestResult = await _paymentManagementClient.Api.GeneratePaymentAsync( new PaymentGenerationRequest { CustomerId = ownerId, Amount = campaign.VoucherPrice, Currency = campaign.Currency, PartnerId = campaign.PartnerId, ExternalPaymentEntityId = voucher.ShortCode, }); if (paymentRequestResult.ErrorCode != PaymentGenerationErrorCode.None) { await CancelReservationAsync(voucher.ShortCode); return(new VoucherReservationResult { ErrorCode = ProcessingVoucherError.InvalidPartnerPaymentConfiguration, }); } await _paymentRequestsRepository.CreatePaymentRequestAsync(paymentRequestResult.PaymentRequestId, voucher.ShortCode); return(new VoucherReservationResult { ErrorCode = ProcessingVoucherError.None, PaymentUrl = paymentRequestResult.PaymentPageUrl, }); } _log.Warning($"Couldn't get a lock for voucher campaign {voucherCampaignId}"); return(new VoucherReservationResult { ErrorCode = ProcessingVoucherError.NoAvailableVouchers }); }