ProcessQuestionDifficultyCalibrationJob.php 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. <?php
  2. namespace App\Jobs;
  3. use App\Services\Analytics\QuestionDifficultyCalibrationService;
  4. use Illuminate\Bus\Queueable;
  5. use Illuminate\Contracts\Queue\ShouldQueue;
  6. use Illuminate\Foundation\Bus\Dispatchable;
  7. use Illuminate\Queue\InteractsWithQueue;
  8. use Illuminate\Queue\SerializesModels;
  9. use Illuminate\Support\Facades\Log;
  10. use Throwable;
  11. class ProcessQuestionDifficultyCalibrationJob implements ShouldQueue
  12. {
  13. use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
  14. public int $tries = 1;
  15. public int $timeout = 300;
  16. /**
  17. * @param list<array<string,mixed>> $questions
  18. */
  19. public function __construct(
  20. public string $paperId,
  21. public string $studentId,
  22. public array $questions
  23. ) {
  24. $this->questions = $this->compactQuestions($questions);
  25. // Online difficulty calibration is not on the user-visible critical
  26. // path. Keep it away from PDF workers so it cannot race report output.
  27. $this->onQueue((string) config('queue.workloads.question_difficulty_calibration', 'default'));
  28. $this->afterCommit();
  29. }
  30. public function handle(QuestionDifficultyCalibrationService $calibrationService): void
  31. {
  32. Log::warning('QuestionDifficultyCalibrationJob: 开始异步在线难度校准', [
  33. 'paper_id' => $this->paperId,
  34. 'student_id' => $this->studentId,
  35. 'question_count' => count($this->questions),
  36. 'attempt' => $this->attempts(),
  37. 'memory_mb' => round(memory_get_usage(true) / 1024 / 1024, 2),
  38. ]);
  39. $updatedQuestions = $calibrationService->updateOnlineFromPaper($this->paperId, $this->questions);
  40. Log::warning('QuestionDifficultyCalibrationJob: 异步在线难度校准完成', [
  41. 'paper_id' => $this->paperId,
  42. 'student_id' => $this->studentId,
  43. 'updated_questions' => $updatedQuestions,
  44. 'memory_peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
  45. ]);
  46. }
  47. public function failed(Throwable $exception): void
  48. {
  49. Log::error('QuestionDifficultyCalibrationJob: 异步在线难度校准最终失败', [
  50. 'paper_id' => $this->paperId,
  51. 'student_id' => $this->studentId,
  52. 'question_count' => count($this->questions),
  53. 'error' => $exception->getMessage(),
  54. 'exception' => get_class($exception),
  55. 'memory_peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
  56. ]);
  57. }
  58. /**
  59. * @param list<array<string,mixed>> $questions
  60. * @return list<array<string,mixed>>
  61. */
  62. private function compactQuestions(array $questions): array
  63. {
  64. $compact = [];
  65. foreach ($questions as $question) {
  66. if (! is_array($question)) {
  67. continue;
  68. }
  69. $questionId = $question['question_id'] ?? $question['question_bank_id'] ?? null;
  70. if ($questionId === null || $questionId === '') {
  71. continue;
  72. }
  73. $compact[] = [
  74. 'question_id' => $questionId,
  75. 'is_correct' => $question['is_correct'] ?? [],
  76. ];
  77. }
  78. return $compact;
  79. }
  80. }