예제 #1
0
        public async Task RunAsync(TimeSpan refreshInterval, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                var isPeriodStarted = true; //TODO  read value from cache

                while (isPeriodStarted)
                {
                    paymentLogger.LogInfo("Starting to refresh all Levy Accounts Details");

                    try
                    {
                        await accountBalanceService.RefreshLevyAccountDetails(cancellationToken);
                    }
                    catch (Exception e)
                    {
                        paymentLogger.LogError("Error While trying to refresh all Levy Accounts Details", e);
                    }

                    // isPeriodStarted = true //TODO  read value from cache

                    await Task.Delay(refreshInterval, cancellationToken);
                }
            }
            catch (TaskCanceledException e)
            {
                paymentLogger.LogError("Levy Accounts Refresh Task was Canceled", e);
            }
            catch (Exception e)
            {
                paymentLogger.LogError("Error While trying to refresh all Levy Accounts Details", e);
                throw;
            }
        }
        public async Task RefreshLevyAccountDetails(CancellationToken cancellationToken = default(CancellationToken))
        {
            logger.LogInfo("Now Trying to Refresh All Accounts Balance Details");

            var page = 1;

            await retryPolicy.ExecuteAsync(GetTotalPageSize).ConfigureAwait(false);

            while (page <= totalPageSize)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    var pagedAccountsRecords = await accountApiClient.GetPageOfAccounts(page, batchSize).ConfigureAwait(false);

                    var pagedLevyAccountModels = MapToLevyAccountModel(pagedAccountsRecords);
                    await BatchUpdateLevyAccounts(pagedLevyAccountModels, cancellationToken).ConfigureAwait(false);
                    await PublishNotLevyPayerEmployerEvents(pagedLevyAccountModels).ConfigureAwait(false);

                    logger.LogInfo($"Successfully retrieved Account Balance Details for Page {page} of Levy Accounts");
                }
                catch (Exception e)
                {
                    logger.LogError($"Error while retrieving Account Balance Details for Page {page} of Levy Accounts", e);
                }

                page++;
            }
        }
        private async Task <List <(Object Message, BatchMessageReceiver Receiver, Message ReceivedMessage)> > ReceiveMessages(BatchMessageReceiver messageReceiver, CancellationToken cancellationToken)
        {
            var applicationMessages = new List <(Object Message, BatchMessageReceiver Receiver, Message ReceivedMessage)>();
            var messages            = await messageReceiver.ReceiveMessages(200, cancellationToken).ConfigureAwait(false);

            if (!messages.Any())
            {
                return(applicationMessages);
            }

            foreach (var message in messages)
            {
                cancellationToken.ThrowIfCancellationRequested();
                try
                {
                    var applicationMessage = GetApplicationMessage(message);
                    applicationMessages.Add((applicationMessage, messageReceiver, message));
                }
                catch (Exception e)
                {
                    logger.LogError($"Error deserialising the message. Error: {e.Message}", e);
                    //TODO: should use the error queue instead of dead letter queue
                    await messageReceiver.DeadLetter(message)
                    .ConfigureAwait(false);
                }
            }

            return(applicationMessages);
        }
