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;
}
}
}