// ReSharper restore NotAccessedField.Local internal SemaphoreSlimIsolationSemaphore(GroupKey key, IConfigurableValue<int> maxConcurrent, IStats stats, IConfigurableValue<long> gaugeIntervalMillisOverride = null) { _key = key; if (stats == null) { throw new ArgumentNullException("stats"); } _stats = stats; // Note: Changing the semaphore maximum at runtime is not currently supported. _maxConcurrent = maxConcurrent.Value; _semaphore = new SemaphoreSlim(_maxConcurrent); _timer = new GaugeTimer((source, args) => { var count = _semaphore.CurrentCount; _stats.Gauge(StatsPrefix + " available", (count == 0 ? "Full" : "Available"), count); }, gaugeIntervalMillisOverride); }
internal FailurePercentageCircuitBreaker(GroupKey key, IClock clock, ICommandMetrics metrics, IStats stats, IMetricEvents metricEvents, FailurePercentageCircuitBreakerProperties properties, IConfigurableValue<long> gaugeIntervalMillisOverride = null) { _key = key; _clock = clock; _metrics = metrics; if (stats == null) { throw new ArgumentNullException("stats"); } if (metricEvents == null) { throw new ArgumentNullException("metricEvents"); } _stats = stats; _metricEvents = metricEvents; Properties = properties; _state = State.Fixed; // Start off assuming everything's fixed. _lastTrippedTimestamp = 0; // 0 is fine since it'll be far less than the first compared value. // Old gauge, will be phased out in v3.0 when IStats are removed. _statsTimer = new GaugeTimer((source, args) => { var snapshot = _metrics.GetSnapshot(); _stats.Gauge(StatsPrefix + " total", snapshot.Total >= properties.MinimumOperations.Value ? "Above" : "Below", snapshot.Total); _stats.Gauge(StatsPrefix + " error", snapshot.ErrorPercentage >= properties.ThresholdPercentage.Value ? "Above" : "Below", snapshot.ErrorPercentage); }, gaugeIntervalMillisOverride); _metricsTimer = new GaugeTimer((source, args) => { _metricEvents.BreakerConfigGauge( Name, Properties.MinimumOperations.Value, Properties.ThresholdPercentage.Value, Properties.TrippedDurationMillis.Value); }, ConfigGaugeIntervalMillis); }
public SemaphoreBulkheadHolder(GroupKey key, IMetricEvents metricEvents) { if (metricEvents == null) { throw new ArgumentNullException("metricEvents"); } _metricEvents = metricEvents; // The order of things here is very intentional. // We create the configurable value first, retrieve its current value, and then // initialize the semaphore bulkhead. We register the change handler after that. // That 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 configKey = "mjolnir.bulkhead." + key + ".maxConcurrent"; _config = new ConfigurableValue<int>(configKey, DefaultBulkheadMaxConcurrent); var value = _config.Value; _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.AddChangeHandler(newLimit => { if (newLimit < 0) { Log.ErrorFormat("Semaphore bulkhead config {0} changed to an invalid limit of {0}, the bulkhead will not be changed", configKey, newLimit); return; } _bulkhead = new SemaphoreBulkhead(key, newLimit); }); _timer = new GaugeTimer((source, args) => { _metricEvents.BulkheadConfigGauge(_bulkhead.Name, "semaphore", _config.Value); }, ConfigGaugeIntervalMillis); }