예제 #4
0
        public async Task RefreshLevyAccountDetails(int pageNumber, CancellationToken cancellationToken = default(CancellationToken))
        {
            logger.LogInfo("Now Trying to Refresh All Accounts Balance Details");

            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                var pagedAccountsRecords = await accountApiClient.GetPageOfAccounts(pageNumber, batchSize).ConfigureAwait(false);

                var pagedLevyAccountModels = MapToLevyAccountModel(pagedAccountsRecords);

                var storedEmployers =
                    await levyFundingSourceRepository.GetCurrentEmployerStatus(pagedLevyAccountModels.Select(x => x.AccountId).ToList(), cancellationToken);

                await BatchUpdateLevyAccounts(pagedLevyAccountModels, cancellationToken).ConfigureAwait(false);
                await PublishEmployerEvents(pagedLevyAccountModels, storedEmployers).ConfigureAwait(false);

                logger.LogInfo($"Successfully retrieved Account Balance Details for Page {pageNumber} of Levy Accounts");
            }
            catch (Exception e)
            {
                logger.LogError($"Error while retrieving Account Balance Details for Page {pageNumber} of Levy Accounts", e);
            }
        }
        public async Task HandleEmployerProviderPriorityChange(EmployerChangedProviderPriority message)
        {
            try
            {
                using (var operation =
                           telemetry.StartOperation("LevyFundedService.HandleEmployerProviderPriorityChange",
                                                    message.EventId.ToString()))
                {
                    var stopwatch = Stopwatch.StartNew();
                    paymentLogger.LogDebug(
                        $"Storing EmployerChangedProviderPriority event for {Id},  Account Id: {message.EmployerAccountId}");
                    await employerProviderPriorityStorageService.StoreEmployerProviderPriority(message)
                    .ConfigureAwait(false);

                    paymentLogger.LogInfo(
                        $"Finished Storing EmployerChangedProviderPriority event for {Id},  Account Id: {message.EmployerAccountId}");
                    TrackInfrastructureEvent("LevyFundedService.HandleEmployerProviderPriorityChange", stopwatch);
                    telemetry.StopOperation(operation);
                }
            }
            catch (Exception ex)
            {
                paymentLogger.LogError(
                    $"Error while handling EmployerChangedProviderPriority event for {Id},  Account Id: {message.EmployerAccountId} Error:{ex.Message}",
                    ex);
                throw;
            }
        }
        public async Task RefreshLevyAccountDetails(int pageNumber, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                paymentLogger.LogInfo($"Starting to refresh page of Levy Accounts Details (Page {pageNumber})");

                try
                {
                    await accountBalanceService.RefreshLevyAccountDetails(pageNumber, cancellationToken);
                }
                catch (Exception e)
                {
                    paymentLogger.LogError($"Error While trying to refresh page of Levy Accounts Details (Page {pageNumber})", e);
                }
            }
            catch (TaskCanceledException e)
            {
                paymentLogger.LogError($"Levy Accounts Refresh Task was Canceled (Page {pageNumber})", e);
            }
            catch (Exception e)
            {
                paymentLogger.LogError($"Error While trying to refresh page of Levy Accounts Details (Page {pageNumber})", e);
                throw;
            }
        }
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                logger.LogInfo($"PaymentsEventModelBatchService for {typeof(T).Name} started");

                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    try
                    {
                        await policy.ExecuteAsync(() => StorePayments(cancellationToken));
                    }
                    catch (Exception ex)
                    {
                        logger.LogError($"Error while storing batch. Error: {ex.Message}", ex);
                    }

                    await Task.Delay(batchInterval, cancellationToken);
                }
            }
            catch (TaskCanceledException)
            {
                logger.LogInfo($"Cancellation requested, stopping PaymentsEventModelBatchService for {typeof(T).Name}");
            }
            catch (Exception ex)
            {
                logger.LogFatal($"Fatal error while storing batch. Error: {ex.Message}", ex);
            }
        }
예제 #8
0
        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            var initialised = false;

            try
            {
                logger.LogDebug("Starting the Earning Events service.");
                jobContextManager = lifetimeScope.Resolve <IJobContextManager <JobContextMessage> >();
                jobContextManager.OpenAsync(cancellationToken);
                initialised = true;
                logger.LogInfo("Started the Earning Events service.");
                await Task.Delay(Timeout.Infinite, cancellationToken);
            }
            catch (Exception exception) when(!(exception is TaskCanceledException))
            {
                // Ignore, as an exception is only really thrown on cancellation of the token.
                logger.LogError($"Reference Data Stateless Service Exception. Error: {exception}.", exception);
            }
            finally
            {
                if (initialised)
                {
                    logger.LogInfo("Earning Events Stateless Service End");
                    await jobContextManager.CloseAsync();
                }
            }
        }
