feat: PROCESSING 좀비 상태 복구 - 실행 소유권(analysis_run_id) 및 can_retry API 필… - #84
feat: PROCESSING 좀비 상태 복구 - 실행 소유권(analysis_run_id) 및 can_retry API 필…#846ye0m wants to merge 2 commits into
Conversation
|
전체적으로 #52 의도대로 잘 구현된 것 확인했습니다. 다만 머지 전에 한 가지 동시성 케이스만 확인/수정 부탁드립니다. 현재 분석이 이미 5분을 넘긴 상태에서는 아래 순서가 가능해 보입니다.
즉 상태 소유권 덮어쓰기는 막았지만,
이 케이스 테스트도 하나 추가 부탁드립니다. |
|
지적하신 동시성 케이스 반영했습니다. 수정 내용 _finish_success()가 소유권을 잃었을 때(조건부 UPDATE 0건) 조용히 return하던 걸, StaleAnalysisRunError를 던지도록 변경했습니다. python _execute_analysis()도 이 예외를 잡아서, StudyTask 저장은 끝났더라도 최종 완료 처리 시점에 소유권을 잃었다면 tasks를 정상 반환하지 않고 예외를 그대로 전파하도록 수정했습니다. python 테스트 추가 test_ownership_lost_between_save_and_finish_does_not_report_success — _finish_success()를 patch해서, 그 함수가 호출되는 바로 그 시점(StudyTask 저장 커밋 직후, 완료 처리 직전)에 소유권이 다른 실행으로 넘어가는 상황을 재현했습니다. analyze_and_estimate()가 StaleAnalysisRunError를 던지고, analysis_status는 COMPLETED로 갱신되지 않으며, 이미 저장된 StudyTask는 그대로 남아있는 것까지 확인했습니다. 기존 test_finish_success_ignored_when_run_superseded도 새 동작(예외 발생)에 맞게 같이 수정했습니다. 검증 결과 python manage.py test → Ran 252 tests, OK 참고: _finish_failure()는 이번엔 대칭적으로 고치지 않았습니다. 실패 경로에서 소유권을 잃으면 원래 예외(AIAnalysisError 등)가 그대로 "실패"로 전달되는데, 이건 이번에 고친 "거짓 성공" 케이스보다 위험도가 낮다고 판단했습니다. 필요하시면 후속으로 대칭 처리하겠습니다. |
close #52
작업 내용
exams/models.py
StudyMaterial에 analysis_started_at(PROCESSING 진입 시각), analysis_run_id(실행 식별자 UUID) 필드 추가
exams/services/analysis_orchestrator.py
PROCESSING_TIMEOUT_SECONDS = 300(5분) 기준으로 좀비 PROCESSING 판정, retry_analysis()에서만 구제 허용 (정책 단순화)
재시도 횟수 제한을 FAILED/좀비 양쪽에 동일하게 적용 (좀비라고 우회 불가)
analysis_started_at이 NULL인 경우(필드 추가 이전부터 PROCESSING이었던 데이터)도 좀비로 취급
analysis_run_id로 실행 소유권 관리 — 저장 직전 소유권 재확인(StaleAnalysisRunError), _finish_success/_finish_failure도 조건부 UPDATE로 변경해 뒤늦은 실행이 최신 상태를 덮어쓰지 못하게 방지
get_analysis_status()에 is_stale/can_retry/retry_after_seconds 추가
exams/views.py
material_analysis_status 응답에 can_retry/retry_after_seconds 포함
마이그레이션: exams/migrations/0003_studymaterial_analysis_run_id_and_more.py
exams/tests.py
ProcessingTimeoutTestCase(22개), MaterialAnalysisViewTestCase에 5개 추가 (총 27개)
검증 결과
python manage.py test exams.tests.ProcessingTimeoutTestCase → Ran 22 tests, OK
python manage.py test exams.tests.MaterialAnalysisViewTestCase → Ran 25 tests, OK
python manage.py test → Ran 240 tests, OK
manage.py check / makemigrations --check → 이상 없음