public void GetBulkhead_WhenInitializingBulkheadAndMaxConcurrentConfigIsInvalid_AndThenConfigChangedToValidValue_CreatesBulkhead() { // Arrange var key = AnyGroupKey; const int invalidMaxConcurrent = -1; const int validMaxConcurrent = 1; var mockMetricEvents = new Mock <IMetricEvents>(MockBehavior.Strict); var mockConfig = new MjolnirConfiguration { BulkheadConfigurations = new Dictionary <string, BulkheadConfiguration> { { key.Name, new BulkheadConfiguration { MaxConcurrent = invalidMaxConcurrent } } } }; var mockLogFactory = new Mock <IMjolnirLogFactory>(MockBehavior.Strict); mockLogFactory.Setup(m => m.CreateLog <BulkheadFactory>()).Returns(new DefaultMjolnirLog <BulkheadFactory>()); mockLogFactory.Setup(m => m.CreateLog <SemaphoreBulkheadHolder>()).Returns(new DefaultMjolnirLog <SemaphoreBulkheadHolder>()); var factory = new BulkheadFactory(mockMetricEvents.Object, mockConfig, mockLogFactory.Object); try { factory.GetBulkhead(key); } catch (ArgumentOutOfRangeException) { // Expected, config is invalid for the first attempt. } mockConfig.BulkheadConfigurations = new Dictionary <string, BulkheadConfiguration> { { key.Name, new BulkheadConfiguration { MaxConcurrent = validMaxConcurrent } } }; mockConfig.NotifyAfterConfigUpdate(); // Act var bulkhead = factory.GetBulkhead(key); // Should not throw. // Assert Assert.Equal(validMaxConcurrent, bulkhead.CountAvailable); }
private async Task ReloadConfig() { while (true) { _root = LoadConfigFromJsonFile(); // We can add some deep comparision between _currentConfig and new config here so // we notify our observers only when config really changes _currentConfig?.NotifyAfterConfigUpdate(); await Task.Delay(_updateTimeInterval); } }
public void GetBulkhead_ReturnsNewBulkheadWhenConfigChanges() { // Config can be used to resize the bulkhead at runtime, which results in a new // bulkhead being created. // To ensure consistency, callers who retrieve a bulkhead and call TryEnter() // on it should keep a local reference to the same bulkhead to later call // Release() on (rather than re-retrieving the bulkhead from the context). // That behavior is tested elsewhere (with the BulkheadInvoker tests). // Arrange var key = AnyString; var groupKey = GroupKey.Named(key); const int initialExpectedCount = 5; const int newExpectedCount = 6; var mockMetricEvents = new Mock <IMetricEvents>(MockBehavior.Strict); var mockConfig = new MjolnirConfiguration { BulkheadConfigurations = new Dictionary <string, BulkheadConfiguration> { { groupKey.Name, new BulkheadConfiguration { MaxConcurrent = initialExpectedCount } } } }; var mockLogFactory = new Mock <IMjolnirLogFactory>(MockBehavior.Strict); mockLogFactory.Setup(m => m.CreateLog <BulkheadFactory>()).Returns(new DefaultMjolnirLog <BulkheadFactory>()); mockLogFactory.Setup(m => m.CreateLog <SemaphoreBulkheadHolder>()).Returns(new DefaultMjolnirLog <SemaphoreBulkheadHolder>()); var factory = new BulkheadFactory(mockMetricEvents.Object, mockConfig, mockLogFactory.Object); // Act var firstBulkhead = factory.GetBulkhead(groupKey); mockConfig.BulkheadConfigurations = new Dictionary <string, BulkheadConfiguration> { { groupKey.Name, new BulkheadConfiguration { MaxConcurrent = newExpectedCount } } }; mockConfig.NotifyAfterConfigUpdate(); // Give the change handler callback enough time to create and reassign the bulkhead. Thread.Sleep(500); var secondBulkhead = factory.GetBulkhead(groupKey); // Assert // Shouldn't change any existing referenced bulkheads... Assert.Equal(initialExpectedCount, firstBulkhead.CountAvailable); // ...but newly-retrieved bulkheads should get a new instance // with the updated count. Assert.Equal(newExpectedCount, secondBulkhead.CountAvailable); // And they shouldn't be the same bulkhead (which should be obvious by this point). Assert.False(firstBulkhead == secondBulkhead); }