예제 #9
0
        public async Task <ReadOnlyCollection <PeriodisedRequiredPaymentEvent> > HandlePayableEarningEvent(PayableEarningEvent earningEvent, CancellationToken cancellationToken)
        {
            paymentLogger.LogVerbose($"Handling PayableEarningEvent for jobId:{earningEvent.JobId} with apprenticeship key based on {logSafeApprenticeshipKeyString}");
            try
            {
                using (var operation = telemetry.StartOperation("RequiredPaymentsService.HandlePayableEarningEvent", earningEvent.EventId.ToString()))
                {
                    var stopwatch = Stopwatch.StartNew();
                    await ResetPaymentHistoryCacheIfDifferentCollectionPeriod(earningEvent.CollectionPeriod)
                    .ConfigureAwait(false);

                    await Initialise(earningEvent.CollectionPeriod.Period).ConfigureAwait(false);

                    var requiredPaymentEvents = await payableEarningEventProcessor.HandleEarningEvent(earningEvent, paymentHistoryCache, cancellationToken).ConfigureAwait(false);

                    Log(requiredPaymentEvents);
                    telemetry.TrackDuration("RequiredPaymentsService.HandlePayableEarningEvent", stopwatch, earningEvent);
                    telemetry.StopOperation(operation);
                    return(requiredPaymentEvents);
                }
            }
            catch (Exception e)
            {
                paymentLogger.LogError($"Error handling payable earning. Error: {e.Message}");
                throw;
            }
        }
        private async Task <List <LevyAccountModel> > GetPaymentsLevyAccountDetails()
        {
            paymentLogger.LogDebug("Started Importing Payments Employer Accounts");

            List <LevyAccountModel> levyAccountModels;

            try
            {
                levyAccountModels = await paymentsDataContext.LevyAccount.ToListAsync();

                if (levyAccountModels.IsNullOrEmpty())
                {
                    return(null);
                }
            }
            catch (Exception e)
            {
                paymentLogger.LogError("Error while retrieving Account Balance Details from PaymentsV2", e);
                return(null);
            }

            paymentLogger.LogInfo("Finished Importing Payments Employer Accounts");

            return(levyAccountModels);
        }
예제 #11
0
        public async Task <int> Process(int batchSize, CancellationToken cancellationToken)
        {
            logger.LogVerbose("Processing batch.");
            var batch = await cache.GetPayments(batchSize, cancellationToken).ConfigureAwait(false);

            if (batch.Count < 1)
            {
                logger.LogVerbose("No records found to process.");
                return(0);
            }

            using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, TransactionScopeAsyncFlowOption.Enabled))
            {
                try
                {
                    foreach (var item in batch)
                    {
                        logger.LogVerbose($"Saving {typeof(T).Name} to table: {item.ToString()}");
                        await bulkWriter.Write(item, cancellationToken).ConfigureAwait(false);
                    }

                    await bulkWriter.Flush(cancellationToken).ConfigureAwait(false);

                    scope.Complete();
                }
                catch (Exception e)
                {
                    logger.LogError($"Error performing bulk copy for model type: {typeof(T).Name}. Error: {e.Message}", e);
                    throw;
                }
            }

            return(batch.Count);
        }
예제 #12
0
        private async Task <List <LevyAccountModel> > GetPageOfLevyAccounts(int pageNumber, CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                var pagedAccountsRecords = await accountApiClient.GetPageOfAccounts(pageNumber, accountApiBatchSize).ConfigureAwait(false);

                return(MapToLevyAccountModel(pagedAccountsRecords));
            }
            catch (Exception e)
            {
                logger.LogError($"Error while retrieving Account Balance Details for Page {pageNumber} of Levy Accounts", e);
                return(new List <LevyAccountModel>());
            }
        }
