- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
177 lines
5.5 KiB
PHP
177 lines
5.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\ErrorBoundaries;
|
|
|
|
use App\Framework\Core\ValueObjects\Duration;
|
|
use App\Framework\DateTime\SystemTimer;
|
|
use App\Framework\DateTime\Timer;
|
|
use App\Framework\ErrorBoundaries\CircuitBreaker\BoundaryCircuitBreakerManager;
|
|
use App\Framework\ErrorBoundaries\Events\BoundaryEventPublisher;
|
|
use App\Framework\EventBus\EventBus;
|
|
use App\Framework\Logging\Logger;
|
|
use App\Framework\StateManagement\StateManagerFactory;
|
|
|
|
/**
|
|
* Factory for creating error boundaries with appropriate configurations
|
|
*/
|
|
final readonly class ErrorBoundaryFactory
|
|
{
|
|
private array $routeConfigs;
|
|
|
|
public function __construct(
|
|
private ?Timer $timer = null,
|
|
private ?Logger $logger = null,
|
|
private ?StateManagerFactory $stateManagerFactory = null,
|
|
private ?EventBus $eventBus = null,
|
|
array $routeConfigs = []
|
|
) {
|
|
$this->routeConfigs = array_merge($this->getDefaultRouteConfigs(), $routeConfigs);
|
|
}
|
|
|
|
/**
|
|
* Create error boundary for specific route
|
|
*/
|
|
public function createForRoute(string $routeName): ErrorBoundary
|
|
{
|
|
$config = $this->getConfigForRoute($routeName);
|
|
|
|
return $this->create("route_{$routeName}", $config);
|
|
}
|
|
|
|
/**
|
|
* Create error boundary for database operations
|
|
*/
|
|
public function createForDatabase(string $operation = 'database'): ErrorBoundary
|
|
{
|
|
return $this->create($operation, BoundaryConfig::database());
|
|
}
|
|
|
|
/**
|
|
* Create error boundary for external service calls
|
|
*/
|
|
public function createForExternalService(string $serviceName): ErrorBoundary
|
|
{
|
|
return $this->create("external_{$serviceName}", BoundaryConfig::externalService());
|
|
}
|
|
|
|
/**
|
|
* Create error boundary for UI components
|
|
*/
|
|
public function createForUI(string $componentName): ErrorBoundary
|
|
{
|
|
return $this->create("ui_{$componentName}", BoundaryConfig::ui());
|
|
}
|
|
|
|
/**
|
|
* Create error boundary for background jobs
|
|
*/
|
|
public function createForBackgroundJob(string $jobName): ErrorBoundary
|
|
{
|
|
return $this->create("job_{$jobName}", BoundaryConfig::backgroundJob());
|
|
}
|
|
|
|
/**
|
|
* Create error boundary for critical operations
|
|
*/
|
|
public function createForCriticalOperation(string $operationName): ErrorBoundary
|
|
{
|
|
return $this->create("critical_{$operationName}", BoundaryConfig::critical());
|
|
}
|
|
|
|
/**
|
|
* Create custom error boundary
|
|
*/
|
|
public function create(string $name, BoundaryConfig $config): ErrorBoundary
|
|
{
|
|
$circuitBreakerManager = null;
|
|
|
|
if ($config->circuitBreakerEnabled && $this->stateManagerFactory) {
|
|
$stateManager = $this->stateManagerFactory->createForErrorBoundary();
|
|
$circuitBreakerManager = new BoundaryCircuitBreakerManager($stateManager, $this->logger);
|
|
}
|
|
|
|
$eventPublisher = new BoundaryEventPublisher($this->eventBus, $this->logger);
|
|
|
|
return new ErrorBoundary(
|
|
boundaryName: $name,
|
|
config: $config,
|
|
timer: $this->timer ?? new SystemTimer(),
|
|
logger: $this->logger,
|
|
circuitBreakerManager: $circuitBreakerManager,
|
|
eventPublisher: $eventPublisher,
|
|
);
|
|
}
|
|
|
|
private function getConfigForRoute(string $routeName): BoundaryConfig
|
|
{
|
|
// Check for exact route match
|
|
if (isset($this->routeConfigs[$routeName])) {
|
|
return $this->routeConfigs[$routeName];
|
|
}
|
|
|
|
// Check for pattern matches
|
|
foreach ($this->routeConfigs as $pattern => $config) {
|
|
if (str_contains($pattern, '*') && $this->matchesPattern($routeName, $pattern)) {
|
|
return $config;
|
|
}
|
|
}
|
|
|
|
// Default configuration
|
|
return $this->routeConfigs['default'];
|
|
}
|
|
|
|
private function matchesPattern(string $routeName, string $pattern): bool
|
|
{
|
|
$regex = str_replace('*', '.*', preg_quote($pattern, '/'));
|
|
|
|
return (bool) preg_match("/^{$regex}$/", $routeName);
|
|
}
|
|
|
|
private function getDefaultRouteConfigs(): array
|
|
{
|
|
return [
|
|
// API routes - more retries and circuit breaker
|
|
'api/*' => BoundaryConfig::externalService(),
|
|
|
|
// Admin routes - critical operations
|
|
'admin/*' => BoundaryConfig::critical(),
|
|
|
|
// Auth routes - fail fast for security
|
|
'auth/*' => BoundaryConfig::failFast(),
|
|
|
|
// Public routes - user-friendly defaults
|
|
'public/*' => BoundaryConfig::ui(),
|
|
|
|
// Background job routes
|
|
'job/*' => BoundaryConfig::backgroundJob(),
|
|
|
|
// Database operations
|
|
'db/*' => BoundaryConfig::database(),
|
|
|
|
// Default fallback
|
|
'default' => new BoundaryConfig(
|
|
maxRetries: 2,
|
|
retryStrategy: RetryStrategy::EXPONENTIAL_JITTER,
|
|
baseDelay: Duration::fromMilliseconds(100),
|
|
maxDelay: Duration::fromSeconds(2),
|
|
circuitBreakerEnabled: true,
|
|
circuitBreakerThreshold: 5,
|
|
circuitBreakerTimeout: Duration::fromMinutes(1),
|
|
enableMetrics: true
|
|
),
|
|
|
|
// HTTP request fallback
|
|
'http_request' => new BoundaryConfig(
|
|
maxRetries: 1,
|
|
retryStrategy: RetryStrategy::FIXED,
|
|
baseDelay: Duration::fromMilliseconds(50),
|
|
maxDelay: Duration::fromMilliseconds(200),
|
|
circuitBreakerEnabled: false,
|
|
enableMetrics: true
|
|
),
|
|
];
|
|
}
|
|
}
|