repository = $repository ?? new PipelineRepository(); } /** * Get detailed run status with progress calculations. * * @param int $pipelineId Pipeline ID * @param int $runId Run ID * @return array{success: bool, error?: string, data?: array} */ public function execute(int $pipelineId, int $runId): array { $run = $this->repository->findRunById($runId); if ($run === null || (int) $run['pipeline_id'] !== $pipelineId) { return ['success' => false, 'error' => 'Run nicht gefunden']; } return [ 'success' => true, 'data' => $this->buildStatusData($run), ]; } /** * Build comprehensive status data from run record. */ private function buildStatusData(array $run): array { $startedAt = strtotime($run['started_at'] ?? 'now'); $elapsed = time() - $startedAt; $total = (int) ($run['documents_total'] ?? 0); $processed = (int) ($run['documents_processed'] ?? 0); $progress = $total > 0 ? min(100, round(($processed / $total) * 100)) : 0; // Cap processed display to not exceed total $processedDisplay = min($processed, $total); $estimatedRemaining = $this->calculateEta($elapsed, $processed, $total); $lastUpdate = strtotime($run['last_update_at'] ?? $run['started_at'] ?? 'now'); $isStalled = (time() - $lastUpdate) > 60 && $run['status'] === 'running'; $isTerminal = in_array($run['status'], ['completed', 'failed', 'cancelled'], true); return [ 'status' => $run['status'], 'current_step' => $run['current_step'], 'current_document' => $run['current_document'], 'documents_total' => $total, 'documents_processed' => $processed, 'documents_failed' => (int) ($run['documents_failed'] ?? 0), 'chunks_created' => (int) ($run['chunks_created'] ?? 0), 'embeddings_created' => (int) ($run['embeddings_created'] ?? 0), 'progress' => $progress, 'elapsed' => $elapsed, 'elapsed_formatted' => gmdate('i:s', $elapsed), 'estimated_remaining' => $estimatedRemaining, 'estimated_formatted' => $estimatedRemaining !== null ? gmdate('i:s', $estimatedRemaining) : null, 'log_tail' => $run['log_tail'] ?? '', 'is_stalled' => $isStalled, 'is_terminal' => $isTerminal, 'completed_at' => $run['completed_at'], 'error_log' => $run['error_log'], ]; } /** * Calculate estimated time remaining. */ private function calculateEta(int $elapsed, int $processed, int $total): ?int { if ($processed <= 0 || $total <= $processed) { return null; } $avgTimePerDoc = $elapsed / $processed; $remaining = $total - $processed; return (int) ($avgTimePerDoc * $remaining); } }