예제 #13
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            var initialised = false;

            try
            {
                logger.LogDebug("Starting the Job Context Manager service.");
                jobContextManager.OpenAsync(cancellationToken);
                initialised = true;
                logger.LogInfo("Started the Job Context Manager service.");
                await Task.Delay(Timeout.Infinite, cancellationToken);
            }
            catch (Exception exception) when(!(exception is TaskCanceledException))
            {
                logger.LogError($"Error running DC job context manager. Error: {exception.Message}.", exception);
                throw;
            }
            finally
            {
                if (initialised)
                {
                    logger.LogDebug("Closing the job context manager.");
                    await jobContextManager.CloseAsync();

                    logger.LogInfo("Closed job context manager.");
                }
            }
        }
        public async Task Handle(CalculatedRequiredCoInvestedAmount message, IMessageHandlerContext context)
        {
            paymentLogger.LogInfo($"Processing Required Payment Service event for Message Id : {context.MessageId}");
            var currentExecutionContext = (ESFA.DC.Logging.ExecutionContext)executionContext;

            currentExecutionContext.JobId = message.JobId.ToString();

            var payments = contractType2RequiredPaymentService.GetFundedPayments(message);

            foreach (var recordablePaymentEvent in payments)
            {
                try
                {
                    await context.Publish(recordablePaymentEvent);

                    paymentLogger.LogInfo($"Successfully published CoInvestedPayment of Type  {recordablePaymentEvent.GetType().Name}");
                }
                catch (Exception ex)
                {
                    paymentLogger.LogError($"Error publishing the event: RecordablePaymentEvent", ex);
                    throw;
                }
            }

            paymentLogger.LogInfo($"Successfully processed NonLevyFunded Service event for Job Id {message.JobId}");
        }
        public async Task <int> Process(int batchSize, CancellationToken cancellationToken)
        {
            logger.LogVerbose("Processing batch.");
            var batch = await cache.GetPayments(batchSize, cancellationToken).ConfigureAwait(false);

            if (batch.Count < 1)
            {
                logger.LogVerbose("No records found to process.");
                return(0);
            }

            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, TransactionScopeAsyncFlowOption.Enabled))
                {
                    foreach (var changeEvent in batch)
                    {
                        await SaveDataLockEvent(cancellationToken, changeEvent);

                        foreach (var period in changeEvent.Periods)
                        {
                            await SaveEventPeriods(period, changeEvent, cancellationToken);
                        }

                        foreach (var commitment in changeEvent.CommitmentVersions)
                        {
                            await SaveCommitmentVersion(commitment, changeEvent, cancellationToken);
                        }

                        foreach (var error in changeEvent.Errors)
                        {
                            await SaveErrorCode(error, changeEvent, cancellationToken);
                        }

                        logger.LogDebug(
                            $"Saved PriceEpisodeStatusChange event {changeEvent.DataLock.DataLockEventId} for UKPRN {changeEvent.DataLock.UKPRN}. " +
                            $"Commitment versions: {changeEvent.CommitmentVersions.Length}, " +
                            $"periods: {changeEvent.Periods.Length}, errors: {changeEvent.Errors.Length}");
                    }

                    await dataLockEventWriter.Flush(cancellationToken);

                    await dataLockEventCommitmentVersionWriter.Flush(cancellationToken);

                    await dataLockEventPeriodWriter.Flush(cancellationToken);

                    await dataLockEventErrorWriter.Flush(cancellationToken);

                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                logger.LogError($"Error saving batch of DataLockStatusChanged events. Error: {e.Message}", e);
                throw;
            }

            return(batch.Count);
        }
        public async Task Process(ApprenticeshipCreatedEvent createdEvent)
        {
            try
            {
                logger.LogDebug($"Now processing the apprenticeship created event. " +
                                $"Apprenticeship id: {createdEvent.ApprenticeshipId}, " +
                                $"employer account id: {createdEvent.AccountId}, " +
                                $"Ukprn: {createdEvent.ProviderId}.");
                var model      = mapper.Map <ApprenticeshipModel>(createdEvent);
                var duplicates = await apprenticeshipService.NewApprenticeship(model).ConfigureAwait(false);

                logger.LogDebug($"Apprenticeship saved to database. " +
                                $"Apprenticeship id: {createdEvent.ApprenticeshipId}, " +
                                $"employer account id: {createdEvent.AccountId}, " +
                                $"Ukprn: {createdEvent.ProviderId}.");

                var updatedEvent = mapper.Map <ApprenticeshipUpdated>(model);
                updatedEvent.Duplicates = duplicates.Select(duplicate => new ApprenticeshipDuplicate
                {
                    Ukprn = duplicate.Ukprn, ApprenticeshipId = duplicate.ApprenticeshipId
                }).ToList();
                var endpointInstance = await endpointInstanceFactory.GetEndpointInstance().ConfigureAwait(false);

                await endpointInstance.Publish(updatedEvent).ConfigureAwait(false);

                logger.LogInfo($"Finished processing the apprenticeship created event. " +
                               $"Apprenticeship id: {createdEvent.ApprenticeshipId}, " +
                               $"employer account id: {createdEvent.AccountId}, " +
                               $"Ukprn: {createdEvent.ProviderId}.");
            }
            catch (ApprenticeshipAlreadyExistsException e)
            {
                logger.LogWarning($"Apprenticeship already exists while trying to add a new apprenticeship: {e.Message}\n" +
                                  $"Apprenticeship id: {createdEvent.ApprenticeshipId}, " +
                                  $"employer account id: {createdEvent.AccountId}, " +
                                  $"Ukprn: {createdEvent.ProviderId}.");
            }
            catch (InvalidOperationException e)
            {
                logger.LogError($"Unhandled exception while adding apprenticeship: {e.Message}\n" +
                                $"Apprenticeship id: {createdEvent.ApprenticeshipId}, " +
                                $"employer account id: {createdEvent.AccountId}, " +
                                $"Ukprn: {createdEvent.ProviderId}.", e);
                throw;
            }
            catch (Exception ex)
            {
                logger.LogError($"Error processing the apprenticeship event. Error: {ex.Message}", ex);
                throw;
            }
        }
