- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
22 KiB
Exception System Advanced Features
Übersicht
Das Exception-System wurde um 10 erweiterte Features erweitert, die in drei Phasen implementiert wurden:
- Phase 1 (Foundation): Rate Limiting, Context Caching, Performance Tracking
- Phase 2 (User Experience): User-Friendly Messages, Localization
- Phase 3 (Advanced): Recovery/Retry, Pattern Detection, Correlation, Metrics, Health Checks
Alle Features sind optional und können einzeln aktiviert werden. Sie folgen den Framework-Prinzipien (final, readonly, Value Objects, Composition over Inheritance).
Phase 1: Foundation Features
1. Exception Rate Limiting & Throttling
Ziel: Verhindert Log-Spam durch wiederholte gleiche Exceptions
Komponenten:
ExceptionFingerprint- Generiert eindeutige Fingerprints für Exception-GruppierungExceptionRateLimitConfig- Konfiguration für Thresholds und Time WindowsExceptionRateLimiter- Rate Limiter mit Cache-basiertem Tracking
Verwendung:
use App\Framework\ExceptionHandling\RateLimit\ExceptionRateLimiter;
use App\Framework\ExceptionHandling\RateLimit\ExceptionRateLimitConfig;
use App\Framework\Core\ValueObjects\Duration;
// Konfiguration erstellen
$config = ExceptionRateLimitConfig::withLimits(
maxExceptions: 10,
timeWindow: Duration::fromSeconds(60)
);
// Rate Limiter erstellen
$rateLimiter = new ExceptionRateLimiter($cache, $config);
// In ErrorKernel integriert (automatisch)
// Exceptions werden automatisch rate-limited, wenn Threshold erreicht wird
Konfiguration:
maxExceptions: Maximale Anzahl gleicher Exceptions pro Time Window (Default: 10)timeWindow: Time Window für Rate Limiting (Default: 60 Sekunden)skipLoggingOnLimit: Skip Logging wenn Rate Limit erreicht (Default: true)skipAuditOnLimit: Skip Audit Logging wenn Rate Limit erreicht (Default: true)trackMetricsOnLimit: Track Metriken auch bei Rate Limit (Default: true)
Fingerprint-Generierung:
- Basierend auf Exception-Klasse, normalisierter Message, File/Line
- Optional: Component und Operation aus Context für präzisere Gruppierung
- Normalisierung entfernt variable Teile (UUIDs, Timestamps, Zahlen, etc.)
2. Exception Context Caching
Ziel: Performance-Optimierung durch Caching von häufig verwendeten Context-Daten
Komponenten:
ExceptionContextCache- Cache-Wrapper für Context-Daten- Integration in
ExceptionContextBuilder- Automatischer Cache-Lookup
Verwendung:
use App\Framework\ExceptionHandling\Context\ExceptionContextCache;
use App\Framework\ExceptionHandling\Context\ExceptionContextBuilder;
// Context Cache erstellen
$contextCache = new ExceptionContextCache($cache);
// Context Builder mit Cache
$builder = new ExceptionContextBuilder(
errorScope: $errorScope,
contextCache: $contextCache
);
// Automatischer Cache-Lookup beim buildFromRequest()
$context = $builder->buildFromRequest($request);
Cache-Levels:
- Request-Level: TTL 10 Minuten (spezifischste)
- Session-Level: TTL 10 Minuten
- User-Level: TTL 30 Minuten (am wenigsten spezifisch)
Cache-Invalidation:
// Manuelle Invalidation bei Context-Änderungen
$contextCache->invalidateRequest($requestId);
$contextCache->invalidateSession($sessionId);
$contextCache->invalidateUser($userId);
3. Exception Performance Tracking
Ziel: Tracking von Performance-Impact pro Exception-Typ
Komponenten:
ExceptionPerformanceMetrics- Value Object für MetrikenExceptionPerformanceTracker- Performance-Tracking
Verwendung:
use App\Framework\ExceptionHandling\Performance\ExceptionPerformanceTracker;
$tracker = new ExceptionPerformanceTracker();
// Start tracking
$startData = $tracker->start();
// ... exception occurs ...
// End tracking
$metrics = $tracker->end($startData, $exception, $context);
// Metriken enthalten:
// - executionTimeMs: Ausführungszeit in Millisekunden
// - memoryDeltaBytes: Memory-Delta in Bytes
// - cpuUsagePercent: CPU-Usage in Prozent (wenn verfügbar)
Integration:
- Metriken werden automatisch in
ExceptionContextData::metadata['performance']gespeichert - Kann mit
MetricsCollectorintegriert werden für Monitoring
Phase 2: User Experience Features
4. User-Friendly Exception Messages
Ziel: Übersetzung von technischen Exception-Messages zu benutzerfreundlichen Texten
Komponenten:
UserFriendlyMessage- Value Object für User-MessagesExceptionMessageTranslator- Message-Übersetzung mit Template-System
Verwendung:
use App\Framework\ExceptionHandling\Translation\ExceptionMessageTranslator;
use App\Framework\ExceptionHandling\Translation\UserFriendlyMessage;
// Templates definieren
$templates = [
\App\Framework\Exception\DatabaseException::class => [
'message' => 'Database connection failed. Please try again later.',
'title' => 'Database Error',
'help' => 'If this problem persists, please contact support.'
],
\App\Framework\Exception\ValidationException::class => [
'message' => 'Please check your input and try again.',
'title' => 'Validation Error'
]
];
// Translator erstellen
$translator = new ExceptionMessageTranslator(
templates: $templates,
isDebugMode: false
);
// Message übersetzen
$userMessage = $translator->translate($exception, $context);
// $userMessage->message: User-friendly message
// $userMessage->title: Optional title
// $userMessage->helpText: Optional help text
// $userMessage->technicalMessage: Original technical message (für Debugging)
Template-Variablen:
{exception_message}- Original Exception-Message{exception_class}- Exception-Klasse{operation}- Operation aus Context{component}- Component aus Context
Integration:
- Automatisch in
ResponseErrorRendererintegriert - In Debug-Mode werden technische Messages angezeigt
- In Production werden User-Friendly Messages verwendet
5. Exception Localization
Ziel: i18n-Support für Exception-Messages basierend auf User-Locale
Komponenten:
ExceptionLocalizer- Lokalisierung mit Fallback-Chain
Verwendung:
use App\Framework\ExceptionHandling\Localization\ExceptionLocalizer;
// Übersetzungen definieren
$translations = [
'de' => [
\App\Framework\Exception\DatabaseException::class => [
'message' => 'Datenbankverbindung fehlgeschlagen. Bitte versuchen Sie es später erneut.',
'title' => 'Datenbankfehler'
]
],
'en' => [
\App\Framework\Exception\DatabaseException::class => [
'message' => 'Database connection failed. Please try again later.',
'title' => 'Database Error'
]
]
];
// Localizer erstellen
$localizer = new ExceptionLocalizer(
translations: $translations,
defaultLocale: 'en'
);
// Locale aus Context extrahieren
$locale = $localizer->getLocale($context);
// Übersetzungen für Locale abrufen
$localeTranslations = $localizer->getTranslations($locale);
// Fallback-Chain: [user_locale, default_locale, 'en']
$fallbackChain = $localizer->getFallbackChain($locale);
Locale-Extraktion:
- Aus
ExceptionContextData::metadata['locale'] - Fallback zu Default-Locale
- Fallback zu 'en' als letzte Option
Integration:
- Wird von
ExceptionMessageTranslatorverwendet - Locale sollte in
ExceptionContextData::metadata['locale']gespeichert werden
Phase 3: Advanced Features
6. Exception Recovery & Retry Logic
Ziel: Automatische Retry-Logik für temporäre Exceptions
Komponenten:
RetryStrategy- Retry-Strategien (Exponential Backoff, Linear, Fixed)ExceptionRecoveryManager- Recovery-ManagerRetryableException- Marker-Interface
Verwendung:
use App\Framework\ExceptionHandling\Recovery\ExceptionRecoveryManager;
use App\Framework\ExceptionHandling\Recovery\RetryableException;
use App\Framework\Exception\ExceptionMetadata;
// Retryable Exception implementieren
final class NetworkException extends \Exception implements RetryableException
{
}
// Exception mit Retry-Config erstellen
$metadata = ExceptionMetadata::withRetry(
retryAfter: 1000 // Base delay in milliseconds
)->withMaxRetries(3)
->withRetryStrategy('exponential_backoff');
// Recovery Manager
$recoveryManager = new ExceptionRecoveryManager();
// Prüfen ob Retry nötig
if ($recoveryManager->shouldRetry($exception, $metadata)) {
$delay = $recoveryManager->getRetryDelay($exception, $metadata, $attemptNumber);
// Retry nach $delay Millisekunden
}
Retry-Strategien:
- Exponential Backoff (Default):
baseDelay * 2^(attempt-1) - Linear:
baseDelay * attempt - Fixed:
baseDelay(konstant)
ExceptionMetadata Erweiterungen:
maxRetries: Maximale Anzahl Retries (Default: 3)retryStrategy: Retry-Strategie (Default: 'exponential_backoff')retryAfter: Base Delay in Millisekunden
Retryable Exceptions:
- Exceptions die
RetryableExceptionimplementieren - Exceptions mit bestimmten Namen-Patterns (NetworkException, TimeoutException, etc.)
7. Exception Pattern Detection & Auto-Fix Suggestions
Ziel: ML-basierte Pattern-Erkennung mit Fix-Vorschlägen
Komponenten:
ExceptionPattern- Value Object für PatternsFixSuggestion- Value Object für Fix-VorschlägeExceptionPatternDetector- Pattern-Detection
Verwendung:
use App\Framework\ExceptionHandling\PatternDetection\ExceptionPatternDetector;
use App\Framework\ExceptionHandling\PatternDetection\FixSuggestion;
// Knowledge Base definieren
$knowledgeBase = [
\App\Framework\Exception\DatabaseException::class => [
'description' => 'Database connection timeout',
'fixes' => [
[
'title' => 'Check connection pool size',
'description' => 'Increase database connection pool size',
'code' => '$config->setMaxConnections(50);',
'confidence' => 'high'
],
[
'title' => 'Check database server',
'description' => 'Verify database server is running and accessible',
'confidence' => 'medium'
]
]
]
];
// Pattern Detector erstellen
$detector = new ExceptionPatternDetector($knowledgeBase);
// Patterns erkennen
$patterns = $detector->detect($exception, $context);
foreach ($patterns as $pattern) {
echo $pattern->description . "\n";
foreach ($pattern->fixSuggestions as $fix) {
echo " - " . $fix->title . ": " . $fix->description . "\n";
}
}
Integration:
- Kann in
ErrorAggregatorintegriert werden - Patterns werden in
ExceptionContextData::metadata['patterns']gespeichert
8. Exception Correlation & Root Cause Analysis
Ziel: Verknüpfung verwandter Exceptions für Root-Cause-Analyse
Komponenten:
ExceptionCorrelation- Value Object für KorrelationenExceptionCorrelationEngine- Correlation-Engine
Verwendung:
use App\Framework\ExceptionHandling\Correlation\ExceptionCorrelationEngine;
$correlationEngine = new ExceptionCorrelationEngine($cache);
// Exception korrelieren
$correlation = $correlationEngine->correlate($exception, $context);
// Correlation-Daten:
// - correlationKey: Request-ID, Session-ID oder User-ID
// - exceptionIds: Array von verwandten Exception-IDs
// - rootCauseId: ID der ersten Exception (Root Cause)
Correlation-Keys:
- Request-ID (höchste Priorität): Alle Exceptions in derselben Request
- Session-ID: Alle Exceptions in derselben Session
- User-ID: Alle Exceptions für denselben User
Root Cause Analysis:
- Erste Exception in Correlation-Chain ist Root Cause
- Alle weiteren Exceptions sind Folge-Exceptions
Integration:
- Correlation-Daten werden in
ExceptionContextData::metadata['correlations']gespeichert - Kann für Exception-Graph-Visualisierung verwendet werden
9. Exception Metrics & Monitoring Integration
Ziel: Integration mit Monitoring-Systemen (Prometheus, StatsD)
Komponenten:
ExceptionMetrics- Value Object für MetrikenExceptionMetricsCollector- Metrics-CollectorPrometheusExporter- Prometheus-Export
Verwendung:
use App\Framework\ExceptionHandling\Metrics\ExceptionMetricsCollector;
use App\Framework\ExceptionHandling\Metrics\PrometheusExporter;
$collector = new ExceptionMetricsCollector($cache);
// Exception-Metrik aufzeichnen
$collector->record($exception, $context, $executionTimeMs);
// Metriken abrufen
$metrics = $collector->getMetrics();
// Prometheus-Format exportieren
$exporter = new PrometheusExporter();
$prometheusMetrics = $exporter->export($metrics);
// Output:
// exception_total 42
// exception_by_class{exception_class="DatabaseException"} 10
// exception_by_component{component="UserService"} 5
// exception_average_execution_time_ms 125.50
Metriken:
totalCount: Gesamtanzahl ExceptionsbyClass: Anzahl pro Exception-KlassebyComponent: Anzahl pro ComponentaverageExecutionTimeMs: Durchschnittliche Ausführungszeit
Integration:
- Kann in
ProductionMetricsControllerintegriert werden - Metriken werden im Prometheus-Format exportiert
- Real-time Aggregation über Time-Windows
10. Exception Health Checks & Circuit Breakers
Ziel: Circuit Breaker Pattern für Exception-basierte Health Checks
Komponenten:
ExceptionHealthChecker- Health Checker
Verwendung:
use App\Framework\ExceptionHandling\Health\ExceptionHealthChecker;
use App\Framework\ExceptionHandling\Metrics\ExceptionMetricsCollector;
$metricsCollector = new ExceptionMetricsCollector($cache);
$healthChecker = new ExceptionHealthChecker(
metricsCollector: $metricsCollector,
errorRateThreshold: 0.1, // 10% Error Rate
timeWindowSeconds: 60
);
// Health Check durchführen
$result = $healthChecker->check();
// Status:
// - Healthy: Error Rate < 5%
// - Warning: Error Rate 5-10%
// - Unhealthy: Error Rate > 10%
Health Check Status:
- Healthy: Error Rate unterhalb des Thresholds
- Warning: Error Rate bei 50% des Thresholds
- Unhealthy: Error Rate oberhalb des Thresholds
Integration:
- Implementiert
HealthCheckInterface - Kann in
HealthCheckManagerregistriert werden - Nutzt bestehende
CircuitBreakerInfrastruktur
DI Container Integration
Beispiel-Konfiguration
// Exception Rate Limiter
$container->bind(ExceptionRateLimitConfig::class, function() {
return ExceptionRateLimitConfig::withLimits(
maxExceptions: 10,
timeWindow: Duration::fromSeconds(60)
);
});
$container->singleton(ExceptionRateLimiter::class, function($container) {
return new ExceptionRateLimiter(
cache: $container->get(Cache::class),
config: $container->get(ExceptionRateLimitConfig::class)
);
});
// Exception Context Cache
$container->singleton(ExceptionContextCache::class, function($container) {
return new ExceptionContextCache(
cache: $container->get(Cache::class)
);
});
// Exception Context Builder
$container->singleton(ExceptionContextBuilder::class, function($container) {
return new ExceptionContextBuilder(
errorScope: $container->get(ErrorScope::class),
contextCache: $container->get(ExceptionContextCache::class)
);
});
// Exception Performance Tracker
$container->singleton(ExceptionPerformanceTracker::class, function() {
return new ExceptionPerformanceTracker();
});
// Exception Message Translator
$container->singleton(ExceptionMessageTranslator::class, function($container) {
$templates = require __DIR__ . '/config/exception_messages.php';
return new ExceptionMessageTranslator(
templates: $templates,
isDebugMode: $container->get('config')->get('app.debug', false)
);
});
// Exception Localizer
$container->singleton(ExceptionLocalizer::class, function() {
$translations = require __DIR__ . '/config/exception_translations.php';
return new ExceptionLocalizer(
translations: $translations,
defaultLocale: 'en'
);
});
// Exception Recovery Manager
$container->singleton(ExceptionRecoveryManager::class, function() {
return new ExceptionRecoveryManager();
});
// Exception Pattern Detector
$container->singleton(ExceptionPatternDetector::class, function() {
$knowledgeBase = require __DIR__ . '/config/exception_patterns.php';
return new ExceptionPatternDetector($knowledgeBase);
});
// Exception Correlation Engine
$container->singleton(ExceptionCorrelationEngine::class, function($container) {
return new ExceptionCorrelationEngine(
cache: $container->get(Cache::class)
);
});
// Exception Metrics Collector
$container->singleton(ExceptionMetricsCollector::class, function($container) {
return new ExceptionMetricsCollector(
cache: $container->get(Cache::class)
);
});
// Exception Health Checker
$container->singleton(ExceptionHealthChecker::class, function($container) {
return new ExceptionHealthChecker(
metricsCollector: $container->get(ExceptionMetricsCollector::class),
errorRateThreshold: 0.1,
timeWindowSeconds: 60
);
});
// ErrorKernel mit allen Features
$container->singleton(ErrorKernel::class, function($container) {
return new ErrorKernel(
rendererFactory: $container->get(ErrorRendererFactory::class),
reporter: $container->get(Reporter::class),
errorAggregator: $container->get(ErrorAggregatorInterface::class),
contextProvider: $container->get(ExceptionContextProvider::class),
auditLogger: $container->get(ExceptionAuditLogger::class),
rateLimiter: $container->get(ExceptionRateLimiter::class), // NEU
executionContext: $container->get(ExecutionContext::class),
consoleOutput: $container->get(ConsoleOutput::class),
isDebugMode: $container->get('config')->get('app.debug', false)
);
});
Best Practices
1. Rate Limiting konfigurieren
// Für Production: Strikte Limits
$config = ExceptionRateLimitConfig::withLimits(
maxExceptions: 5,
timeWindow: Duration::fromSeconds(60)
);
// Für Development: Lockerere Limits
$config = ExceptionRateLimitConfig::withLimits(
maxExceptions: 50,
timeWindow: Duration::fromSeconds(60)
);
2. Context Caching nutzen
// Context Cache nur aktivieren wenn Context-Erstellung teuer ist
// (z.B. DB-Queries, externe API-Calls)
if ($needsCaching) {
$builder = new ExceptionContextBuilder(
errorScope: $errorScope,
contextCache: $contextCache
);
} else {
$builder = new ExceptionContextBuilder(errorScope: $errorScope);
}
3. User-Friendly Messages definieren
// Alle wichtigen Exceptions sollten User-Friendly Messages haben
$templates = [
\App\Framework\Exception\DatabaseException::class => [
'message' => 'Database connection failed. Please try again later.',
'title' => 'Database Error',
'help' => 'If this problem persists, please contact support.'
],
\App\Framework\Exception\ValidationException::class => [
'message' => 'Please check your input and try again.',
'title' => 'Validation Error'
]
];
4. Retry-Strategien wählen
// Für Network-Exceptions: Exponential Backoff
$metadata = ExceptionMetadata::withRetry(1000)
->withRetryStrategy('exponential_backoff');
// Für Rate-Limited APIs: Linear
$metadata = ExceptionMetadata::withRetry(2000)
->withRetryStrategy('linear');
// Für Polling: Fixed Delay
$metadata = ExceptionMetadata::withRetry(5000)
->withRetryStrategy('fixed');
5. Health Checks konfigurieren
// Für kritische Services: Strikte Thresholds
$healthChecker = new ExceptionHealthChecker(
metricsCollector: $metricsCollector,
errorRateThreshold: 0.05, // 5%
timeWindowSeconds: 60
);
// Für weniger kritische Services: Lockerere Thresholds
$healthChecker = new ExceptionHealthChecker(
metricsCollector: $metricsCollector,
errorRateThreshold: 0.2, // 20%
timeWindowSeconds: 300
);
Migration Guide
Von altem System migrieren
-
Rate Limiting aktivieren:
// In DI Container $container->singleton(ExceptionRateLimiter::class, ...); -
Context Caching aktivieren (optional):
// Nur wenn Performance-Probleme auftreten $container->singleton(ExceptionContextCache::class, ...); -
User-Friendly Messages hinzufügen:
// Templates in config/exception_messages.php definieren -
Health Checks registrieren:
// In HealthCheckManager $healthCheckManager->register($exceptionHealthChecker);
Troubleshooting
Rate Limiting blockiert zu viele Exceptions
Problem: Rate Limiting blockiert auch wichtige Exceptions
Lösung: Threshold erhöhen oder Time Window anpassen
$config = ExceptionRateLimitConfig::withLimits(
maxExceptions: 20, // Erhöht
timeWindow: Duration::fromSeconds(60)
);
Context Cache liefert veraltete Daten
Problem: Context Cache enthält veraltete User/Session-Daten
Lösung: Cache bei User/Session-Änderungen invalidieren
$contextCache->invalidateUser($userId);
$contextCache->invalidateSession($sessionId);
Performance Tracking zeigt keine Daten
Problem: Performance-Metriken werden nicht aufgezeichnet
Lösung: Sicherstellen dass ExceptionPerformanceTracker in ErrorKernel integriert ist
// Performance-Tracking manuell starten
$startData = $performanceTracker->start();
// ... exception occurs ...
$metrics = $performanceTracker->end($startData, $exception, $context);