totalExecutions === 0) { return Percentage::fromFloat(0.0); } return Percentage::fromFloat($this->successfulExecutions / $this->totalExecutions); } /** * Calculate failure rate */ public function getFailureRate(): Percentage { if ($this->totalExecutions === 0) { return Percentage::fromFloat(0.0); } return Percentage::fromFloat($this->failedExecutions / $this->totalExecutions); } /** * Calculate fallback rate */ public function getFallbackRate(): Percentage { if ($this->totalExecutions === 0) { return Percentage::fromFloat(0.0); } return Percentage::fromFloat($this->fallbackExecutions / $this->totalExecutions); } /** * Calculate timeout rate */ public function getTimeoutRate(): Percentage { if ($this->totalExecutions === 0) { return Percentage::fromFloat(0.0); } return Percentage::fromFloat($this->timeoutExecutions / $this->totalExecutions); } /** * Check if boundary is healthy (success rate > 90%) */ public function isHealthy(): bool { return $this->getSuccessRate()->toFloat() > 0.9; } /** * Check if circuit breaker is frequently tripping */ public function hasFrequentCircuitBreakerTrips(): bool { if ($this->totalExecutions === 0) { return false; } $tripRate = $this->circuitBreakerTrips / $this->totalExecutions; return $tripRate > 0.1; // More than 10% of executions result in circuit breaker trips } /** * Get health status */ public function getHealthStatus(): BoundaryHealthStatus { if ($this->isHealthy() && ! $this->hasFrequentCircuitBreakerTrips()) { return BoundaryHealthStatus::HEALTHY; } if ($this->getSuccessRate()->toFloat() > 0.7) { return BoundaryHealthStatus::WARNING; } return BoundaryHealthStatus::CRITICAL; } /** * Record successful execution */ public function recordSuccess(Duration $executionTime): self { $newTotalTime = $this->totalExecutionTime->add($executionTime); $newTotalExecutions = $this->totalExecutions + 1; $newAverageTime = Duration::fromMilliseconds( $newTotalTime->toMilliseconds() / $newTotalExecutions ); return new self( boundaryName: $this->boundaryName, totalExecutions: $newTotalExecutions, successfulExecutions: $this->successfulExecutions + 1, failedExecutions: $this->failedExecutions, fallbackExecutions: $this->fallbackExecutions, timeoutExecutions: $this->timeoutExecutions, circuitBreakerTrips: $this->circuitBreakerTrips, totalExecutionTime: $newTotalTime, averageExecutionTime: $newAverageTime, maxExecutionTime: $executionTime->isGreaterThan($this->maxExecutionTime) ? $executionTime : $this->maxExecutionTime, minExecutionTime: $this->minExecutionTime->isZero() || $executionTime->isLessThan($this->minExecutionTime) ? $executionTime : $this->minExecutionTime, lastSuccessTime: Timestamp::now(), lastFailureTime: $this->lastFailureTime, lastFallbackTime: $this->lastFallbackTime, createdAt: $this->createdAt ?? Timestamp::now(), updatedAt: Timestamp::now(), ); } /** * Record failed execution */ public function recordFailure(Duration $executionTime): self { $newTotalTime = $this->totalExecutionTime->add($executionTime); $newTotalExecutions = $this->totalExecutions + 1; $newAverageTime = Duration::fromMilliseconds( $newTotalTime->toMilliseconds() / $newTotalExecutions ); return new self( boundaryName: $this->boundaryName, totalExecutions: $newTotalExecutions, successfulExecutions: $this->successfulExecutions, failedExecutions: $this->failedExecutions + 1, fallbackExecutions: $this->fallbackExecutions, timeoutExecutions: $this->timeoutExecutions, circuitBreakerTrips: $this->circuitBreakerTrips, totalExecutionTime: $newTotalTime, averageExecutionTime: $newAverageTime, maxExecutionTime: $executionTime->isGreaterThan($this->maxExecutionTime) ? $executionTime : $this->maxExecutionTime, minExecutionTime: $this->minExecutionTime->isZero() || $executionTime->isLessThan($this->minExecutionTime) ? $executionTime : $this->minExecutionTime, lastSuccessTime: $this->lastSuccessTime, lastFailureTime: Timestamp::now(), lastFallbackTime: $this->lastFallbackTime, createdAt: $this->createdAt ?? Timestamp::now(), updatedAt: Timestamp::now(), ); } /** * Record fallback execution */ public function recordFallback(): self { return new self( boundaryName: $this->boundaryName, totalExecutions: $this->totalExecutions + 1, successfulExecutions: $this->successfulExecutions, failedExecutions: $this->failedExecutions, fallbackExecutions: $this->fallbackExecutions + 1, timeoutExecutions: $this->timeoutExecutions, circuitBreakerTrips: $this->circuitBreakerTrips, totalExecutionTime: $this->totalExecutionTime, averageExecutionTime: $this->averageExecutionTime, maxExecutionTime: $this->maxExecutionTime, minExecutionTime: $this->minExecutionTime, lastSuccessTime: $this->lastSuccessTime, lastFailureTime: $this->lastFailureTime, lastFallbackTime: Timestamp::now(), createdAt: $this->createdAt ?? Timestamp::now(), updatedAt: Timestamp::now(), ); } /** * Record timeout execution */ public function recordTimeout(Duration $executionTime): self { $newTotalTime = $this->totalExecutionTime->add($executionTime); $newTotalExecutions = $this->totalExecutions + 1; $newAverageTime = Duration::fromMilliseconds( $newTotalTime->toMilliseconds() / $newTotalExecutions ); return new self( boundaryName: $this->boundaryName, totalExecutions: $newTotalExecutions, successfulExecutions: $this->successfulExecutions, failedExecutions: $this->failedExecutions, fallbackExecutions: $this->fallbackExecutions, timeoutExecutions: $this->timeoutExecutions + 1, circuitBreakerTrips: $this->circuitBreakerTrips, totalExecutionTime: $newTotalTime, averageExecutionTime: $newAverageTime, maxExecutionTime: $executionTime->isGreaterThan($this->maxExecutionTime) ? $executionTime : $this->maxExecutionTime, minExecutionTime: $this->minExecutionTime->isZero() || $executionTime->isLessThan($this->minExecutionTime) ? $executionTime : $this->minExecutionTime, lastSuccessTime: $this->lastSuccessTime, lastFailureTime: $this->lastFailureTime, lastFallbackTime: $this->lastFallbackTime, createdAt: $this->createdAt ?? Timestamp::now(), updatedAt: Timestamp::now(), ); } /** * Record circuit breaker trip */ public function recordCircuitBreakerTrip(): self { return new self( boundaryName: $this->boundaryName, totalExecutions: $this->totalExecutions, successfulExecutions: $this->successfulExecutions, failedExecutions: $this->failedExecutions, fallbackExecutions: $this->fallbackExecutions, timeoutExecutions: $this->timeoutExecutions, circuitBreakerTrips: $this->circuitBreakerTrips + 1, totalExecutionTime: $this->totalExecutionTime, averageExecutionTime: $this->averageExecutionTime, maxExecutionTime: $this->maxExecutionTime, minExecutionTime: $this->minExecutionTime, lastSuccessTime: $this->lastSuccessTime, lastFailureTime: $this->lastFailureTime, lastFallbackTime: $this->lastFallbackTime, createdAt: $this->createdAt ?? Timestamp::now(), updatedAt: Timestamp::now(), ); } /** * Convert to array for serialization */ public function toArray(): array { return [ 'boundary_name' => $this->boundaryName, 'total_executions' => $this->totalExecutions, 'successful_executions' => $this->successfulExecutions, 'failed_executions' => $this->failedExecutions, 'fallback_executions' => $this->fallbackExecutions, 'timeout_executions' => $this->timeoutExecutions, 'circuit_breaker_trips' => $this->circuitBreakerTrips, 'success_rate' => $this->getSuccessRate()->toFloat(), 'failure_rate' => $this->getFailureRate()->toFloat(), 'fallback_rate' => $this->getFallbackRate()->toFloat(), 'timeout_rate' => $this->getTimeoutRate()->toFloat(), 'total_execution_time_ms' => $this->totalExecutionTime->toMilliseconds(), 'average_execution_time_ms' => $this->averageExecutionTime->toMilliseconds(), 'max_execution_time_ms' => $this->maxExecutionTime->toMilliseconds(), 'min_execution_time_ms' => $this->minExecutionTime->toMilliseconds(), 'last_success_time' => $this->lastSuccessTime?->toIsoString(), 'last_failure_time' => $this->lastFailureTime?->toIsoString(), 'last_fallback_time' => $this->lastFallbackTime?->toIsoString(), 'health_status' => $this->getHealthStatus()->value, 'is_healthy' => $this->isHealthy(), 'has_frequent_circuit_trips' => $this->hasFrequentCircuitBreakerTrips(), 'created_at' => $this->createdAt?->toIsoString(), 'updated_at' => $this->updatedAt?->toIsoString(), ]; } }