예제 #17
0
        private async Task LoadExistingJobs()
        {
            try
            {
                using (var scope = scopeFactory.Create("LoadExistingJobs"))
                {
                    var jobStorage = scope.Resolve <IJobStorageService>();
                    var jobs       = await jobStorage.GetCurrentJobs(cancellationToken).ConfigureAwait(false);

                    foreach (var job in jobs)
                    {
                        StartMonitoringJob(job, JobType.EarningsJob);
                    }
                }
            }
            catch (Exception e)
            {
                logger.LogError("Failed to load existing jobs.");
            }
        }
예제 #18
0
        private async Task LoadExistingJobs()
        {
            try
            {
                using (var scope = scopeFactory.Create("LoadExistingJobs"))
                {
                    var jobStorage = scope.Resolve <IJobStorageService>();
                    var jobs       = await GetCurrentJobs(jobStorage);

                    foreach (var job in jobs)
                    {
                        StartMonitoringJob(job, JobType.EarningsJob);
                    }
                }
            }
            catch (Exception e)
            {
                logger.LogError($"Failed to load existing jobs. Error: {e.Message}", e);
            }
        }
예제 #19
0
 private static async Task RunApprenticeshipsReferenceDataComparison(IApprenticeshipsDataService service, IPaymentLogger log)
 {
     try
     {
         await service.ProcessComparison();
     }
     catch (Exception e)
     {
         log.LogError("Error in ProcessComparison", e);
         throw;
     }
 }
예제 #20
0
        public PeriodisedRequiredPaymentEvent Create(EarningType earningType, int transactionType)
        {
            PeriodisedRequiredPaymentEvent paymentEvent = null;

            switch (earningType)
            {
            case EarningType.CoInvested:
                if (IsValidPaymentType <OnProgrammeEarningType>(transactionType))
                {
                    paymentEvent = new CalculatedRequiredCoInvestedAmount
                    {
                        OnProgrammeEarningType = (OnProgrammeEarningType)transactionType,
                    };
                }

                break;

            case EarningType.Incentive:
                if (IsValidPaymentType <IncentivePaymentType>(transactionType))
                {
                    paymentEvent = new CalculatedRequiredIncentiveAmount
                    {
                        Type = (IncentivePaymentType)transactionType,
                    };
                }

                break;

            case EarningType.Levy:
                if (IsValidPaymentType <OnProgrammeEarningType>(transactionType))
                {
                    paymentEvent = new CalculatedRequiredLevyAmount
                    {
                        OnProgrammeEarningType = (OnProgrammeEarningType)transactionType,
                    };
                }

                break;

            default:
                throw new InvalidOperationException(
                          $"Unknown earning type found: {earningType:G}. Cannot create the PeriodisedRequiredPaymentEvent.");
            }

            if (paymentEvent == null)
            {
                logger.LogError(
                    $"Invalid EarningType and TransactionType combination: EarningType: {earningType:G}, TransactionType: {transactionType}");
            }

            return(paymentEvent);
        }
 protected override async Task RunAsync(CancellationToken cancellationToken)
 {
     try
     {
         logger.LogDebug("Starting the DC JobContextMessageService for the Period End service.");
         jobContextManagerService = lifetimeScope.Resolve <IJobContextManagerService>();
         await jobContextManagerService.RunAsync(cancellationToken);
     }
     catch (Exception ex) when(!(ex is TaskCanceledException))
     {
         logger.LogError($"Error starting the job context manager. Error: {ex.Message}", ex);
         throw;
     }
 }
