Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
143
src/Framework/Http/MiddlewareCircuitBreaker.php
Normal file
143
src/Framework/Http/MiddlewareCircuitBreaker.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Http;
|
||||
|
||||
use App\Framework\CircuitBreaker\CircuitBreaker;
|
||||
use App\Framework\CircuitBreaker\CircuitBreakerConfig;
|
||||
use App\Framework\CircuitBreaker\CircuitState;
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Circuit breaker for middlewares to prevent repeatedly failing middlewares from being executed
|
||||
*
|
||||
* This class is a wrapper around the CircuitBreaker module that provides middleware-specific functionality.
|
||||
*/
|
||||
final class MiddlewareCircuitBreaker
|
||||
{
|
||||
/**
|
||||
* Default configuration for middleware circuit breakers
|
||||
*/
|
||||
private CircuitBreakerConfig $defaultConfig;
|
||||
|
||||
/**
|
||||
* @param CircuitBreaker $circuitBreaker The circuit breaker instance
|
||||
* @param int $failureThreshold Number of failures before opening the circuit
|
||||
* @param int $recoveryTimeoutSeconds Time in seconds to keep the circuit open
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly CircuitBreaker $circuitBreaker,
|
||||
int $failureThreshold = 5,
|
||||
int $recoveryTimeoutSeconds = 60
|
||||
) {
|
||||
$this->defaultConfig = new CircuitBreakerConfig(
|
||||
failureThreshold: $failureThreshold,
|
||||
recoveryTimeout: Duration::fromSeconds($recoveryTimeoutSeconds),
|
||||
halfOpenMaxAttempts: 3,
|
||||
successThreshold: 2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a middleware is allowed to execute
|
||||
*
|
||||
* @param string $middlewareName The fully qualified class name of the middleware
|
||||
* @return bool True if the middleware is allowed to execute, false otherwise
|
||||
*/
|
||||
public function isAllowed(string $middlewareName): bool
|
||||
{
|
||||
try {
|
||||
// Use the CircuitBreaker to check if the middleware is allowed to execute
|
||||
$this->circuitBreaker->check($this->getServiceName($middlewareName), $this->defaultConfig);
|
||||
|
||||
return true;
|
||||
} catch (Throwable $e) {
|
||||
// If the circuit is open, the check method will throw an exception
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a successful middleware execution
|
||||
*
|
||||
* @param string $middlewareName The fully qualified class name of the middleware
|
||||
*/
|
||||
public function recordSuccess(string $middlewareName): void
|
||||
{
|
||||
// Delegate to the CircuitBreaker
|
||||
$this->circuitBreaker->recordSuccess($this->getServiceName($middlewareName), $this->defaultConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a middleware failure
|
||||
*
|
||||
* @param string $middlewareName The fully qualified class name of the middleware
|
||||
* @param int|null $failureThreshold Custom failure threshold for this middleware
|
||||
* @param int|null $openTime Custom open time for this middleware
|
||||
*/
|
||||
public function recordFailure(string $middlewareName, ?int $failureThreshold = null, ?int $openTime = null): void
|
||||
{
|
||||
// Create a custom config if custom thresholds are provided
|
||||
$config = $this->defaultConfig;
|
||||
if ($failureThreshold !== null || $openTime !== null) {
|
||||
$config = new CircuitBreakerConfig(
|
||||
failureThreshold: $failureThreshold ?? $this->defaultConfig->failureThreshold,
|
||||
recoveryTimeout: $openTime ? Duration::fromSeconds($openTime) : $this->defaultConfig->recoveryTimeout,
|
||||
halfOpenMaxAttempts: $this->defaultConfig->halfOpenMaxAttempts,
|
||||
successThreshold: $this->defaultConfig->successThreshold
|
||||
);
|
||||
}
|
||||
|
||||
// Create a RuntimeException to pass to the CircuitBreaker
|
||||
$exception = new RuntimeException("Middleware {$middlewareName} failed");
|
||||
|
||||
// Delegate to the CircuitBreaker
|
||||
$this->circuitBreaker->recordFailure($this->getServiceName($middlewareName), $exception, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of the circuit for a middleware
|
||||
*
|
||||
* @param string $middlewareName The fully qualified class name of the middleware
|
||||
* @return CircuitState The current state of the circuit
|
||||
*/
|
||||
public function getState(string $middlewareName): CircuitState
|
||||
{
|
||||
return $this->circuitBreaker->getState($this->getServiceName($middlewareName), $this->defaultConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the circuit for a middleware
|
||||
*
|
||||
* @param string $middlewareName The fully qualified class name of the middleware
|
||||
*/
|
||||
public function reset(string $middlewareName): void
|
||||
{
|
||||
$this->circuitBreaker->reset($this->getServiceName($middlewareName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metrics for a middleware
|
||||
*
|
||||
* @param string $middlewareName The fully qualified class name of the middleware
|
||||
* @return array Metrics for the middleware
|
||||
*/
|
||||
public function getMetrics(string $middlewareName): array
|
||||
{
|
||||
return $this->circuitBreaker->getMetrics($this->getServiceName($middlewareName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a middleware name to a service name for the CircuitBreaker
|
||||
*
|
||||
* @param string $middlewareName The fully qualified class name of the middleware
|
||||
* @return string The service name for the CircuitBreaker
|
||||
*/
|
||||
private function getServiceName(string $middlewareName): string
|
||||
{
|
||||
return 'middleware:' . $middlewareName;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user