All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Add Domain/Interfaces/IMistralConnector.cs with AiServiceException and AiErrorCode enum - Add Infrastructure/Configuration/MistralConfig.cs with validation - Add Infrastructure/Services/MistralConnector.cs with HTTP client implementation - Add Infrastructure/Services/MistralRateLimiter.cs for rate limiting - Add Infrastructure/Services/MistralCircuitBreaker.cs for circuit breaker pattern - Add Application/Models/MistralRequest.cs with request models - Add Application/Models/MistralResponse.cs with response models - Update Program.cs to register IMistralConnector with MemoryCache, HttpClient, and config - Update GermanApp.csproj with existing dependencies - Update docs/features/ai-services.md with Phase 0 completion Phase 0 of AI Services feature is complete. Mistral API Connector is ready for use by MistralService. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
125 lines
3.5 KiB
C#
125 lines
3.5 KiB
C#
using System;
|
|
|
|
namespace GermanApp.Infrastructure.Services;
|
|
|
|
/// <summary>
|
|
/// Circuit breaker implementation for Mistral API.
|
|
/// Prevents cascading failures by temporarily blocking requests after too many failures.
|
|
/// This is part of the Infrastructure layer.
|
|
/// </summary>
|
|
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();
|
|
|
|
/// <summary>
|
|
/// Creates a new circuit breaker.
|
|
/// </summary>
|
|
/// <param name="failureThreshold">Number of consecutive failures before opening the circuit</param>
|
|
/// <param name="resetTimeout">Time to wait before attempting to close the circuit</param>
|
|
public MistralCircuitBreaker(int failureThreshold, TimeSpan resetTimeout)
|
|
{
|
|
_failureThreshold = failureThreshold;
|
|
_resetTimeout = resetTimeout;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets whether the circuit is currently closed (allowing requests).
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current failure count.
|
|
/// </summary>
|
|
public int FailureCount => _failureCount;
|
|
|
|
/// <summary>
|
|
/// Gets the last failure time.
|
|
/// </summary>
|
|
public DateTime LastFailureTime => _lastFailureTime;
|
|
|
|
/// <summary>
|
|
/// Records a successful request, resetting the failure count.
|
|
/// </summary>
|
|
public void RecordSuccess()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_failureCount = 0;
|
|
_lastFailureTime = DateTime.MinValue;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Records a failed request, incrementing the failure count.
|
|
/// </summary>
|
|
public void RecordFailure()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_failureCount++;
|
|
_lastFailureTime = DateTime.UtcNow;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the circuit breaker to its initial state.
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_failureCount = 0;
|
|
_lastFailureTime = DateTime.MinValue;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the time remaining until the circuit can be reset.
|
|
/// Returns TimeSpan.Zero if circuit is closed or already eligible for reset.
|
|
/// </summary>
|
|
public TimeSpan TimeUntilReset
|
|
{
|
|
get
|
|
{
|
|
if (_failureCount < _failureThreshold)
|
|
return TimeSpan.Zero;
|
|
|
|
var elapsed = DateTime.UtcNow - _lastFailureTime;
|
|
if (elapsed >= _resetTimeout)
|
|
return TimeSpan.Zero;
|
|
|
|
return _resetTimeout - elapsed;
|
|
}
|
|
}
|
|
}
|