예제 #22
0
        public async Task <List <ProviderAdjustment> > GetCurrentProviderAdjustments(int academicYear)
        {
            logger.LogInfo("Getting Current Provider Adjustments - Getting Token");

            var token = await GetToken();

            logger.LogInfo("Token retrieved");

            var providerAdjustments = new List <ProviderAdjustment>();
            var pageNumber          = 1;

            while (true)
            {
                var request = new HttpRequestMessage(HttpMethod.Get, $"api/v1/Eas/{academicYear}?pagenumber={pageNumber}&pagesize={pageSize}");
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

                logger.LogInfo($"Getting page {pageNumber} of data from API");
                var httpResponse = await client.SendAsync(request).ConfigureAwait(false);

                logger.LogInfo($"Successfully connected to the API");

                var responseContent = await httpResponse.Content.ReadAsStringAsync();

                logger.LogDebug($"Response code: {httpResponse.StatusCode}, Reason: {httpResponse.ReasonPhrase}, " +
                                $"Request: {httpResponse.RequestMessage.RequestUri}");

                if (httpResponse.IsSuccessStatusCode)
                {
                    var batch = JsonConvert.DeserializeObject <List <ProviderAdjustment> >(responseContent);
                    if (batch.Count == 0)
                    {
                        logger.LogInfo($"No messages on page {pageNumber}");
                        break;
                    }
                    logger.LogInfo($"Successfully retrieved {batch.Count} records from API");
                    providerAdjustments.AddRange(batch);
                }
                else
                {
                    logger.LogError($"Error getting EAS records: {responseContent}, {httpResponse}");
                    throw new InvalidOperationException($"Error getting EAS records: {responseContent}");
                }

                pageNumber++;
            }

            logger.LogInfo($"Finished reading records from the API. Got {providerAdjustments.Count} records");
            return(providerAdjustments);
        }
예제 #23
0
        private static async Task RunLevyAccountImport(IEndpointInstanceFactory endpointInstanceFactory, IScheduledJobsConfiguration config, IPaymentLogger log)
        {
            try
            {
                var command          = new ImportEmployerAccounts();
                var endpointInstance = await endpointInstanceFactory.GetEndpointInstance().ConfigureAwait(false);

                await endpointInstance.Send(config.LevyAccountBalanceEndpoint, command).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                log.LogError("Error in LevyAccountImport", e);
                throw;
            }
        }
예제 #24
0
 /// <summary>
 /// Optional override to create listeners (e.g., TCP, HTTP) for this service replica to handle client or user requests.
 /// </summary>
 /// <returns>A collection of listeners.</returns>
 protected override IEnumerable <ServiceInstanceListener> CreateServiceInstanceListeners()
 {
     try
     {
         return(new List <ServiceInstanceListener>
         {
             new ServiceInstanceListener(context => lifetimeScope.Resolve <IStatelessServiceBusBatchCommunicationListener>())
         });
     }
     catch (Exception e)
     {
         logger.LogError($"Error starting the service instance listener: {e.Message}", e);
         throw;
     }
 }
