Files
sendico/frontend/pshared/lib/service/authorization/circuit_breaker.dart
Stephan D c6a56071b5
Some checks failed
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
+signup +login
2025-11-17 20:16:45 +01:00

92 lines
3.0 KiB
Dart

import 'package:logging/logging.dart';
/// Circuit breaker pattern implementation for authentication service failures
class AuthCircuitBreaker {
static final _logger = Logger('service.auth_circuit_breaker');
static int _failureCount = 0;
static DateTime? _lastFailure;
static const int _failureThreshold = 3;
static const Duration _recoveryTime = Duration(minutes: 5);
/// Returns true if the circuit breaker is open (blocking operations)
static bool get isOpen {
if (_failureCount < _failureThreshold) return false;
if (_lastFailure == null) return false;
final isOpen = DateTime.now().difference(_lastFailure!) < _recoveryTime;
if (isOpen) {
_logger.warning('Circuit breaker is OPEN. Failure count: $_failureCount, last failure: $_lastFailure');
}
return isOpen;
}
/// Returns true if the circuit breaker is in half-open state (allowing test requests)
static bool get isHalfOpen {
if (_failureCount < _failureThreshold) return false;
if (_lastFailure == null) return false;
return DateTime.now().difference(_lastFailure!) >= _recoveryTime;
}
/// Executes an operation with circuit breaker protection
static Future<T> execute<T>(Future<T> Function() operation) async {
if (isOpen) {
final timeSinceFailure = _lastFailure != null
? DateTime.now().difference(_lastFailure!)
: Duration.zero;
final timeUntilRecovery = _recoveryTime - timeSinceFailure;
_logger.warning('Circuit breaker blocking operation. Recovery in: ${timeUntilRecovery.inSeconds}s');
throw Exception('Auth service temporarily unavailable. Try again in ${timeUntilRecovery.inMinutes} minutes.');
}
try {
_logger.fine('Executing operation through circuit breaker');
final result = await operation();
_reset();
return result;
} catch (e) {
_recordFailure();
rethrow;
}
}
/// Records a failure and updates the circuit breaker state
static void _recordFailure() {
_failureCount++;
_lastFailure = DateTime.now();
_logger.warning('Auth circuit breaker recorded failure #$_failureCount at $_lastFailure');
if (_failureCount >= _failureThreshold) {
_logger.severe('Auth circuit breaker OPENED after $_failureCount failures');
}
}
/// Resets the circuit breaker to closed state
static void _reset() {
if (_failureCount > 0) {
_logger.info('Auth circuit breaker CLOSED - resetting failure count from $_failureCount to 0');
}
_failureCount = 0;
_lastFailure = null;
}
/// Manual reset (for testing or administrative purposes)
static void manualReset() {
_logger.info('Auth circuit breaker manually reset');
_reset();
}
/// Get current status for debugging
static Map<String, dynamic> getStatus() {
return {
'failureCount': _failureCount,
'lastFailure': _lastFailure?.toIso8601String(),
'isOpen': isOpen,
'isHalfOpen': isHalfOpen,
'threshold': _failureThreshold,
'recoveryTime': _recoveryTime.inSeconds,
};
}
}