sinceDate($hours); $sql = " SELECT COUNT(*) AS total, SUM(outcome = 'success') AS success, SUM(outcome = 'partial') AS partial, SUM(outcome IN ('failed', 'failed_permanent')) AS failed, SUM(state IN ('pending','scheduled','processing')) AS active FROM {$this->queueTable} WHERE created_at >= %s "; return (array) $this->db->get_row( $this->db->prepare($sql, $since), ARRAY_A ); } public function byHour(int $hours = 24): array { $since = $this->sinceDate($hours); $sql = " SELECT HOUR(created_at) AS hour, COUNT(*) AS total, SUM(outcome = 'success') AS success, SUM(outcome IN ('failed','failed_permanent')) AS failed FROM {$this->queueTable} WHERE created_at >= %s GROUP BY hour ORDER BY hour ASC "; $rows = $this->db->get_results( $this->db->prepare($sql, $since), ARRAY_A ); $result = []; foreach ($rows as $row) { $key = str_pad($row['hour'], 2, '0', STR_PAD_LEFT); $result[$key] = [ 'total' => (int) $row['total'], 'success' => (int) $row['success'], 'failed' => (int) $row['failed'], ]; } return $result; } public function liveByUser(int $hours = 24, int $limit = 100): array { $since = $this->sinceDate($hours); $sql = " SELECT user_id, COUNT(*) AS total, SUM(outcome = 'success') AS success, SUM(outcome IN ('failed','failed_permanent')) AS failed, AVG(retries) AS avg_retries FROM {$this->queueTable} WHERE created_at >= %s GROUP BY user_id ORDER BY total DESC LIMIT %d "; return $this->db->get_results( $this->db->prepare($sql, $since, $limit), ARRAY_A ); } public function liveQueueHealth(): array { $sql = " SELECT SUM(state = 'pending') AS pending, SUM(state = 'scheduled') AS scheduled, SUM(state = 'processing') AS processing, MIN(scheduled_at) AS oldest_scheduled, SUM( state = 'processing' AND started_at < DATE_SUB(NOW(), INTERVAL 15 MINUTE) ) AS stuck FROM {$this->queueTable} "; return (array) $this->db->get_row($sql, ARRAY_A); } public function liveByType(int $hours = 24): array { $since = gmdate('Y-m-d H:i:s', time() - $hours * HOUR_IN_SECONDS); $sql = " SELECT type, COUNT(*) AS total, SUM(outcome = 'success') AS success, SUM(outcome = 'partial') AS partial, SUM(outcome IN ('failed','failed_permanent')) AS failed, AVG(TIMESTAMPDIFF(SECOND, started_at, completed_at)) AS avg_duration FROM {$this->queueTable} WHERE completed_at IS NOT NULL AND created_at >= %s GROUP BY type "; return $this->db->get_results( $this->db->prepare($sql, $since), ARRAY_A ); } /* ---------- Historical metrics (stats table) ---------- */ public function dailySummary( \DateTimeInterface $from, \DateTimeInterface $to ): array { $sql = " SELECT date, SUM(total_operations) AS total, SUM(successful_operations) AS success, SUM(partial_operations) AS partial, SUM(failed_operations) AS failed, SUM(failed_permanent_operations) AS failed_permanent, SUM(total_items_processed) AS items, AVG(average_duration) AS avg_duration, MAX(max_duration) AS max_duration FROM {$this->statsTable} WHERE date BETWEEN %s AND %s GROUP BY date ORDER BY date "; return $this->db->get_results( $this->db->prepare( $sql, $from->format('Y-m-d'), $to->format('Y-m-d') ), ARRAY_A ); } public function dailyByType( \DateTimeInterface $from, \DateTimeInterface $to ): array { $sql = " SELECT date, type, total_operations, successful_operations, partial_operations, failed_operations, failed_permanent_operations, average_duration, max_duration FROM {$this->statsTable} WHERE date BETWEEN %s AND %s ORDER BY date, type "; return $this->db->get_results( $this->db->prepare( $sql, $from->format('Y-m-d'), $to->format('Y-m-d') ), ARRAY_A ); } }