$examData */ public function __construct( public string $taskId, public array $examData ) { // Keep the default on the scaled worker fleet. In production today the // PDF nodes are the only horizontally scaled queue consumers. $this->onQueue((string) config('queue.workloads.exam_answer_analysis', 'pdf')); $this->afterCommit(); } public function handle(ExamAnswerAnalysisService $analysisService, TaskManager $taskManager): void { try { $taskManager->updateTaskProgress($this->taskId, 10, '正在分析考试答题...'); Log::warning('ProcessExamAnswerAnalysisJob: 开始处理考试答题分析', [ 'task_id' => $this->taskId, 'paper_id' => $this->examData['paper_id'] ?? null, 'student_id' => $this->examData['student_id'] ?? null, 'question_count' => count($this->examData['questions'] ?? []), 'attempt' => $this->attempts(), 'memory_mb' => round(memory_get_usage(true) / 1024 / 1024, 2), ]); $result = $analysisService->analyzeExamAnswers($this->examData); $taskManager->markTaskCompleted($this->taskId, [ 'paper_id' => $this->examData['paper_id'] ?? null, 'student_id' => $this->examData['student_id'] ?? null, 'analysis_status' => 'completed', 'pdf_status' => 'queued', 'analyzed_knowledge_points' => count($result['knowledge_point_analysis'] ?? []), 'result_url' => isset($this->examData['student_id'], $this->examData['paper_id']) ? route('api.exam-answer-analysis.result', [ 'student_id' => $this->examData['student_id'], 'paper_id' => $this->examData['paper_id'], ]) : null, 'pdf_lookup_url' => isset($this->examData['paper_id']) ? route('api.exam-analysis.pdf', ['paper_id' => $this->examData['paper_id']]) : null, ]); $taskManager->sendCallback($this->taskId); Log::warning('ProcessExamAnswerAnalysisJob: 考试答题分析完成', [ 'task_id' => $this->taskId, 'paper_id' => $this->examData['paper_id'] ?? null, 'student_id' => $this->examData['student_id'] ?? null, 'memory_peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2), ]); } catch (Throwable $e) { $taskManager->markTaskFailed($this->taskId, $e->getMessage()); $taskManager->sendCallback($this->taskId); Log::error('ProcessExamAnswerAnalysisJob: 考试答题分析失败', [ 'task_id' => $this->taskId, 'paper_id' => $this->examData['paper_id'] ?? null, 'student_id' => $this->examData['student_id'] ?? null, 'error' => $e->getMessage(), 'exception' => get_class($e), 'memory_peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2), ]); throw $e; } } public function failed(Throwable $exception): void { Log::error('ProcessExamAnswerAnalysisJob: 队列任务最终失败', [ 'task_id' => $this->taskId, 'paper_id' => $this->examData['paper_id'] ?? null, 'student_id' => $this->examData['student_id'] ?? null, 'error' => $exception->getMessage(), ]); } }