status) { 'pending' => $pending++, 'running' => $running++, 'completed' => $completed++, 'failed' => $failed++, 'dead_letter' => $deadLetter++, default => null }; if ($metrics->executionTimeMs > 0) { $totalExecutionTime += $metrics->executionTimeMs; $totalMemoryUsage += $metrics->getMemoryUsageMB(); $executionCount++; } if (strtotime($metrics->createdAt) >= $windowStart) { $jobsInWindow++; } } $avgExecutionTime = $executionCount > 0 ? $totalExecutionTime / $executionCount : 0.0; $avgMemoryUsage = $executionCount > 0 ? $totalMemoryUsage / $executionCount : 0.0; $throughput = $jobsInWindow / (strtotime($timeWindow) / 3600); $successRate = $total > 0 ? Percentage::from(($completed / $total) * 100) : Percentage::from(100.0); return new self( queueName: $queueName, totalJobs: $total, pendingJobs: $pending, runningJobs: $running, completedJobs: $completed, failedJobs: $failed, deadLetterJobs: $deadLetter, averageExecutionTimeMs: $avgExecutionTime, averageMemoryUsageMB: $avgMemoryUsage, throughputJobsPerHour: $throughput, successRate: $successRate, measuredAt: date('Y-m-d H:i:s'), additionalMetrics: [] ); } public function withAdditionalMetrics(array $metrics): self { return new self( queueName: $this->queueName, totalJobs: $this->totalJobs, pendingJobs: $this->pendingJobs, runningJobs: $this->runningJobs, completedJobs: $this->completedJobs, failedJobs: $this->failedJobs, deadLetterJobs: $this->deadLetterJobs, averageExecutionTimeMs: $this->averageExecutionTimeMs, averageMemoryUsageMB: $this->averageMemoryUsageMB, throughputJobsPerHour: $this->throughputJobsPerHour, successRate: $this->successRate, measuredAt: $this->measuredAt, additionalMetrics: array_merge($this->additionalMetrics, $metrics) ); } public function getFailureRate(): Percentage { if ($this->totalJobs === 0) { return Percentage::from(0.0); } return Percentage::from(($this->failedJobs / $this->totalJobs) * 100); } public function getAverageExecutionTimeSeconds(): float { return $this->averageExecutionTimeMs / 1000.0; } public function getHealthScore(): Percentage { // Composite health score based on multiple factors $successWeight = 40; // Success rate weight $throughputWeight = 30; // Throughput weight $performanceWeight = 20; // Performance weight $stabilityWeight = 10; // Stability weight // Success rate score (0-100) $successScore = $this->successRate->getValue(); // Throughput score (normalized, assuming 100 jobs/hour is excellent) $throughputScore = min(100, ($this->throughputJobsPerHour / 100) * 100); // Performance score (inverse of execution time, assuming 1000ms is baseline) $performanceScore = $this->averageExecutionTimeMs > 0 ? max(0, 100 - (($this->averageExecutionTimeMs / 1000) * 10)) : 100; // Stability score (low pending/running job ratio) $activeJobs = $this->pendingJobs + $this->runningJobs; $stabilityScore = $this->totalJobs > 0 ? max(0, 100 - (($activeJobs / $this->totalJobs) * 100)) : 100; $weightedScore = ( ($successScore * $successWeight) + ($throughputScore * $throughputWeight) + ($performanceScore * $performanceWeight) + ($stabilityScore * $stabilityWeight) ) / 100; return Percentage::from($weightedScore); } public function isHealthy(): bool { return $this->getHealthScore()->getValue() >= 70.0; } public function getBottleneckIndicators(): array { $indicators = []; // High pending jobs if ($this->pendingJobs > ($this->totalJobs * 0.3)) { $indicators[] = 'high_pending_jobs'; } // High failure rate if ($this->getFailureRate()->getValue() > 10.0) { $indicators[] = 'high_failure_rate'; } // Slow execution if ($this->averageExecutionTimeMs > 5000) { $indicators[] = 'slow_execution'; } // High memory usage if ($this->averageMemoryUsageMB > 100) { $indicators[] = 'high_memory_usage'; } // Low throughput if ($this->throughputJobsPerHour < 10) { $indicators[] = 'low_throughput'; } return $indicators; } public function toArray(): array { return [ 'queue_name' => $this->queueName, 'total_jobs' => $this->totalJobs, 'pending_jobs' => $this->pendingJobs, 'running_jobs' => $this->runningJobs, 'completed_jobs' => $this->completedJobs, 'failed_jobs' => $this->failedJobs, 'dead_letter_jobs' => $this->deadLetterJobs, 'average_execution_time_ms' => $this->averageExecutionTimeMs, 'average_execution_time_seconds' => $this->getAverageExecutionTimeSeconds(), 'average_memory_usage_mb' => $this->averageMemoryUsageMB, 'throughput_jobs_per_hour' => $this->throughputJobsPerHour, 'success_rate' => $this->successRate->getValue(), 'failure_rate' => $this->getFailureRate()->getValue(), 'health_score' => $this->getHealthScore()->getValue(), 'is_healthy' => $this->isHealthy(), 'bottleneck_indicators' => $this->getBottleneckIndicators(), 'measured_at' => $this->measuredAt, 'additional_metrics' => $this->additionalMetrics ]; } }