using System; namespace GermanApp.Infrastructure.Services; /// /// Circuit breaker implementation for Mistral API. /// Prevents cascading failures by temporarily blocking requests after too many failures. /// This is part of the Infrastructure layer. /// public class MistralCircuitBreaker { private readonly int _failureThreshold; private readonly TimeSpan _resetTimeout; private int _failureCount = 0; private DateTime _lastFailureTime = DateTime.MinValue; private readonly object _lock = new(); /// /// Creates a new circuit breaker. /// /// Number of consecutive failures before opening the circuit /// Time to wait before attempting to close the circuit public MistralCircuitBreaker(int failureThreshold, TimeSpan resetTimeout) { _failureThreshold = failureThreshold; _resetTimeout = resetTimeout; } /// /// Gets whether the circuit is currently closed (allowing requests). /// public bool IsClosed { get { if (_failureCount >= _failureThreshold) { // Circuit is open, check if reset timeout has elapsed if (DateTime.UtcNow - _lastFailureTime > _resetTimeout) { // Reset the circuit lock (_lock) { if (_failureCount >= _failureThreshold && DateTime.UtcNow - _lastFailureTime > _resetTimeout) { _failureCount = 0; _lastFailureTime = DateTime.MinValue; } } } else { return false; } } return true; } } /// /// Gets the current failure count. /// public int FailureCount => _failureCount; /// /// Gets the last failure time. /// public DateTime LastFailureTime => _lastFailureTime; /// /// Records a successful request, resetting the failure count. /// public void RecordSuccess() { lock (_lock) { _failureCount = 0; _lastFailureTime = DateTime.MinValue; } } /// /// Records a failed request, incrementing the failure count. /// public void RecordFailure() { lock (_lock) { _failureCount++; _lastFailureTime = DateTime.UtcNow; } } /// /// Resets the circuit breaker to its initial state. /// public void Reset() { lock (_lock) { _failureCount = 0; _lastFailureTime = DateTime.MinValue; } } /// /// Gets the time remaining until the circuit can be reset. /// Returns TimeSpan.Zero if circuit is closed or already eligible for reset. /// public TimeSpan TimeUntilReset { get { if (_failureCount < _failureThreshold) return TimeSpan.Zero; var elapsed = DateTime.UtcNow - _lastFailureTime; if (elapsed >= _resetTimeout) return TimeSpan.Zero; return _resetTimeout - elapsed; } } }