예제 #1
0
            public SemaphoreBulkheadHolder(GroupKey key, IMetricEvents metricEvents, MjolnirConfiguration config, IMjolnirLogFactory logFactory)
            {
                _key          = key;
                _metricEvents = metricEvents ?? throw new ArgumentNullException(nameof(metricEvents));
                _config       = config ?? throw new ArgumentNullException(nameof(config));

                if (logFactory == null)
                {
                    throw new ArgumentNullException(nameof(logFactory));
                }

                _log = logFactory.CreateLog <SemaphoreBulkheadHolder>();
                if (_log == null)
                {
                    throw new InvalidOperationException($"{nameof(IMjolnirLogFactory)} implementation returned null from {nameof(IMjolnirLogFactory.CreateLog)} for type {typeof(SemaphoreBulkheadHolder)}, please make sure the implementation returns a non-null log for all calls to {nameof(IMjolnirLogFactory.CreateLog)}");
                }

                // The order of things here is very intentional.
                // We get the MaxConcurrent value first and then initialize the semaphore bulkhead.
                // The change handler is registered after that. The order ought to help avoid a
                // situation where we might fire a config change handler before we add the
                // semaphore to the dictionary, potentially trying to add two entries with
                // different values in rapid succession.

                var value = _config.GetBulkheadConfiguration(key.Name).MaxConcurrent;

                _bulkhead = new SemaphoreBulkhead(_key, value);

                // On change, we'll replace the bulkhead. The assumption here is that a caller
                // using the bulkhead will have kept a local reference to the bulkhead that they
                // acquired a lock on, and will release the lock on that bulkhead and not one that
                // has been replaced after a config change.
                _config.OnConfigurationChanged(c => c.GetBulkheadConfiguration(key.Name).MaxConcurrent, UpdateMaxConcurrent);
            }
예제 #2
0
        public void GetMaxConcurrent_UsesSpecificValueIfConfigured()
        {
            // Arrange

            var groupKey            = AnyGroupKey;
            var expectedConfigValue = AnyPositiveInt;

            var config = new MjolnirConfiguration
            {
                BulkheadConfigurations = new Dictionary <string, BulkheadConfiguration>
                {
                    {
                        groupKey.Name,
                        new BulkheadConfiguration
                        {
                            MaxConcurrent = expectedConfigValue
                        }
                    }
                }
            };

            // Act

            var value = config.GetBulkheadConfiguration(groupKey.Name).MaxConcurrent;

            // Assert

            Assert.Equal(expectedConfigValue, value);
        }
예제 #3
0
        public void GetMaxConcurrent_UsesDefaultValueIfNoSpecificValueConfigured()
        {
            // Arrange

            var groupKey            = AnyGroupKey;
            var expectedConfigValue = AnyPositiveInt;

            var config = new MjolnirConfiguration
            {
                DefaultBulkheadConfiguration = new BulkheadConfiguration
                {
                    MaxConcurrent = expectedConfigValue
                }
            };

            // Act

            var value = config.GetBulkheadConfiguration(groupKey.Name).MaxConcurrent;

            // Assert

            Assert.Equal(expectedConfigValue, value);
        }
예제 #4
0
        // ReSharper restore PrivateFieldCanBeConvertedToLocalVariable

        public BulkheadFactory(IMetricEvents metricEvents, MjolnirConfiguration config, IMjolnirLogFactory logFactory)
        {
            // No null checks on parameters; we don't use them, we're just passing them through to
            // the objects we're creating.

            _metricEvents = metricEvents;
            _config       = config;
            _logFactory   = logFactory ?? throw new ArgumentNullException(nameof(logFactory));

            var log = logFactory.CreateLog <BulkheadFactory>();

            if (log == null)
            {
                throw new InvalidOperationException($"{nameof(IMjolnirLogFactory)} implementation returned null from {nameof(IMjolnirLogFactory.CreateLog)} for type {typeof(BulkheadFactory)}, please make sure the implementation returns a non-null log for all calls to {nameof(IMjolnirLogFactory.CreateLog)}");
            }

            _timer = new GaugeTimer(state =>
            {
                try
                {
                    var keys = _bulkheads.Keys;
                    foreach (var key in keys)
                    {
                        if (_bulkheads.TryGetValue(key, out Lazy <SemaphoreBulkheadHolder> holder) && holder.IsValueCreated)
                        {
                            var bulkhead = holder.Value.Bulkhead;
                            _metricEvents.BulkheadGauge(bulkhead.Name, "semaphore", _config.GetBulkheadConfiguration(key.Name).MaxConcurrent, bulkhead.CountAvailable);
                        }
                    }
                }
                catch (Exception e)
                {
                    log.Error($"Error sending {nameof(IMetricEvents.BulkheadGauge)} metric event", e);
                }
            });
        }
예제 #5
0
        public void GetMaxConcurrent_UsesDefaultValueIfNoSpecificValueOrDefaultValueConfigured_DefaultIs10()
        {
            // Arrange

            const int expectedDefaultMaxConcurrent = 10;

            var groupKey = AnyGroupKey;

            var config = new MjolnirConfiguration
            {
                DefaultBulkheadConfiguration = new BulkheadConfiguration
                {
                    MaxConcurrent = expectedDefaultMaxConcurrent
                }
            };

            // Act

            var value = config.GetBulkheadConfiguration(groupKey.Name).MaxConcurrent;

            // Assert

            Assert.Equal(expectedDefaultMaxConcurrent, value);
        }