Files
michaelschiemer/src/Framework/ErrorBoundaries/CircuitBreaker/BoundaryCircuitBreakerState.php
Michael Schiemer 55a330b223 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
2025-08-11 20:13:26 +02:00

197 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\ErrorBoundaries\CircuitBreaker;
use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\StateManagement\SerializableState;
/**
* Value object representing circuit breaker state for error boundaries
*/
final readonly class BoundaryCircuitBreakerState implements SerializableState
{
public function __construct(
public int $failureCount = 0,
public int $successCount = 0,
public ?Timestamp $lastFailureTime = null,
public ?Timestamp $openedAt = null,
public BoundaryCircuitState $state = BoundaryCircuitState::CLOSED,
public int $halfOpenAttempts = 0,
) {
}
/**
* Check if circuit is open
*/
public function isOpen(): bool
{
return $this->state === BoundaryCircuitState::OPEN;
}
/**
* Check if circuit is closed
*/
public function isClosed(): bool
{
return $this->state === BoundaryCircuitState::CLOSED;
}
/**
* Check if circuit is half-open
*/
public function isHalfOpen(): bool
{
return $this->state === BoundaryCircuitState::HALF_OPEN;
}
/**
* Record a failure and return new state
*/
public function recordFailure(): self
{
return new self(
failureCount: $this->failureCount + 1,
successCount: $this->successCount,
lastFailureTime: Timestamp::now(),
openedAt: $this->openedAt,
state: $this->state,
halfOpenAttempts: $this->halfOpenAttempts,
);
}
/**
* Record a success and return new state
*/
public function recordSuccess(): self
{
return new self(
failureCount: 0, // Reset failure count on success
successCount: $this->successCount + 1,
lastFailureTime: $this->lastFailureTime,
openedAt: null, // Reset opened time
state: $this->state,
halfOpenAttempts: 0, // Reset half-open attempts
);
}
/**
* Transition to OPEN state
*/
public function transitionToOpen(): self
{
return new self(
failureCount: $this->failureCount,
successCount: $this->successCount,
lastFailureTime: $this->lastFailureTime,
openedAt: Timestamp::now(),
state: BoundaryCircuitState::OPEN,
halfOpenAttempts: 0,
);
}
/**
* Transition to HALF_OPEN state
*/
public function transitionToHalfOpen(): self
{
return new self(
failureCount: $this->failureCount,
successCount: $this->successCount,
lastFailureTime: $this->lastFailureTime,
openedAt: $this->openedAt,
state: BoundaryCircuitState::HALF_OPEN,
halfOpenAttempts: 0,
);
}
/**
* Transition to CLOSED state
*/
public function transitionToClosed(): self
{
return new self(
failureCount: 0, // Reset failure count
successCount: $this->successCount,
lastFailureTime: null, // Reset last failure time
openedAt: null, // Reset opened time
state: BoundaryCircuitState::CLOSED,
halfOpenAttempts: 0,
);
}
/**
* Increment half-open attempts
*/
public function incrementHalfOpenAttempts(): self
{
return new self(
failureCount: $this->failureCount,
successCount: $this->successCount,
lastFailureTime: $this->lastFailureTime,
openedAt: $this->openedAt,
state: $this->state,
halfOpenAttempts: $this->halfOpenAttempts + 1,
);
}
/**
* Check if failure threshold is exceeded
*/
public function exceedsFailureThreshold(int $threshold): bool
{
return $this->failureCount >= $threshold;
}
/**
* Check if success threshold is met for half-open state
*/
public function meetsSuccessThreshold(int $threshold): bool
{
return $this->successCount >= $threshold;
}
/**
* Check if half-open attempts exceed maximum
*/
public function exceedsHalfOpenAttempts(int $maxAttempts): bool
{
return $this->halfOpenAttempts >= $maxAttempts;
}
/**
* Convert to array for serialization
*/
public function toArray(): array
{
return [
'failure_count' => $this->failureCount,
'success_count' => $this->successCount,
'last_failure_time' => $this->lastFailureTime?->toFloat(),
'opened_at' => $this->openedAt?->toFloat(),
'state' => $this->state->value,
'half_open_attempts' => $this->halfOpenAttempts,
];
}
/**
* Create from array (deserialization)
*/
public static function fromArray(array $data): static
{
return new self(
failureCount: $data['failure_count'] ?? 0,
successCount: $data['success_count'] ?? 0,
lastFailureTime: isset($data['last_failure_time'])
? Timestamp::fromFloat($data['last_failure_time'])
: null,
openedAt: isset($data['opened_at'])
? Timestamp::fromFloat($data['opened_at'])
: null,
state: BoundaryCircuitState::from($data['state'] ?? 'closed'),
halfOpenAttempts: $data['half_open_attempts'] ?? 0,
);
}
}