private async Task <(IEnumerable <CalculationAggregation>, long)> BuildAggregations(GenerateAllocationMessageProperties messageProperties)
        {
            Stopwatch sw = Stopwatch.StartNew();
            BuildAggregationRequest aggreagationRequest = new BuildAggregationRequest
            {
                BatchCount = messageProperties.BatchCount,
                GenerateCalculationAggregationsOnly = messageProperties.GenerateCalculationAggregationsOnly,
                SpecificationId = messageProperties.SpecificationId
            };

            IEnumerable <CalculationAggregation> aggregations = await _calculationAggregationService.BuildAggregations(aggreagationRequest);

            return(aggregations, sw.ElapsedMilliseconds);
        }
        public async Task <IEnumerable <CalculationAggregation> > BuildAggregations(BuildAggregationRequest aggreagationRequest)
        {
            IEnumerable <CalculationAggregation> aggregations = Enumerable.Empty <CalculationAggregation>();

            aggregations = await _cacheProvider.GetAsync <List <CalculationAggregation> >(
                $"{ CacheKeys.DatasetAggregationsForSpecification}{aggreagationRequest.SpecificationId}");

            if (DoesNotExistInCache(aggregations))
            {
                aggregations = (await _datasetAggregationsRepository.GetDatasetAggregationsForSpecificationId(aggreagationRequest.SpecificationId)).Select(m => new CalculationAggregation
                {
                    SpecificationId = m.SpecificationId,
                    Values          = m.Fields.IsNullOrEmpty() ? Enumerable.Empty <AggregateValue>() : m.Fields.Select(f => new AggregateValue
                    {
                        AggregatedType      = f.FieldType,
                        FieldDefinitionName = f.FieldDefinitionName,
                        Value = f.Value
                    })
                });

                await _cacheProvider.SetAsync($"{CacheKeys.DatasetAggregationsForSpecification}{aggreagationRequest.SpecificationId}", aggregations.ToList());
            }

            if (!aggreagationRequest.GenerateCalculationAggregationsOnly)
            {
                ConcurrentDictionary <string, List <decimal> > cachedCalculationAggregations = new ConcurrentDictionary <string, List <decimal> >(
                    StringComparer.InvariantCultureIgnoreCase);

                List <Task>   allTasks  = new List <Task>();
                SemaphoreSlim throttler = new SemaphoreSlim(_engineSettings.CalculationAggregationRetreivalParallelism);

                for (int i = 1; i <= aggreagationRequest.BatchCount; i++)
                {
                    await throttler.WaitAsync();

                    int currentBatchNumber = i;

                    allTasks.Add(
                        Task.Run(async() =>
                    {
                        try
                        {
                            string batchedCacheKey = $"{CacheKeys.CalculationAggregations}{aggreagationRequest.SpecificationId}_{currentBatchNumber}";

                            Dictionary <string, List <decimal> > cachedCalculationAggregationsPart = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <Dictionary <string, List <decimal> > >(batchedCacheKey));

                            if (!cachedCalculationAggregationsPart.IsNullOrEmpty())
                            {
                                foreach (KeyValuePair <string, List <decimal> > cachedAggregations in cachedCalculationAggregationsPart)
                                {
                                    List <decimal> values = cachedCalculationAggregations.GetOrAdd(cachedAggregations.Key, new List <decimal>());

                                    values.AddRange(cachedAggregations.Value);
                                }
                            }
                        }
                        finally
                        {
                            throttler.Release();
                        }
                    }));
                }

                await TaskHelper.WhenAllAndThrow(allTasks.ToArray());

                if (!cachedCalculationAggregations.IsNullOrEmpty())
                {
                    foreach (KeyValuePair <string, List <decimal> > cachedCalculationAggregation in cachedCalculationAggregations.OrderBy(o => o.Key))
                    {
                        aggregations = aggregations.Concat(new[]
                        {
                            new CalculationAggregation
                            {
                                SpecificationId = aggreagationRequest.SpecificationId,
                                Values          = new []
                                {
                                    new AggregateValue {
                                        FieldDefinitionName = cachedCalculationAggregation.Key, AggregatedType = AggregatedType.Sum, Value = cachedCalculationAggregation.Value.Sum()
                                    },
                                    new AggregateValue {
                                        FieldDefinitionName = cachedCalculationAggregation.Key, AggregatedType = AggregatedType.Min, Value = cachedCalculationAggregation.Value.Min()
                                    },
                                    new AggregateValue {
                                        FieldDefinitionName = cachedCalculationAggregation.Key, AggregatedType = AggregatedType.Max, Value = cachedCalculationAggregation.Value.Max()
                                    },
                                    new AggregateValue {
                                        FieldDefinitionName = cachedCalculationAggregation.Key, AggregatedType = AggregatedType.Average, Value = cachedCalculationAggregation.Value.Average()
                                    },
                                }
                            }
                        });
                    }
                }
            }

            return(aggregations);
        }
示例#3
0
        public async Task <IActionResult> PreviewCalculationResult(
            string specificationId,
            string providerId,
            PreviewCalculationRequest previewCalculationRequest)
        {
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));
            Guard.IsNullOrWhiteSpace(providerId, nameof(providerId));
            Guard.ArgumentNotNull(previewCalculationRequest, nameof(previewCalculationRequest));

            Assembly         assembly        = Assembly.Load(previewCalculationRequest.AssemblyContent);
            IAllocationModel allocationModel = _calculationEngine.GenerateAllocationModel(assembly);

            SpecificationSummary specificationSummary = await GetSpecificationSummary(specificationId);

            ApiResponse <ProviderVersionSearchResult> providerVersionSearchResultApiResponse =
                await _providersApiClientPolicy.ExecuteAsync(() => _providersApiClient.GetProviderByIdFromProviderVersion(
                                                                 specificationSummary.ProviderVersionId,
                                                                 providerId));

            ProviderVersionSearchResult providerVersionSearchResult = providerVersionSearchResultApiResponse.Content;

            if (providerVersionSearchResult == null)
            {
                return(new NotFoundResult());
            }

            ProviderSummary providerSummary = _mapper.Map <ProviderSummary>(providerVersionSearchResult);

            List <CalculationSummaryModel>        calculationSummaries     = new List <CalculationSummaryModel>();
            IEnumerable <CalculationSummaryModel> specCalculationSummaries = await GetCalculationSummaries(specificationId);

            calculationSummaries.AddRange(specCalculationSummaries);
            calculationSummaries.Add(previewCalculationRequest.PreviewCalculationSummaryModel);

            Dictionary <string, Dictionary <string, ProviderSourceDataset> > providerSourceDatasets =
                await _providerSourceDatasetsRepository.GetProviderSourceDatasetsByProviderIdsAndRelationshipIds(
                    specificationId,
                    new[] { providerId },
                    specificationSummary.DataDefinitionRelationshipIds);

            Dictionary <string, ProviderSourceDataset> providerSourceDataset = providerSourceDatasets[providerId];

            BuildAggregationRequest buildAggregationRequest = new BuildAggregationRequest
            {
                SpecificationId = specificationId,
                GenerateCalculationAggregationsOnly = true,
                BatchCount = 100
            };
            IEnumerable <CalculationAggregation> calculationAggregations =
                await _calculationAggregationService.BuildAggregations(buildAggregationRequest);

            ProviderResult providerResult = _calculationEngine.CalculateProviderResults(
                allocationModel,
                specificationId,
                calculationSummaries,
                providerSummary,
                providerSourceDataset,
                calculationAggregations
                );

            return(new OkObjectResult(providerResult));
        }