public async Task ScaleUp(IEnumerable <EventData> events) { Guard.ArgumentNotNull(events, nameof(events)); IEnumerable <string> collectionsToProcess = _cosmosDbThrottledEventsFilter.GetUniqueCosmosDBContainerNamesFromEventData(events); if (collectionsToProcess.IsNullOrEmpty()) { return; } _logger.Information($"Found {collectionsToProcess.Count()} collections to process"); foreach (string containerName in collectionsToProcess) { try { CosmosCollectionType cosmosRepositoryType = containerName.GetEnumValueFromDescription <CosmosCollectionType>(); CosmosDbScalingCollectionSettings settings = await _scalingConfigRepositoryPolicy.ExecuteAsync(() => _cosmosDbScalingConfigRepository.GetCollectionSettingsByRepositoryType(cosmosRepositoryType)); int currentThroughput = settings.CurrentRequestUnits; if (settings.AvailableRequestUnits == 0) { string errorMessage = $"The collection '{containerName}' throughput is already at the maximum of {settings.MaxRequestUnits} RU's"; _logger.Warning(errorMessage); continue; } int incrementalRequestUnitsValue = scaleUpIncrementValue; int increasedRequestUnits = currentThroughput + incrementalRequestUnitsValue; if (incrementalRequestUnitsValue > settings.AvailableRequestUnits) { increasedRequestUnits = settings.MaxRequestUnits; incrementalRequestUnitsValue = settings.AvailableRequestUnits; } settings.CurrentRequestUnits = await ScaleCollection(cosmosRepositoryType, increasedRequestUnits, settings.MaxRequestUnits); await UpdateCollectionSettings(settings, CosmosDbScalingDirection.Up, incrementalRequestUnitsValue); } catch (NonRetriableException) { throw; } catch (Exception ex) { string errorMessage = $"Failed to increase cosmosdb request units on collection '{containerName}'"; _logger.Error(ex, errorMessage); throw new RetriableException(errorMessage, ex); } } }
public async Task <CosmosDbScalingConfig> GetConfigByRepositoryType(CosmosCollectionType cosmosCollectionType) { Guard.ArgumentNotNull(cosmosCollectionType, nameof(cosmosCollectionType)); IQueryable <CosmosDbScalingConfig> configs = _cosmosRepository.Query <CosmosDbScalingConfig>().Where(x => x.RepositoryType == cosmosCollectionType); return(await Task.FromResult(configs.AsEnumerable().FirstOrDefault())); }
public async Task <CosmosDbScalingConfig> GetConfigByRepositoryType(CosmosCollectionType cosmosCollectionType) { Guard.ArgumentNotNull(cosmosCollectionType, nameof(cosmosCollectionType)); IEnumerable <CosmosDbScalingConfig> configs = (await _cosmosRepository.Query <CosmosDbScalingConfig>(x => x.Content.RepositoryType == cosmosCollectionType)); return(configs.FirstOrDefault()); }
private async Task ScaleCollection(CosmosCollectionType cosmosRepositoryType, int requestUnits) { ICosmosDbScalingRepository cosmosDbScalingRepository = _cosmosDbScalingRepositoryProvider.GetRepository(cosmosRepositoryType); try { await _scalingRepositoryPolicy.ExecuteAsync(() => cosmosDbScalingRepository.SetThroughput(requestUnits)); } catch (Exception ex) { _logger.Error(ex, $"Failed to set throughput on repository type '{cosmosRepositoryType}' with '{requestUnits}' request units"); throw; } }
public ICosmosDbScalingRepository GetRepository(CosmosCollectionType repositoryType) { switch (repositoryType) { case CosmosCollectionType.CalculationProviderResults: return(_serviceProvider.GetService <CalculationProviderResultsScalingRepository>()); case CosmosCollectionType.ProviderSourceDatasets: return(_serviceProvider.GetService <ProviderSourceDatasetsScalingRepository>()); case CosmosCollectionType.PublishedFunding: return(_serviceProvider.GetService <PublishedFundingScalingRepository>()); case CosmosCollectionType.Calculations: return(_serviceProvider.GetService <CalculationsScalingRepository>()); case CosmosCollectionType.Jobs: return(_serviceProvider.GetService <JobsScalingRepository>()); case CosmosCollectionType.DatasetAggregations: return(_serviceProvider.GetService <DatasetAggregationsScalingRepository>()); case CosmosCollectionType.Datasets: return(_serviceProvider.GetService <DatasetsScalingRepository>()); case CosmosCollectionType.Profiling: return(_serviceProvider.GetService <ProfilingScalingRepository>()); case CosmosCollectionType.Specifications: return(_serviceProvider.GetService <SpecificationsScalingRepository>()); case CosmosCollectionType.TestResults: return(_serviceProvider.GetService <TestResultsScalingRepository>()); case CosmosCollectionType.Tests: return(_serviceProvider.GetService <TestsScalingRepository>()); case CosmosCollectionType.Users: return(_serviceProvider.GetService <UsersScalingRepository>()); default: throw new ArgumentException("Invalid repository type provided"); } }
public async Task <int> ScaleCollection(CosmosCollectionType cosmosRepositoryType, int requestUnits, int maxRequestUnits) { ICosmosDbScalingRepository cosmosDbScalingRepository = _cosmosDbScalingRepositoryProvider.GetRepository(cosmosRepositoryType); int throughPutRequestUnits = Math.Min(requestUnits, maxRequestUnits); try { await _scalingRepositoryPolicy.ExecuteAsync(async() => await cosmosDbScalingRepository.SetThroughput(throughPutRequestUnits)); return(throughPutRequestUnits); } catch (Exception ex) { _logger.Error(ex, $"Failed to set throughput on repository type '{cosmosRepositoryType}' with '{requestUnits}' request units"); throw; } }
public void GetRepository_GivenRepositoryType_ReturnsInstanceOfCorrectRepository(CosmosCollectionType cosmosRepositoryType, string repositoryTypeName) { //Arrange CosmosCollectionType repositoryType = cosmosRepositoryType; IServiceProvider serviceProvider = CreateServiceProvider(); CosmosDbScalingRepositoryProvider scalingRepositoryProvider = new CosmosDbScalingRepositoryProvider(serviceProvider); //Act ICosmosDbScalingRepository scalingRepository = scalingRepositoryProvider.GetRepository(repositoryType); //Assert //AB: using gettype and name rather than assignable tp because ncrunch throws a wobbly scalingRepository .GetType() .Name .Should() .Be(repositoryTypeName); }
public void GetRepository_GivenRepositoryTypeIsNotValid_ThrowsArgumentException() { //Arrange CosmosCollectionType repositoryType = (CosmosCollectionType)42; IServiceProvider serviceProvider = CreateServiceProvider(); CosmosDbScalingRepositoryProvider scalingRepositoryProvider = new CosmosDbScalingRepositoryProvider(serviceProvider); //Act Action test = () => scalingRepositoryProvider.GetRepository(repositoryType); //Assert test .Should() .ThrowExactly <ArgumentException>() .Which .Message .Should() .Be("Invalid repository type provided"); }
public async Task <CosmosDbScalingCollectionSettings> GetCollectionSettingsByRepositoryType(CosmosCollectionType cosmosCollectionType) { Guard.ArgumentNotNull(cosmosCollectionType, nameof(cosmosCollectionType)); IEnumerable <CosmosDbScalingCollectionSettings> settings = (await _cosmosRepository.Query <CosmosDbScalingCollectionSettings>(x => x.Content.CosmosCollectionType == cosmosCollectionType)); return(settings?.AsEnumerable().FirstOrDefault()); }
private async Task <int?> GetMinimumThroughput(CosmosCollectionType collectionType) { ICosmosDbScalingRepository cosmosDbScalingRepository = _cosmosDbScalingRepositoryProvider.GetRepository(collectionType); return(await _scalingRepositoryPolicy.ExecuteAsync(async() => await cosmosDbScalingRepository.GetMinimumThroughput())); }