예제 #25
0
        public async Task <bool> HandleAsync(JobContextMessage message, CancellationToken cancellationToken)
        {
            try
            {
                logger.LogDebug("Getting task type from period end message.");
                var taskType = GetTask(message);
                logger.LogDebug("Got period end type now create the period end event.");
                var periodEndEvent = CreatePeriodEndEvent(taskType);
                logger.LogDebug($"Created period end event. Type: {periodEndEvent.GetType().Name}");
                periodEndEvent.JobId            = message.JobId;
                periodEndEvent.CollectionPeriod = new CollectionPeriod
                {
                    AcademicYear = Convert.ToInt16(GetMessageValue(message, JobContextMessageConstants.KeyValuePairs.CollectionYear)),
                    Period       = Convert.ToByte(GetMessageValue(message, JobContextMessageConstants.KeyValuePairs.ReturnPeriod))
                };

                logger.LogDebug($"Got period end event: {periodEndEvent.ToJson()}");
                await RecordPeriodEndJob(taskType, periodEndEvent).ConfigureAwait(false);

                var endpointInstance = await endpointInstanceFactory.GetEndpointInstance();

                await endpointInstance.Publish(periodEndEvent);

                logger.LogInfo($"Finished publishing the period end event. Name: {periodEndEvent.GetType().Name}, JobId: {periodEndEvent.JobId}, Collection Period: {periodEndEvent.CollectionPeriod.Period}-{periodEndEvent.CollectionPeriod.AcademicYear}.");

                // TODO: This is a temporary workaround to enable the PeriodEndStart and PeriodEndStop messages to return true as otherwise the service will
                // TODO: just hang as there is nothing implemented to handle the Start and Stop events and so the job status service will never get a completion and so this will never return true.
                // PV2-1345 will handle PeriodEndStart
                // PeriodEndStoppedEvent will be handled by the PeriodEndStoppedEventHandler which in turn is handled by the ProcessProviderMonthEndCommandHandler but we don't want to wait for it


                if (periodEndEvent is PeriodEndStartedEvent || periodEndEvent is PeriodEndStoppedEvent)
                {
                    logger.LogDebug("Returning as this is either a PeriodEndStart or PeriodEndStop event");
                    return(true);
                }

                await jobStatusService.WaitForJobToFinish(message.JobId, cancellationToken);

                return(true);
            }
            catch (Exception ex)
            {
                logger.LogError($"Failed to process job context message. Message: {message.ToJson()}", ex);
                throw;
            }
        }
