private Task <Job> QueueAssignTemplateCalculationsJob(Reference user, string correlationId, string specificationId, string fundingStreamId, string fundingPeriodId, string templateVersionId) => _jobs.QueueJob(new JobCreateModel { JobDefinitionId = AssignTemplateCalculationsJob, InvokerUserId = user?.Id, InvokerUserDisplayName = user?.Name, CorrelationId = correlationId, SpecificationId = specificationId, Trigger = new Trigger { Message = "Changed template version for specification", EntityId = specificationId, EntityType = nameof(Specification) }, Properties = new Dictionary <string, string> { { "specification-id", specificationId }, { "fundingstream-id", fundingStreamId }, { "fundingperiod-id", fundingPeriodId }, { "template-version", templateVersionId } } });
public override async Task Process(Message message) { Guard.ArgumentNotNull(message, nameof(message)); JobSummary jobSummary = message.GetPayloadAsInstanceOf <JobSummary>(); if (jobSummary.CompletionStatus == CompletionStatus.Succeeded && jobSummary.JobType == JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob) { JobCreateModel jobCreateModel = new JobCreateModel { JobDefinitionId = JobConstants.DefinitionNames.CreateInstructAllocationJob, InvokerUserDisplayName = jobSummary.InvokerUserDisplayName, InvokerUserId = jobSummary.InvokerUserId, CorrelationId = message.GetCorrelationId(), SpecificationId = jobSummary.SpecificationId, Properties = new Dictionary <string, string> { { "specification-id", jobSummary.SpecificationId } }, Trigger = jobSummary.Trigger }; Job newJob = await _jobManagement.QueueJob(jobCreateModel); if (newJob == null) { _logger.Error($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'"); throw new Exception($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'"); } _logger.Information($"Created new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' with id: '{newJob.Id}'"); } }
public async Task CreateInstructGenerateAggregationsAllocationJob_GivenJobCreated_LogsInformation() { //Arrange JobSummary jobNotification = CreateJobSummary(); string json = JsonConvert.SerializeObject(jobNotification); Message message = new Message(Encoding.UTF8.GetBytes(json)); Job job = new Job { Id = "job-id-1" }; IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns(job); ILogger logger = CreateLogger(); JobService jobService = CreateJobService(jobManagement, logger); //Act await jobService.Process(message); //Assert logger .Received(1) .Information(Arg.Is($"Created new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' with id: '{job.Id}'")); }
public async Task CreateAdditionalCalculation_GivenCreateJobReturnsNull_ReturnsInternalServerError() { //Arrange CalculationCreateModel model = CreateCalculationCreateModel(); Reference author = CreateAuthor(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .CreateDraftCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository(); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns((Job)null); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecificationSummary>( HttpStatusCode.OK, new SpecificationSummary { Id = SpecificationId } )); ILogger logger = CreateLogger(); CalculationService calculationService = CreateCalculationService( calculationsRepository: calculationsRepository, calculationVersionRepository: versionRepository, searchRepository: searchRepository, jobManagement: jobManagement, logger: logger, specificationsApiClient: specificationsApiClient); //Act IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, CorrelationId); //Assert result .Should() .BeOfType <InternalServerErrorResult>() .Which .Value .Should() .Be($"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{SpecificationId}'"); logger .Received(1) .Error(Arg.Is($"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{SpecificationId}'")); }
public void SetUp() { _policies = Substitute.For <IPoliciesApiClient>(); _jobs = Substitute.For <IJobManagement>(); _userId = NewRandomString(); _userName = NewRandomString(); _user = NewReference(_ => _.WithId(_userId) .WithName(_userName)); _correlationId = NewRandomString(); _action = new QueueCreateSpecificationJobAction(_policies, _jobs, new SpecificationsResiliencePolicies { JobsApiClient = Policy.NoOpAsync(), PoliciesApiClient = Policy.NoOpAsync() }, Substitute.For <ILogger>()); _jobs.QueueJob(Arg.Any <JobCreateModel>()) .Returns(new Job()); //default instance as we assert was called but have null checks in the test now }
public async Task <IActionResult> QueueSpecificationIndexJob(string specificationId, Reference user, string correlationId) { Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId)); return(new OkObjectResult(await _jobs.QueueJob(new JobCreateModel { JobDefinitionId = ReIndexSpecificationJob, InvokerUserId = user?.Id, CorrelationId = correlationId, SpecificationId = specificationId, Trigger = new Trigger { Message = "Specification change requires reindexing", EntityType = nameof(Specification), EntityId = specificationId }, Properties = new Dictionary <string, string> { { SpecificationId, specificationId } } }))); }
public void CreateInstructGenerateAggregationsAllocationJob_GivenCreatingJobReturnsNull_ThrowsException() { //Arrange JobSummary jobNotification = CreateJobSummary(); string json = JsonConvert.SerializeObject(jobNotification); Message message = new Message(Encoding.UTF8.GetBytes(json)); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns((Job)null); ILogger logger = CreateLogger(); JobService jobService = CreateJobService(jobManagement, logger); //Act Func <Task> test = () => jobService.Process(message); //Assert test .Should() .ThrowExactly <Exception>() .Which .Message .Should() .Be($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'"); logger .Received(1) .Error(Arg.Is($"Failed to create new job of type: '{JobConstants.DefinitionNames.CreateInstructAllocationJob}'")); }
private async Task <long> QueueSearchIndexWriterJob( IEnumerable <ProviderResult> providerResults, SpecificationSummary specificationSummary, Reference user, string correlationId, string parentJobId) { Stopwatch stopwatch = Stopwatch.StartNew(); string specificationId = specificationSummary.GetSpecificationId(); IEnumerable <string> providerIds = providerResults.Select(x => x.Provider?.Id).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray(); if (!providerIds.Any()) { return(0); } try { Common.ApiClient.Jobs.Models.Job searchIndexWriterJob = await _jobManagement.QueueJob( new JobCreateModel() { Trigger = new Trigger { EntityId = specificationId, EntityType = "Specification", Message = "Write ProviderCalculationResultsIndex serach index for specification" }, InvokerUserId = user.Id, InvokerUserDisplayName = user.Name, JobDefinitionId = JobConstants.DefinitionNames.SearchIndexWriterJob, ParentJobId = parentJobId, SpecificationId = specificationId, CorrelationId = correlationId, Properties = new Dictionary <string, string> { { "specification-id", specificationId }, { "specification-name", specificationSummary.Name }, { "index-writer-type", SearchIndexWriterTypes.ProviderCalculationResultsIndexWriter } }, MessageBody = JsonConvert.SerializeObject(providerIds) }); } catch (Exception ex) { string errorMessage = $"Failed to queue SearchIndexWriterJob for specification - {specificationId}"; _logger.Error(ex, errorMessage); throw; } stopwatch.Stop(); return(stopwatch.ElapsedMilliseconds); }
public async Task <Job> CreateReIndexJob(Reference user, string correlationId, string specificationId = null, string parentJobId = null) { try { Job job = await _jobManagement.QueueJob(new JobCreateModel { JobDefinitionId = JobConstants.DefinitionNames.ReIndexPublishedProvidersJob, InvokerUserId = user.Id, InvokerUserDisplayName = user.Name, CorrelationId = correlationId, Trigger = new Trigger { Message = "ReIndexing PublishedProviders", EntityType = nameof(PublishedProviderIndex), } }); if (!string.IsNullOrWhiteSpace(parentJobId)) { job.ParentJobId = parentJobId; } if (!string.IsNullOrWhiteSpace(specificationId)) { job.Properties = new Dictionary <string, string> { { "specification-id", specificationId } }; } if (job != null) { _logger.Information($"New job of type '{job.JobDefinitionId}' created with id: '{job.Id}'"); } else { string errorMessage = $"Failed to create job of type '{JobConstants.DefinitionNames.ReIndexPublishedProvidersJob}'"; _logger.Error(errorMessage); } return(job); } catch (Exception ex) { string error = $"Failed to queue published provider re-index job"; _logger.Error(ex, error); throw new Exception(error); } }
private async Task <Job> CreateJob(string errorMessage, JobCreateModel createModel) { try { Job job = await _jobManagement.QueueJob(createModel); return(job); } catch (Exception ex) { _logger.Error(ex, errorMessage); throw new Exception(errorMessage); } }
private async Task <Job> CreateJob(JobCreateModel createModel) { try { var job = await _jobManagement.QueueJob(createModel); GuardAgainstNullJob(job, createModel); return(job); } catch (Exception ex) { _logger.Error($"Failed to create job of type '{createModel.JobDefinitionId}' on specification '{createModel.Trigger.EntityId}'. {ex}"); throw; } }
private async Task <bool> RegenerateScopedProvidersForSpecification(string specificationId, bool setCachedProviders) { string scopedProviderSummariesCountCacheKey = $"{CacheKeys.ScopedProviderSummariesCount}{specificationId}"; string currentProviderCount = await _cachePolicy.ExecuteAsync(() => _cacheProvider.GetAsync <string>(scopedProviderSummariesCountCacheKey)); string cacheKeyScopedListCacheKey = $"{CacheKeys.ScopedProviderSummariesPrefix}{specificationId}"; long scopedProviderRedisListCount = await _cachePolicy.ExecuteAsync(() => _cacheProvider.ListLengthAsync <ProviderSummary>(cacheKeyScopedListCacheKey)); if (string.IsNullOrWhiteSpace(currentProviderCount) || int.Parse(currentProviderCount) != scopedProviderRedisListCount || setCachedProviders) { IEnumerable <JobSummary> latestJob = await _jobManagement.GetLatestJobsForSpecification(specificationId, new[] { JobConstants.DefinitionNames.PopulateScopedProvidersJob }); // the populate scoped providers job is already running so don't need to queue another job if (latestJob?.FirstOrDefault()?.RunningStatus == RunningStatus.InProgress) { return(true); } await _jobManagement.QueueJob(new JobCreateModel { JobDefinitionId = JobConstants.DefinitionNames.PopulateScopedProvidersJob, SpecificationId = specificationId, Trigger = new Trigger { EntityId = specificationId, EntityType = "Specification", Message = "Triggered for specification changes" }, Properties = new Dictionary <string, string> { { "specification-id", specificationId } } }); return(true); } return(false); }
public void SetUp() { _jobs = Substitute.For <IJobManagement>(); _userId = NewRandomString(); _userName = NewRandomString(); _user = NewReference(_ => _.WithId(_userId) .WithName(_userName)); _correlationId = NewRandomString(); _action = new QueueDeleteSpecificationJobAction( _jobs, Substitute.For <ILogger>()); _jobs.QueueJob(Arg.Any <JobCreateModel>()) .Returns(new Job()); //default instance as we assert was called but have null checks in the test now }
private async Task <JobsModels.Job> SendInstructAllocationsToJobService(string specificationId, Reference user, JobsModels.Trigger trigger, string correlationId, bool generateAggregations = false) { JobsModels.JobCreateModel job = new JobsModels.JobCreateModel { InvokerUserDisplayName = user?.Name, InvokerUserId = user?.Id, JobDefinitionId = generateAggregations ? JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob : JobConstants.DefinitionNames.CreateInstructAllocationJob, SpecificationId = specificationId, Properties = new Dictionary <string, string> { { "specification-id", specificationId }, { "ignore-save-provider-results", "true" } }, Trigger = trigger, CorrelationId = correlationId }; return(await _jobManagement.QueueJob(job)); }
public async Task <Job> CreateJob(string fundingStreamId, string fundingPeriodId, string correlationId) { Dictionary <string, string> messageProperties = new Dictionary <string, string> { { "funding-stream-id", fundingStreamId }, { "funding-period-id", fundingPeriodId } }; try { Job job = await _jobManagement.QueueJob(new JobCreateModel { JobDefinitionId = DeletePublishedProvidersJob, Properties = messageProperties, Trigger = new Trigger { EntityId = "N/A", Message = $"Requested deletion of published providers for funding stream {fundingStreamId} and funding period {fundingPeriodId}" }, CorrelationId = correlationId }); if (job != null) { _logger.Information($"New job of type '{DeletePublishedProvidersJob}' created with id: '{job.Id}'"); } else { _logger.Error( $"Failed to create job of type '{DeletePublishedProvidersJob}' on funding stream '{fundingStreamId}' and funding period {fundingPeriodId}"); } return(job); } catch (Exception ex) { _logger.Error(ex, $"Failed to create job of type '{DeletePublishedProvidersJob}' on funding stream '{fundingStreamId}' and funding period {fundingPeriodId}"); throw; } }
public async Task <IActionResult> QueueForSpecification(string specificationId) { Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId)); await _jobManagement.QueueJob(new JobCreateModel { JobDefinitionId = JobConstants.DefinitionNames.ReIndexSpecificationCalculationRelationshipsJob, SpecificationId = specificationId, Trigger = new Trigger { EntityId = specificationId, EntityType = nameof(Specification), Message = "Triggered for specification changes" }, Properties = new Dictionary <string, string> { { "specification-id", specificationId } } }); return(new OkResult()); }
private void GivenTheCreateJobThrowsException(Exception exception) { Jobs.QueueJob(Arg.Any <JobCreateModel>()) .Throws(exception); }
protected async Task <Job> QueueJob(JobCreateModel job) => await _jobManagement.QueueJob(job);
private void WhenJobIsCreateForARequestModelMatching(Expression <Predicate <JobCreateModel> > jobCreateModelMatching, Job job) { _jobs.QueueJob(Arg.Is(jobCreateModelMatching)) .Returns(job); }
public override async Task Process(Message message) { Guard.ArgumentNotNull(message, nameof(message)); string specificationId = message.GetUserProperty <string>(SpecificationIdKey); string fundingStreamId = message.GetUserProperty <string>(FundingStreamIdKey); string providerSnapshotIdValue = message.GetUserProperty <string>(ProviderSnapshotIdKey); string disableQueueCalculationJob = message.GetUserProperty <string>(DisableQueueCalculationJobKey); Reference user = message.GetUserDetails(); string correlationId = message.GetCorrelationId(); if (string.IsNullOrWhiteSpace(providerSnapshotIdValue) || !int.TryParse(providerSnapshotIdValue, out int providerSnapshotId)) { throw new NonRetriableException("Invalid provider snapshot id"); } ProviderSnapshot providerSnapshot = await GetProviderSnapshot(fundingStreamId, providerSnapshotId); string providerVersionId = $"{fundingStreamId}-{providerSnapshot.TargetDate:yyyy}-{providerSnapshot.TargetDate:MM}-{providerSnapshot.TargetDate:dd}-{providerSnapshotId}"; bool isProviderVersionExists = await _providerVersionService.Exists(providerVersionId); if (!isProviderVersionExists) { IEnumerable <Common.ApiClient.FundingDataZone.Models.Provider> fdzProviders = await GetProvidersInSnapshot(providerSnapshotId); ProviderVersionViewModel providerVersionViewModel = CreateProviderVersionViewModel(fundingStreamId, providerVersionId, providerSnapshot, fdzProviders); (bool success, IActionResult actionResult) = await _providerVersionService.UploadProviderVersion(providerVersionId, providerVersionViewModel); if (!success) { string errorMessage = $"Failed to upload provider version {providerVersionId}. {GetErrorMessage(actionResult, providerVersionId)}"; _logger.Error(errorMessage); throw new Exception(errorMessage); } } HttpStatusCode httpStatusCode = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.SetProviderVersion(specificationId, providerVersionId)); if (!httpStatusCode.IsSuccess()) { string errorMessage = $"Unable to update the specification - {specificationId}, with provider version id - {providerVersionId}. HttpStatusCode - {httpStatusCode}"; _logger.Error(errorMessage); throw new Exception(errorMessage); } JobCreateModel mapFdzDatasetsJobCreateModel = new JobCreateModel { Trigger = new Trigger { EntityId = specificationId, EntityType = "Specification", Message = "Map datasets for all relationships in specification" }, InvokerUserId = user.Id, InvokerUserDisplayName = user.Name, JobDefinitionId = JobConstants.DefinitionNames.MapFdzDatasetsJob, ParentJobId = null, SpecificationId = specificationId, CorrelationId = correlationId, Properties = new Dictionary <string, string> { { "specification-id", specificationId }, { "disableQueueCalculationJob", disableQueueCalculationJob }, } }; try { await _jobManagement.QueueJob(mapFdzDatasetsJobCreateModel); } catch (Exception ex) { string errorMessage = $"Failed to queue MapFdzDatasetsJob for specification - {specificationId}"; _logger.Error(ex, errorMessage); throw; } }
public async Task <Job> CreateJob(string specificationId, Reference user, string correlationId, Dictionary <string, string> properties = null, string messageBody = null, string parentJobId = null, bool compress = false) { Dictionary <string, string> messageProperties = properties ?? new Dictionary <string, string>(); messageProperties.Add("specification-id", specificationId); messageProperties.Add("user-id", user.Id); messageProperties.Add("user-name", user.Name); AddExtraMessageProperties(messageProperties); try { Job job = await _jobManagement.QueueJob(new JobCreateModel { InvokerUserDisplayName = user.Name, InvokerUserId = user.Id, JobDefinitionId = JobDefinitionId, Properties = messageProperties, MessageBody = messageBody ?? string.Empty, SpecificationId = specificationId, Trigger = new Trigger { EntityId = specificationId, EntityType = "Specification", Message = TriggerMessage }, CorrelationId = correlationId, Compress = compress }); if (!string.IsNullOrWhiteSpace(parentJobId)) { job.ParentJobId = parentJobId; } if (job != null) { _logger.Information($"New job of type '{job.JobDefinitionId}' created with id: '{job.Id}'"); } else { string errorMessage = $"Failed to create job of type '{job.JobDefinitionId}' on specification '{specificationId}'"; _logger.Error(errorMessage); } return(job); } catch (Exception ex) { string error = $"Failed to queue publishing of specification with id: {specificationId}"; _logger.Error(ex, error); throw new Exception(error); } }
public async Task CreateAdditionalCalculation_GivenCalcSaves_ReturnsOKObjectResult() { //Arrange string cacheKey = $"{CacheKeys.CalculationsMetadataForSpecification}{SpecificationId}"; CalculationCreateModel model = CreateCalculationCreateModel(); Reference author = CreateAuthor(); ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .CreateDraftCalculation(Arg.Any <Calculation>()) .Returns(HttpStatusCode.OK); IVersionRepository <CalculationVersion> versionRepository = CreateCalculationVersionRepository(); ISearchRepository <CalculationIndex> searchRepository = CreateSearchRepository(); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns(new Job { Id = "job-id-1" }); ISpecificationsApiClient specificationsApiClient = CreateSpecificationsApiClient(); specificationsApiClient .GetSpecificationSummaryById(Arg.Is(SpecificationId)) .Returns(new ApiResponse <SpecificationSummary>( HttpStatusCode.OK, new SpecificationSummary { Id = SpecificationId, FundingPeriod = new FundingPeriod { Id = FundingPeriodId } } )); ILogger logger = CreateLogger(); ICacheProvider cacheProvider = CreateCacheProvider(); ICodeContextCache codeContextCache = Substitute.For <ICodeContextCache>(); IResultsApiClient resultsApiClient = CreateResultsApiClient(); CalculationService calculationService = CreateCalculationService( calculationsRepository: calculationsRepository, calculationVersionRepository: versionRepository, searchRepository: searchRepository, jobManagement: jobManagement, logger: logger, cacheProvider: cacheProvider, specificationsApiClient: specificationsApiClient, codeContextCache: codeContextCache, resultsApiClient: resultsApiClient); IEnumerable <CalculationIndex> indexedCalculations = null; await searchRepository .Index(Arg.Do <IEnumerable <CalculationIndex> >(m => indexedCalculations = m )); CalculationVersion savedCalculationVersion = null; await versionRepository .SaveVersion(Arg.Do <CalculationVersion>(m => savedCalculationVersion = m)); //Act IActionResult result = await calculationService.CreateAdditionalCalculation(SpecificationId, model, author, CorrelationId); //Assert result .Should() .BeAssignableTo <OkObjectResult>(); Calculation calculation = (result as OkObjectResult).Value as Calculation; await jobManagement .Received(1) .QueueJob(Arg.Is <JobCreateModel>( m => m.InvokerUserDisplayName == Username && m.InvokerUserId == UserId && m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructAllocationJob && m.Properties["specification-id"] == SpecificationId )); logger .Received(1) .Information(Arg.Is($"New job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' created with id: 'job-id-1'")); await versionRepository .Received(1) .SaveVersion(Arg.Is <CalculationVersion>(m => m.PublishStatus == Models.Versioning.PublishStatus.Draft && m.Author.Id == UserId && m.Author.Name == Username && m.Date.Date == DateTimeOffset.Now.Date && m.Version == 1 && m.SourceCode == model.SourceCode && m.Description == model.Description && m.ValueType == model.ValueType && m.CalculationType == CalculationType.Additional && m.WasTemplateCalculation == false && m.Namespace == CalculationNamespace.Additional && m.Name == model.Name && m.SourceCodeName == new VisualBasicTypeIdentifierGenerator().GenerateIdentifier(model.Name) && m.DataType == CalculationDataType.Decimal )); await searchRepository .Received(1) .Index(Arg.Any <IEnumerable <CalculationIndex> >()); indexedCalculations .Should() .BeEquivalentTo(new List <CalculationIndex>() { new CalculationIndex() { CalculationType = "Additional", Description = "test description", FundingStreamId = "fs-1", FundingStreamName = model.FundingStreamName, Id = model.Id, Name = model.Name, Namespace = "Additional", SpecificationId = "spec-id-1", SpecificationName = "spec-id-1_specificationName", Status = "Draft", ValueType = "Currency", WasTemplateCalculation = false, LastUpdatedDate = savedCalculationVersion.Date, } }); //!string.IsNullOrWhiteSpace(m.First().Id) && //m.First().Name == model.Name && //m.First().SpecificationId == SpecificationId && //m.First().SpecificationName == model.SpecificationName && //m.First().ValueType == model.ValueType.ToString() && //m.First().CalculationType == CalculationType.Additional.ToString() && //m.First().Namespace == CalculationNamespace.Additional.ToString() && //m.First().FundingStreamId == model.FundingStreamId && //m.First().FundingStreamName == model.FundingStreamName && //m.First().WasTemplateCalculation == false && //m.First().Description == model.Description && //m.First().Status == calculation.Current.PublishStatus.ToString() await cacheProvider .Received(1) .RemoveAsync <List <CalculationMetadata> >(Arg.Is(cacheKey)); await codeContextCache .Received(1) .QueueCodeContextCacheUpdate(SpecificationId); }
public async Task <Job> SendInstructAllocationsToJobService(string specificationId, string userId, string userName, Trigger trigger, string correlationId, bool initiateCalcRUn = true) { Job parentJob = null; IEnumerable <Calculation> allCalculations = await _calculationRepositoryPolicy.ExecuteAsync(() => _calculationsRepository.GetCalculationsBySpecificationId(specificationId)); bool generateCalculationAggregations = SourceCodeHelpers.HasCalculationAggregateFunctionParameters(allCalculations.Select(m => m.Current.SourceCode)); string jobDefinitionId = generateCalculationAggregations ? JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob : JobConstants.DefinitionNames.CreateInstructAllocationJob; if (await GraphEnabled()) { // if the graph is enabled then we need to queue a reindex of the graph jobDefinitionId = JobConstants.DefinitionNames.ReIndexSpecificationCalculationRelationshipsJob; } JobCreateModel job = new JobCreateModel { InvokerUserDisplayName = userName, InvokerUserId = userId, JobDefinitionId = jobDefinitionId, SpecificationId = specificationId, Properties = new Dictionary <string, string> { { "specification-id", specificationId } }, Trigger = trigger, CorrelationId = correlationId }; if (await GraphEnabled()) { string parentJobDefinition = generateCalculationAggregations ? JobConstants.DefinitionNames.GenerateGraphAndInstructGenerateAggregationAllocationJob : JobConstants.DefinitionNames.GenerateGraphAndInstructAllocationJob; try { JobCreateModel instructJob = new JobCreateModel { InvokerUserDisplayName = userName, InvokerUserId = userId, JobDefinitionId = parentJobDefinition, SpecificationId = specificationId, Properties = new Dictionary <string, string> { { "specification-id", specificationId } }, Trigger = trigger, CorrelationId = correlationId }; parentJob = await _jobManagement.QueueJob(instructJob); _logger.Information($"New job of type '{parentJob.JobDefinitionId}' created with id: '{parentJob.Id}'"); } catch (Exception ex) { string errorMessage = $"Failed to create job of type '{parentJobDefinition}' on specification '{specificationId}'"; _logger.Error(ex, errorMessage); throw new RetriableException(errorMessage, ex); } } if (parentJob != null) { job.ParentJobId = parentJob.Id; } try { return(await _jobManagement.QueueJob(job)); } catch (Exception ex) { string errorMessage = $"Failed to create job of type '{job.JobDefinitionId}' on specification '{specificationId}'"; _logger.Error(ex, errorMessage); throw new RetriableException(errorMessage, ex); } }
public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameButCreatingJobReturnsNull_LogsError() { // Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" }, Name = "any-name" }, Previous = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); message.UserProperties.Add("user-id", UserId); message.UserProperties.Add("user-name", Username); ILogger logger = CreateLogger(); IEnumerable <Calculation> calcs = new[] { new Calculation { SpecificationId = "spec-id", Id = "any-id", Current = new CalculationVersion { Author = new Reference(UserId, Username), Date = DateTimeOffset.Now, PublishStatus = PublishStatus.Draft, SourceCode = "source code", Version = 1, Name = "any name", CalculationType = CalculationType.Template } } }; BuildProject buildProject = new BuildProject { Id = "build-project-1", SpecificationId = specificationId }; ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(calcs); IBuildProjectsService buildProjectsService = CreateBuildProjectsService(); buildProjectsService .GetBuildProjectForSpecificationId(Arg.Is(specificationId)) .Returns(buildProject); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns((Job)null); CalculationService service = CreateCalculationService( calculationsRepository, logger, buildProjectsService: buildProjectsService, jobManagement: jobManagement); // Act Func <Task> test = async() => await service.Run(message); // Assert test .Should() .ThrowExactly <RetriableException>() .Which .Message .Should() .Be($"Failed to create job: '{JobConstants.DefinitionNames.CreateInstructAllocationJob} for specification id '{specificationId}'"); await jobManagement .Received(1) .QueueJob(Arg.Is <JobCreateModel>( m => m.InvokerUserDisplayName == Username && m.InvokerUserId == UserId && m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructAllocationJob && m.Properties["specification-id"] == specificationId && m.Trigger.EntityId == specificationId && m.Trigger.EntityType == "Specification" && m.Trigger.Message == $"Updating calculations for specification: '{specificationId}'" )); logger .Received(1) .Error(Arg.Is($"Failed to create job: '{JobConstants.DefinitionNames.CreateInstructAllocationJob} for specification id '{specificationId}'")); }
public async Task UpdateCalculationsForSpecification_GivenModelHasChangedPolicyNameAndSourceCodeContainsCalculationAggregate_SavesChangesEnsuresGenerateAggregationsJobCreated() { // Arrange const string specificationId = "spec-id"; SpecificationVersionComparisonModel specificationVersionComparison = new SpecificationVersionComparisonModel() { Id = specificationId, Current = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" }, Name = "any-name" }, Previous = new SpecificationVersion { FundingPeriod = new Reference { Id = "fp1" } } }; string json = JsonConvert.SerializeObject(specificationVersionComparison); Message message = new Message(Encoding.UTF8.GetBytes(json)); message.UserProperties.Add("user-id", UserId); message.UserProperties.Add("user-name", Username); ILogger logger = CreateLogger(); IEnumerable <Calculation> calcs = new[] { new Calculation { SpecificationId = "spec-id", Id = "any-id", Current = new CalculationVersion { Author = new Reference(UserId, Username), Date = DateTimeOffset.Now, PublishStatus = PublishStatus.Draft, SourceCode = "return Min(calc1)", Version = 1, Name = "any name", CalculationType = CalculationType.Template } } }; BuildProject buildProject = new BuildProject { Id = "build-project-1", SpecificationId = specificationId }; ICalculationsRepository calculationsRepository = CreateCalculationsRepository(); calculationsRepository .GetCalculationsBySpecificationId(Arg.Is(specificationId)) .Returns(calcs); IBuildProjectsService buildProjectsService = CreateBuildProjectsService(); buildProjectsService .GetBuildProjectForSpecificationId(Arg.Is(specificationId)) .Returns(buildProject); IJobManagement jobManagement = CreateJobManagement(); jobManagement .QueueJob(Arg.Any <JobCreateModel>()) .Returns(new Job { Id = "job-id-1", JobDefinitionId = JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob }); CalculationService service = CreateCalculationService( calculationsRepository, logger, buildProjectsService: buildProjectsService, jobManagement: jobManagement); // Act await service.Run(message); // Assert await jobManagement .Received(1) .QueueJob(Arg.Is <JobCreateModel>( m => m.InvokerUserDisplayName == Username && m.InvokerUserId == UserId && m.JobDefinitionId == JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob && m.Properties["specification-id"] == specificationId && m.Trigger.EntityId == specificationId && m.Trigger.EntityType == "Specification" && m.Trigger.Message == $"Updating calculations for specification: '{specificationId}'" )); logger .Received(1) .Information(Arg.Is($"New job of type '{JobConstants.DefinitionNames.CreateInstructGenerateAggregationsAllocationJob}' created with id: 'job-id-1'")); }
public async Task <IActionResult> AssignDatasourceVersionToRelationship(AssignDatasourceModel model, Reference user, string correlationId) { if (model == null) { _logger.Error("Null AssignDatasourceModel was provided to AssignDatasourceVersionToRelationship"); return(new BadRequestObjectResult("Null AssignDatasourceModel was provided")); } Dataset dataset = await _datasetRepository.GetDatasetByDatasetId(model.DatasetId); if (dataset == null) { _logger.Error($"Dataset not found for dataset id: {model.DatasetId}"); return(new StatusCodeResult(412)); } DefinitionSpecificationRelationship relationship = await _datasetRepository.GetDefinitionSpecificationRelationshipById(model.RelationshipId); if (relationship == null) { _logger.Error($"Relationship not found for relationship id: {model.RelationshipId}"); return(new StatusCodeResult(412)); } relationship.Author = user; relationship.LastUpdated = _dateTimeProvider.UtcNow; relationship.DatasetVersion = new DatasetRelationshipVersion { Id = model.DatasetId, Version = model.Version }; HttpStatusCode statusCode = await _datasetRepository.UpdateDefinitionSpecificationRelationship(relationship); if (!statusCode.IsSuccess()) { _logger.Error($"Failed to assign data source to relationship : {model.RelationshipId} with status code {statusCode.ToString()}"); return(new StatusCodeResult((int)statusCode)); } IEnumerable <CalculationResponseModel> allCalculations = await _calcsRepository.GetCurrentCalculationsBySpecificationId(relationship.Specification.Id); bool generateCalculationAggregations = !allCalculations.IsNullOrEmpty() && SourceCodeHelpers.HasCalculationAggregateFunctionParameters(allCalculations.Select(m => m.SourceCode)); Trigger trigger = new Trigger { EntityId = dataset.Id, EntityType = nameof(Dataset), Message = $"Mapping dataset: '{dataset.Id}'" }; JobCreateModel job = new JobCreateModel { InvokerUserDisplayName = user?.Name, InvokerUserId = user?.Id, JobDefinitionId = JobConstants.DefinitionNames.MapDatasetJob, MessageBody = JsonConvert.SerializeObject(dataset), Properties = new Dictionary <string, string> { { "specification-id", relationship.Specification.Id }, { "relationship-id", relationship.Id }, { "user-id", user?.Id }, { "user-name", user?.Name }, }, SpecificationId = relationship.Specification.Id, Trigger = trigger, CorrelationId = correlationId }; Job parentJob = null; if (relationship.IsSetAsProviderData) { string parentJobDefinition = generateCalculationAggregations ? JobConstants.DefinitionNames.MapScopedDatasetJobWithAggregation : JobConstants.DefinitionNames.MapScopedDatasetJob; parentJob = await _jobManagement.QueueJob(new JobCreateModel { InvokerUserDisplayName = user?.Name, InvokerUserId = user?.Id, JobDefinitionId = parentJobDefinition, Properties = new Dictionary <string, string> { { "specification-id", relationship.Specification.Id }, { "provider-cache-key", $"{CacheKeys.ScopedProviderSummariesPrefix}{relationship.Specification.Id}" }, { "specification-summary-cache-key", $"{CacheKeys.SpecificationSummaryById}{relationship.Specification.Id}" } }, SpecificationId = relationship.Specification.Id, Trigger = trigger, CorrelationId = correlationId }); } if (parentJob != null) { job.ParentJobId = parentJob.Id; job.Properties.Add("parentJobId", parentJob.Id); } await _jobManagement.QueueJob(job); return(new NoContentResult()); }