public Task Begin() { logger.LogVerbose($"Creating state manager transaction."); ((ReliableStateManagerTransactionProvider)reliableStateManagerTransactionProvider).Current = stateManager.CreateTransaction(); logger.LogDebug($"Creating state manager transaction.Transaction Id: {reliableStateManagerTransactionProvider.Current.TransactionId}"); return(Task.CompletedTask); }
public async Task ProcessedJobMessage(long jobId, Guid messageId, string messageName, List <GeneratedMessage> generatedMessages) { try { logger.LogVerbose($"Sending request to record successful processing of event. Job Id: {jobId}, Event: id: {messageId} "); var itemProcessedEvent = new RecordJobMessageProcessingStatus { JobId = jobId, Id = messageId, MessageName = messageName, EndTime = DateTimeOffset.UtcNow, GeneratedMessages = generatedMessages ?? new List <GeneratedMessage>(), Succeeded = true, }; var partitionedEndpointName = config.GetMonitoringEndpointName(jobId); await messageSession.Send(partitionedEndpointName, itemProcessedEvent).ConfigureAwait(false); logger.LogDebug($"Sent request to record successful processing of event. Job Id: {jobId}, Event: id: {messageId} "); } catch (Exception ex) { logger.LogWarning($"Failed to send the job status message. Job: {jobId}, Message: {messageId}, {messageName}, Error: {ex.Message}, {ex}"); } }
public async Task Reset() { paymentLogger.LogVerbose($"Resetting actor for id {Id}"); await apprenticeships.ResetInitialiseFlag().ConfigureAwait(false); paymentLogger.LogInfo($"Reset actor for Id {Id}"); }
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); }
public async Task Handle(ApprenticeshipContractType1EarningEvent message, IMessageHandlerContext context) { if (message.Learner == null || message.Learner?.Uln == 0) { throw new InvalidOperationException("Invalid 'ApprenticeshipContractType1EarningEvent' received. Learner was null or Uln was 0."); } var uln = message.Learner.Uln; var learnerRef = message.Learner.ReferenceNumber; logger.LogDebug($"Processing DataLockProxyProxyService event for learner with learner ref {learnerRef}"); var actorId = new ActorId(uln.ToString()); logger.LogVerbose($"Creating actor proxy for learner with learner ref {learnerRef}"); var actor = proxyFactory.CreateActorProxy <IDataLockService>(new Uri("fabric:/SFA.DAS.Payments.DataLocks.ServiceFabric/DataLockServiceActorService"), actorId); logger.LogDebug($"Actor proxy created for learner with " + $"JobId: {message.JobId} and LearnRefNumber: {learnerRef}"); logger.LogVerbose($"Calling actor proxy to handle earning for learner with learner ref {learnerRef}"); var dataLockEvents = await actor.HandleEarning(message, CancellationToken.None).ConfigureAwait(false); logger.LogDebug($"Earning handled for learner with learner ref {learnerRef}"); if (dataLockEvents != null) { var summary = string.Join(", ", dataLockEvents.GroupBy(e => e.GetType().Name).Select(g => $"{g.Key}: {g.Count()}")); logger.LogVerbose($"Publishing data lock event for learner with learner ref {learnerRef}: {summary}"); await Task.WhenAll(dataLockEvents.Select(context.Publish)).ConfigureAwait(false); logger.LogDebug($"Data lock event published for learner with learner ref {learnerRef}"); } logger.LogInfo($"Successfully processed DataLockProxyProxyService event for Actor for learner {learnerRef}"); }
public async Task Handle(ReceivedProviderEarningsEvent message, CancellationToken cancellationToken) { logger.LogVerbose($"Handling ILR Submissions. Data: {message.ToJson()}"); var currentIlr = await GetCurrentIlrSubmissionEvent(message.Ukprn, cancellationToken); var isNewIlrSubmission = validateIlrSubmission.IsNewIlrSubmission(new IlrSubmissionValidationRequest { IncomingPaymentUkprn = message.Ukprn, IncomingPaymentSubmissionDate = message.IlrSubmissionDateTime, CurrentIlr = currentIlr }); if (!isNewIlrSubmission) { logger.LogInfo($"Ignored same Ilr Submission Data for Ukprn {message.Ukprn} and Job Id {message.JobId} Submission already processed"); return; } logger.LogInfo($"Updating current Ilr Submission Data for Ukprn {message.Ukprn} and Job Id {message.JobId}"); await ilrSubmittedEventCache.Clear(message.Ukprn.ToString(), cancellationToken); await ilrSubmittedEventCache.Add(message.Ukprn.ToString(), message, cancellationToken); logger.LogDebug($"Successfully Updated current Ilr Submission Data for Ukprn {message.Ukprn} and Job Id {message.JobId}"); await providerPaymentsRepository.DeleteOldMonthEndPayment(message.CollectionPeriod, message.Ukprn, message.IlrSubmissionDateTime, cancellationToken); logger.LogInfo($"Successfully Deleted Old Month End Payment for Ukprn {message.Ukprn} and Job Id {message.JobId}"); }
public async Task Handle(DataLockEvent message, IMessageHandlerContext context) { paymentLogger.LogVerbose($"Processing {message.GetType().Name} event for UKPRN {message.Ukprn}"); await manageReceivedDataLockEvent.ProcessDataLockEvent(message); paymentLogger.LogVerbose($"Successfully Processed {message.GetType().Name} event for UKPRN {message.Ukprn}"); }
public async Task HandleSubmissionSucceeded(short academicYear, byte collectionPeriod, long ukprn, DateTime submissionTime, long jobId, CancellationToken cancellationToken) { logger.LogVerbose($"Handling Submission Succeeded. Data: Ukprn: {ukprn}, Academic Year: {academicYear}, Collection Period: {collectionPeriod}, Submission Time {submissionTime}"); await providerPaymentsRepository.DeleteOldMonthEndPayment(new CollectionPeriod { AcademicYear = academicYear, Period = collectionPeriod }, ukprn, submissionTime, cancellationToken); logger.LogInfo($"Successfully Deleted Old Month End Payment for Ukprn: {ukprn}, Academic Year: {academicYear}, Collection Period: {collectionPeriod}, Submission Time {submissionTime} and Job Id {jobId}"); }
private ProviderPaymentEvent MapToProviderPaymentEvent(PaymentModel payment, long monthEndJobId) { paymentLogger.LogVerbose($"Mapping payment id: {payment.Id}, funding source: {payment.FundingSource}"); var providerPayment = paymentFactory.Create(payment.FundingSource); paymentLogger.LogVerbose($"Got {providerPayment.GetType().Name} payment message type. Now mapping to provider payment."); mapper.Map(payment, providerPayment); providerPayment.JobId = monthEndJobId; paymentLogger.LogVerbose($"Finished mapping payment. Id: {providerPayment.EventId}"); return(providerPayment); }
public async Task StartMonthEnd(long ukprn, short academicYear, byte collectionPeriod, long monthEndJobId) { logger.LogVerbose($"Recoding month end in the cache. Ukprn: {ukprn}, academic year: {academicYear}, collection period: {collectionPeriod}, Month End Job Id {monthEndJobId}"); await monthEndCache.AddOrReplace(ukprn, academicYear, collectionPeriod, monthEndJobId).ConfigureAwait(false); logger.LogDebug($"Recoded month end in the cache. Ukprn: {ukprn}, academic year: {academicYear}, collection period: {collectionPeriod} , Month End Job Id {monthEndJobId}"); logger.LogVerbose($"Flushing model cache. Ukprn: {ukprn}, academic year: {academicYear}, collection period: {collectionPeriod}, Month End Job Id {monthEndJobId}"); await batchService.StorePayments(CancellationToken.None); logger.LogDebug($"Model cache flushed. Ukprn: {ukprn}, academic year: {academicYear}, collection period: {collectionPeriod} , Month End Job Id {monthEndJobId}"); }
private IList <PeriodisedRequiredPaymentEvent> CreateRefundPayments(IdentifiedRemovedLearningAim identifiedRemovedLearningAim, List <Payment> historicPayments, int transactionType, ConditionalValue <PaymentHistoryEntity[]> cacheItem) { var refundPaymentsAndPeriods = refundRemovedLearningAimService.RefundLearningAim(historicPayments); return(refundPaymentsAndPeriods .Select(refund => { logger.LogVerbose("Now mapping the required payment to a PeriodisedRequiredPaymentEvent."); var historicPayment = cacheItem.Value.FirstOrDefault(payment => payment.PriceEpisodeIdentifier == refund.payment.PriceEpisodeIdentifier && payment.DeliveryPeriod == refund.deliveryPeriod); if (historicPayment == null) { throw new InvalidOperationException($"Cannot find historic payment with price episode identifier: {refund.payment.PriceEpisodeIdentifier} for period {refund.deliveryPeriod}."); } var requiredPaymentEvent = requiredPaymentEventFactory.Create(refund.payment.EarningType, transactionType); mapper.Map(refund.payment, requiredPaymentEvent); mapper.Map(historicPayment, requiredPaymentEvent); mapper.Map(identifiedRemovedLearningAim, requiredPaymentEvent); // funding line type is not part of removed aim, we need to use value from historic payment requiredPaymentEvent.LearningAim.FundingLineType = historicPayment.LearningAimFundingLineType; logger.LogDebug("Finished mapping"); return requiredPaymentEvent; }).ToList()); }
public async Task <bool> WaitForJobToFinish(long jobId, CancellationToken cancellationToken) { //TODO: Temp brittle solution to wait for jobs to finish logger.LogDebug($"Waiting for job {jobId} to finish."); var endTime = DateTime.Now.Add(config.TimeToWaitForJobToComplete); while (DateTime.Now < endTime) { cancellationToken.ThrowIfCancellationRequested(); var job = await dataContext.GetJobByDcJobId(jobId).ConfigureAwait(false); if (job != null && (job.DataLocksCompletionTime != null || job.Status != Monitoring.Jobs.Model.JobStatus.InProgress)) { logger.LogInfo($"DC Job {jobId} finished. Status: {job.Status:G}. Finish time: {job.EndTime:G}"); return(true); } logger.LogVerbose($"DC Job {jobId} is still in progress"); await Task.Delay(config.TimeToPauseBetweenChecks); continue; } logger.LogWarning($"Waiting {config.TimeToWaitForJobToComplete} but Job {jobId} still not finished."); return(false); }
private async Task CheckJobStatus(string partitionEndpointName, long jobId) { try { using (var scope = scopeFactory.Create($"CheckJobStatus:{jobId}, ThreadId {Thread.CurrentThread.ManagedThreadId}, PartitionId {partitionEndpointName}")) { try { var jobStatusService = GetJobStatusService(scope); var finished = await jobStatusService.ManageStatus(jobId, cancellationToken).ConfigureAwait(false); logger.LogVerbose($"Job: {jobId}, finished: {finished}"); await scope.Commit(); currentJobs[jobId] = finished; } catch (Exception ex) { scope.Abort(); logger.LogWarning($"Failed to update job status for job: {jobId}, ThreadId {Thread.CurrentThread.ManagedThreadId}, PartitionId {partitionEndpointName} Error: {ex.Message}. {ex}"); } } } catch (Exception e) { logger.LogError($"Failed to create or abort the scope of the state manager transaction for: {jobId}, ThreadId {Thread.CurrentThread.ManagedThreadId}, PartitionId {partitionEndpointName} Error: {e.Message}", e); throw; } }
public async Task Handle(ResetActorsCommand message, IMessageHandlerContext context) { logger.LogDebug("Resetting datalock actors."); var resetTasks = new List <Task>(); foreach (var uln in message.Ulns) { var actorId = new ActorId(uln); logger.LogVerbose($"Creating actor proxy, actor id: {uln}."); var actor = proxyFactory.CreateActorProxy <IDataLockService>(new Uri("fabric:/SFA.DAS.Payments.DataLocks.ServiceFabric/DataLockServiceActorService"), actorId); logger.LogVerbose($"Actor proxy created. Actor id: {uln}, now resetting the cache."); resetTasks.Add(actor.Reset()); } await Task.WhenAll(resetTasks).ConfigureAwait(false); logger.LogInfo("Finished resetting the datalock actors"); }
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; } }
public async Task RecordCompletedJobMessageStatus(RecordJobMessageProcessingStatus jobMessageStatus, CancellationToken cancellationToken) { var completedMessage = new CompletedMessage { MessageId = jobMessageStatus.Id, JobId = jobMessageStatus.JobId, CompletedTime = jobMessageStatus.EndTime, Succeeded = jobMessageStatus.Succeeded }; logger.LogVerbose($"Now storing the completed message. Message id: {completedMessage.MessageId}, Job: {completedMessage.JobId}, End time: {completedMessage.CompletedTime}, Succeeded: {completedMessage.Succeeded}"); await jobStorageService.StoreCompletedMessage(completedMessage, cancellationToken); logger.LogVerbose($"Stored completed message. Now storing {jobMessageStatus.GeneratedMessages.Count} in progress messages generated while processing message: {completedMessage.MessageId} for job: {completedMessage.JobId}"); await jobStorageService.StoreInProgressMessages(jobMessageStatus.JobId, jobMessageStatus.GeneratedMessages.Select(message => new InProgressMessage { MessageId = message.MessageId, JobId = jobMessageStatus.JobId, MessageName = message.MessageName }).ToList(), cancellationToken); logger.LogDebug($"Recorded completion of message processing. Job Id: {jobMessageStatus.JobId}, Message id: {jobMessageStatus.Id}."); }
public async Task Handle(ResetCacheCommand message, IMessageHandlerContext context) { logger.LogDebug($"Resetting cache for provider :{message.Ukprn}"); var ulns = await repository.ApprenticeshipUlnsByProvider(message.Ukprn); var resetTasks = new List <Task>(); foreach (var uln in ulns) { var actorId = new ActorId(uln); logger.LogVerbose($"Creating actor proxy for actor id: {uln}"); var actor = proxyFactory.CreateActorProxy <IDataLockService>(new Uri("fabric:/SFA.DAS.Payments.DataLocks.ServiceFabric/DataLockServiceActorService"), actorId); logger.LogVerbose($"Actor proxy created, now resetting the cache."); resetTasks.Add(actor.Reset()); } await Task.WhenAll(resetTasks).ConfigureAwait(false); logger.LogInfo($"Finished resetting the cache for provider: {message.Ukprn}"); }
public async Task Process(SubmissionJobFailed message, CancellationToken cancellationToken) { logger.LogVerbose($"Flushing cached earning events before removing data for job: {message.JobId}, provider: {message.Ukprn}, collection period: {message.CollectionPeriod}"); await batchService.StorePayments(cancellationToken).ConfigureAwait(false); logger.LogDebug($"Flushed data. Now removing earning events for job: {message.JobId}, provider: {message.Ukprn}, collection period: {message.CollectionPeriod}"); await repository.RemoveFailedSubmissionEvents(message.JobId, cancellationToken) .ConfigureAwait(false); logger.LogInfo($"Finished removing earning events for job: {message.JobId}, provider: {message.Ukprn}, collection period: {message.CollectionPeriod}"); }
public async Task ProcessedJobMessage(long jobId, Guid messageId, string messageName, List <GeneratedMessage> generatedMessages) { try { logger.LogVerbose($"Sending request to record successful processing of event. Job Id: {jobId}, Event: id: {messageId} "); var batchSize = 1000; //TODO: this should come from config List <GeneratedMessage> batch; var itemProcessedEvent = new RecordJobMessageProcessingStatus { JobId = jobId, Id = messageId, MessageName = messageName, EndTime = DateTimeOffset.UtcNow, GeneratedMessages = generatedMessages.Take(batchSize).ToList() ?? new List <GeneratedMessage>(), Succeeded = true, }; var partitionedEndpointName = config.GetMonitoringEndpointName(jobId); await messageSession.Send(partitionedEndpointName, itemProcessedEvent).ConfigureAwait(false); var skip = batchSize; while ((batch = generatedMessages.Skip(skip).Take(batchSize).ToList()).Count > 0) { skip += batchSize; var providerEarningsAdditionalMessages = new RecordJobAdditionalMessages { JobId = jobId, GeneratedMessages = batch, }; await messageSession.Send(partitionedEndpointName, providerEarningsAdditionalMessages).ConfigureAwait(false); } logger.LogDebug( $"Sent request to record successful processing of event. Job Id: {jobId}, Event: id: {messageId} "); } catch (Exception ex) { logger.LogWarning($"Failed to send the job status message. Job: {jobId}, Message: {messageId}, {messageName}, Error: {ex.Message}, {ex}"); } }
public async Task Process(SubmissionJobSucceeded message, CancellationToken cancellationToken) { logger.LogVerbose($"Flushing cached earning events before removing old data for provider. Job: {message.JobId}, provider: {message.Ukprn}, collection period: {message.CollectionPeriod}"); await batchService.StorePayments(cancellationToken).ConfigureAwait(false); logger.LogDebug($"Flushed cache. Now removing old earning events for provider. Job: {message.JobId}, provider: {message.Ukprn}, collection period: {message.CollectionPeriod}"); await repository.RemovePriorEvents(message.Ukprn, message.AcademicYear, message.CollectionPeriod, message.IlrSubmissionDateTime, cancellationToken) .ConfigureAwait(false); logger.LogInfo($"Finished removing old earning events for provider. Job: {message.JobId}, provider: {message.Ukprn}, collection period: {message.CollectionPeriod}"); }
public async Task HandleRequiredPayment(CalculatedRequiredLevyAmount message) { try { using (var operation = telemetry.StartOperation("LevyFundedService.HandleRequiredPayment", message.EventId.ToString())) { var stopwatch = Stopwatch.StartNew(); paymentLogger.LogVerbose($"Handling RequiredPayment for {Id}, Job: {message.JobId}, UKPRN: {message.Ukprn}, Account: {message.AccountId}"); await fundingSourceService.AddRequiredPayment(message).ConfigureAwait(false); paymentLogger.LogInfo($"Finished handling required payment for {Id}, Job: {message.JobId}, UKPRN: {message.Ukprn}, Account: {message.AccountId}"); telemetry.TrackDuration("LevyFundedService.HandleRequiredPayment", stopwatch, message); telemetry.StopOperation(operation); } } catch (Exception e) { paymentLogger.LogError($"Error handling required levy payment. Error:{e.Message}", e); throw; } }
public async Task <ProviderPaymentEvent> GetPaymentEvent(FundingSourcePaymentEvent message) { var isMonthEnd = await providerPeriodEndService .MonthEndStarted(message.Ukprn, message.CollectionPeriod.AcademicYear, message.CollectionPeriod.Period) .ConfigureAwait(false); if (!isMonthEnd) { return(null); } paymentLogger.LogVerbose($"Processing Month End for {message.GetType().Name} Ukprn {message.Ukprn} - AcademicYear {message.CollectionPeriod.AcademicYear} - Period {message.CollectionPeriod.Period}"); var monthEndJobId = await providerPeriodEndService.GetMonthEndJobId(message.Ukprn, message.CollectionPeriod.AcademicYear, message.CollectionPeriod.Period) .ConfigureAwait(false); var payment = MapToProviderPaymentEvent(message, monthEndJobId, message.EventId); return(payment); }
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 <ReadOnlyCollection <FundingSourcePaymentEvent> > HandleMonthEnd( ProcessLevyPaymentsOnMonthEndCommand command) { paymentLogger.LogVerbose( $"Handling ProcessLevyPaymentsOnMonthEndCommand for {Id}, Job: {command.JobId}, Account: {command.AccountId}"); try { using (var operation = telemetry.StartOperation("LevyFundedService.HandleMonthEnd", command.CommandId.ToString())) { var stopwatch = Stopwatch.StartNew(); var fundingSourceEvents = await fundingSourceEventGenerationService.HandleMonthEnd(command.AccountId, command.JobId, command.CollectionPeriod); await monthEndCache.AddOrReplace(CacheKeys.MonthEndStartedForThisAccountCacheKey, true, CancellationToken.None); telemetry.TrackDurationWithMetrics("LevyFundedService.HandleMonthEnd", stopwatch, command, command.AccountId, new Dictionary <string, double> { { TelemetryKeys.Count, fundingSourceEvents.Count } }); telemetry.StopOperation(operation); return(fundingSourceEvents); } } catch (Exception ex) { paymentLogger.LogError($"Failed to get levy or co-invested month end payments. Error: {ex.Message}", ex); throw; } }
public async Task StartPeriodEndJob <T>(T periodEndJob) where T : RecordPeriodEndJob { var jobName = periodEndJob.GetType().Name; logger.LogDebug($"Sending request to record start of {jobName}. Job Id: {periodEndJob.JobId}, collection period: {periodEndJob.CollectionYear}-{periodEndJob.CollectionPeriod}"); var partitionedEndpointName = config.GetMonitoringEndpointName(periodEndJob.JobId); logger.LogVerbose($"Endpoint for PeriodEndJobClient for {jobName} with Job Id {periodEndJob.JobId} is `{partitionedEndpointName}`"); await messageSession.Send(partitionedEndpointName, periodEndJob).ConfigureAwait(false); logger.LogInfo($"Sent request to record period end job: {jobName}. Job Id: {periodEndJob.JobId}, collection period: {periodEndJob.CollectionYear}-{periodEndJob.CollectionPeriod}"); }
public async Task <ReadOnlyCollection <PeriodisedRequiredPaymentEvent> > HandleApprenticeship2ContractTypeEarningsEvent(ApprenticeshipContractType2EarningEvent earningEvent, CancellationToken cancellationToken) { paymentLogger.LogVerbose($"Handling ApprenticeshipContractType2EarningEvent for jobId:{earningEvent.JobId} with apprenticeship key based on {logSafeApprenticeshipKeyString}"); using (var operation = telemetry.StartOperation("RequiredPaymentsService.HandleApprenticeship2ContractTypeEarningsEvent", earningEvent.EventId.ToString())) { var stopwatch = Stopwatch.StartNew(); await ResetPaymentHistoryCacheIfDifferentCollectionPeriod(earningEvent.CollectionPeriod) .ConfigureAwait(false); await Initialise(earningEvent.CollectionPeriod.Period).ConfigureAwait(false); var requiredPaymentEvents = await contractType2EarningsEventProcessor.HandleEarningEvent(earningEvent, paymentHistoryCache, cancellationToken).ConfigureAwait(false); Log(requiredPaymentEvents); telemetry.TrackDuration("RequiredPaymentsService.HandleApprenticeship2ContractTypeEarningsEvent", stopwatch, earningEvent); telemetry.StopOperation(operation); return(requiredPaymentEvents); } }
private async Task BatchUpdateLevyAccounts(List <LevyAccountModel> levyAccountModels, CancellationToken cancellationToken) { try { await Task.WhenAll(levyAccountModels.Select(x => levyAccountBulkWriter.Write(x, cancellationToken))).ConfigureAwait(false); await levyAccountBulkWriter.DeleteAndFlush(cancellationToken).ConfigureAwait(false); logger.LogVerbose($"Successfully Added {levyAccountModels.Count} Batch of Levy Accounts Details"); } catch (Exception e) { logger.LogError($"Error while Adding {levyAccountModels.Count} Batch of Levy Accounts Details", e); } }
protected async Task StartJob <T>(long jobId, short collectionYear, byte collectionPeriod, List <GeneratedMessage> generatedMessages) where T : RecordPeriodEndJob, new() { logger.LogDebug($"Sending request to record start of period end job. Job Id: {jobId}, collection period: {collectionYear}-{collectionPeriod}"); var job = new T { JobId = jobId, CollectionYear = collectionYear, CollectionPeriod = collectionPeriod, GeneratedMessages = generatedMessages }; var partitionedEndpointName = config.GetMonitoringEndpointName(jobId); logger.LogVerbose($"Endpoint for PeriodEndJobClient for Job Id {jobId} is `{partitionedEndpointName}`"); await messageSession.Send(partitionedEndpointName, job).ConfigureAwait(false); logger.LogInfo($"Sent request to record period end job. Job Id: {jobId}, collection period: {collectionYear}-{collectionPeriod}"); }
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}"); }
private IList <PeriodisedRequiredPaymentEvent> CreateRefundPayments(IdentifiedRemovedLearningAim identifiedRemovedLearningAim, List <Payment> historicPaymentsByTransactionType, int transactionType, ConditionalValue <PaymentHistoryEntity[]> cacheItem) { var refundPaymentsAndPeriods = refundRemovedLearningAimService.RefundLearningAim(historicPaymentsByTransactionType); return(refundPaymentsAndPeriods .Select(refund => { logger.LogVerbose("Now mapping the required payment to a PeriodisedRequiredPaymentEvent."); var historicPayment = cacheItem.Value.FirstOrDefault(payment => payment.PriceEpisodeIdentifier == refund.payment.PriceEpisodeIdentifier && payment.DeliveryPeriod == refund.deliveryPeriod && payment.TransactionType == transactionType); if (historicPayment == null) { throw new InvalidOperationException($"Cannot find historic payment with price episode identifier: {refund.payment.PriceEpisodeIdentifier} for period {refund.deliveryPeriod}."); } var requiredPaymentEvent = requiredPaymentEventFactory.Create(refund.payment.EarningType, transactionType); if (requiredPaymentEvent == null) { // This shouldn't now happen as the transaction type in the history should match the one in the cache logger.LogWarning( $"Required payment event is null for EarningType: {refund.payment.EarningType} with TransactionType: {transactionType}"); return null; } mapper.Map(refund.payment, requiredPaymentEvent); mapper.Map(historicPayment, requiredPaymentEvent); mapper.Map(identifiedRemovedLearningAim, requiredPaymentEvent); // funding line type and Learner Uln are not part of removed aim, we need to use value from historic payment requiredPaymentEvent.LearningAim.FundingLineType = historicPayment.LearningAimFundingLineType; requiredPaymentEvent.Learner.Uln = historicPayment.LearnerUln; logger.LogDebug("Finished mapping"); return requiredPaymentEvent; }) .Where(x => x != null) .ToList()); }