예제 #26
0
        public async Task Handle(SubmissionSucceededEvent message, IMessageHandlerContext context)
        {
            var logString = $"{typeof(SubmissionSucceededEvent).Name}. UKPRN: {message.Ukprn} {message.AcademicYear}-R{message.CollectionPeriod:D2}, ILR Submission: {message.IlrSubmissionDateTime:s}, Job ID: {message.JobId}";

            logger.LogInfo("Handling " + logString);

            try
            {
                await submissionEventProcessor.ProcessSubmissionSucceededEvent(message).ConfigureAwait(false);

                logger.LogInfo("Finished handling " + logString);
            }
            catch (Exception ex)
            {
                logger.LogError($"Error handling {logString}. {ex.Message}");
                throw;
            }
        }
        public async Task StartJob(long jobId, long ukprn, DateTime ilrSubmissionTime, short collectionYear, byte collectionPeriod, List <GeneratedMessage> generatedMessages, DateTimeOffset startTime)
        {
            logger.LogVerbose($"Sending request to record start of earnings job. Job Id: {jobId}, Ukprn: {ukprn}");
            try
            {
                var batchSize = 1000; //TODO: this should come from config
                List <GeneratedMessage> batch;
                var providerEarningsEvent = new RecordEarningsJob
                {
                    StartTime         = startTime,
                    JobId             = jobId,
                    Ukprn             = ukprn,
                    IlrSubmissionTime = ilrSubmissionTime,
                    CollectionYear    = collectionYear,
                    CollectionPeriod  = collectionPeriod,
                    GeneratedMessages = generatedMessages.Take(batchSize).ToList(),
                    LearnerCount      = generatedMessages.Count
                };

                var jobsEndpointName        = config.GetSettingOrDefault("Monitoring_JobsService_EndpointName", "sfa-das-payments-monitoring-jobs");
                var partitionedEndpointName = $"{jobsEndpointName}{partitionName.PartitionNameForJob(jobId, ukprn)}";
                logger.LogVerbose($"Endpoint for RecordEarningsJob for Job Id {jobId} is `{partitionedEndpointName}`");
                await messageSession.Send(partitionedEndpointName, providerEarningsEvent).ConfigureAwait(false);

                var skip = batchSize;

                while ((batch = generatedMessages.Skip(skip).Take(1000).ToList()).Count > 0)
                {
                    skip += batchSize;
                    var providerEarningsAdditionalMessages = new RecordEarningsJobAdditionalMessages
                    {
                        JobId             = jobId,
                        GeneratedMessages = batch,
                    };
                    await messageSession.Send(partitionedEndpointName, providerEarningsAdditionalMessages).ConfigureAwait(false);
                }
                logger.LogDebug($"Sent request(s) to record start of earnings job. Job Id: {jobId}, Ukprn: {ukprn}");
            }
            catch (Exception ex)
            {
                logger.LogError($"Failed to send the request to record the earnings job. Job: {jobId}, Error: {ex.Message}", ex);
                throw;
            }
        }
 protected override IEnumerable <ServiceReplicaListener> CreateServiceReplicaListeners()
 {
     try
     {
         partitionEndpointName = ((NamedPartitionInformation)Partition.PartitionInfo).Name;
         var batchListener = lifetimeScope.Resolve <IServiceBusBatchCommunicationListener>();
         batchListener.EndpointName += partitionEndpointName;
         var serviceListener = new ServiceReplicaListener(context => batchListener);
         return(new List <ServiceReplicaListener>
         {
             serviceListener
         });
     }
     catch (Exception e)
     {
         logger.LogError($"Error: {e.Message}", e);
         throw;
     }
 }
        public async Task PerformExportPaymentsAndEarningsToV1(CollectionPeriod collectionPeriod)
        {
            logger.LogVerbose($"Started V1 payments export for collection period {collectionPeriod}");

            while (true)
            {
                int page = -1;
                try
                {
                    page = await paymentExportProgressCache.GetPage(collectionPeriod.AcademicYear, collectionPeriod.Period);

                    logger.LogVerbose($"Starting with page: {page}");

                    var payments = providerPaymentsRepository.GetMonthEndPayments(collectionPeriod, exportBatchSize, page);

                    if (payments.Count == 0)
                    {
                        logger.LogVerbose($"Finished exporting payments to V1 for collection period: {collectionPeriod}");
                        break;
                    }

                    logger.LogVerbose($"Found {payments.Count} payments to process");

                    var result = paymentMapper.MapV2Payments(payments);
                    await legacyPaymentsRepository
                    .WritePaymentInformation(result.payments, result.requiredPayments, result.earnings)
                    .ConfigureAwait(false);

                    logger.LogVerbose($"Completed write for page: {page} for collection period: {collectionPeriod}");

                    await paymentExportProgressCache
                    .IncrementPage(collectionPeriod.AcademicYear, collectionPeriod.Period)
                    .ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    logger.LogError($"Error processing page: {page} during V1 legacy export", e);
                    throw;
                }
            }

            logger.LogVerbose($"Completed V1 payments export for collection period {collectionPeriod}");
        }
        public async Task StoreEmployerProviderPriority(EmployerChangedProviderPriority providerPriorityEvent)
        {
            try
            {
                int order             = 1;
                var paymentPriorities = new List <EmployerProviderPriorityModel>();
                foreach (var providerUkprn in providerPriorityEvent.OrderedProviders)
                {
                    paymentPriorities.Add(new EmployerProviderPriorityModel
                    {
                        Ukprn             = providerUkprn,
                        EmployerAccountId = providerPriorityEvent.EmployerAccountId,
                        Order             = order
                    });

                    order++;
                }

                using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
                {
                    paymentLogger.LogDebug($"Replacing Previous EmployerProviderPriority for Account Id {providerPriorityEvent.EmployerAccountId}");
                    await levyFundingSourceRepository.ReplaceEmployerProviderPriorities(providerPriorityEvent.EmployerAccountId, paymentPriorities).ConfigureAwait(false);

                    paymentLogger.LogDebug($"Successfully Replaced Previous EmployerProviderPriority for Account Id {providerPriorityEvent.EmployerAccountId}");

                    paymentLogger.LogDebug($"Adding EmployerProviderPriority to Cache for Account Id {providerPriorityEvent.EmployerAccountId}");
                    await employerProviderPriorities.AddOrReplace(CacheKeys.EmployerPaymentPriorities, paymentPriorities).ConfigureAwait(false);

                    paymentLogger.LogInfo($"Successfully Add EmployerProviderPriority to Cache for Account Id {providerPriorityEvent.EmployerAccountId}");

                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                paymentLogger.LogError($"Error while updating  EmployerProviderPriority for Account Id {providerPriorityEvent.EmployerAccountId}", e);
                throw;
            }
        }