Skip to content

fix(backend): 재개 후 늦게 온 꼬리질문 콜백이 살아있는 질문을 둘로 만들던 문제 - #182

Merged
i3months merged 1 commit into
devfrom
fix/late-followup-callback-after-resume
Aug 19, 2026
Merged

fix(backend): 재개 후 늦게 온 꼬리질문 콜백이 살아있는 질문을 둘로 만들던 문제#182
i3months merged 1 commit into
devfrom
fix/late-followup-callback-after-resume

Conversation

@i3months

Copy link
Copy Markdown
Member

변경 사항

#180(이어하기) 후속 검토에서 나온 두 번째 결함. 이어하기가 isTerminal() 가드의 전제를 깼다.

종료 세션에 늦게 도착한 콜백은 terminal 가드가 드롭한다. 그런데 재개된 세션은 IN_PROGRESS 라 그대로 통과한다. 재개 이전에는 INTERRUPTED 가 영구 상태였으므로 이 창이 열리지 않았다.

경합

  1. 꼬리질문 요청 → placeholder("(생성 중)") 생성
  2. 사용자 중단 → INTERRUPTED
  3. 사용자 이어하기 → 복구가 placeholder 를 FAILED 로 확정하고 다음 일반질문 발행
  4. 뒤늦게 AI 콜백 도착 → 세션이 IN_PROGRESS 라 terminal 가드 통과 → completeFollowup 이 FAILED placeholder 를 덮어써 정상 질문으로 되살림

결과: 살아있는 질문이 두 개(실패로 표시됐던 꼬리질문 + 복구가 발행한 일반질문). TTS 도 그 자리에 붙고, 사용자의 다음 답변은 마지막 메시지에만 달려 앞의 질문은 답 없는 채로 남는다.

창이 좁아 보이지만 중단 직후 바로 이어하기를 누르거나 AI(Pro 모델)가 느릴 때 충분히 열린다.

수정

applyFollowup 에서 placeholder 가 이미 FAILED 면 그 턴은 지나간 것으로 보고 드롭한다.

if (placeholder != null && placeholder.getStatus() == MessageStatus.FAILED) {
    log.info("callback.questions FOLLOWUP dropped — placeholder already failed (turn moved on). ...");
    return;
}

FAILED placeholder 가 생기는 경로는 두 가지이고 둘 다 "이 턴은 끝났다"를 뜻한다 — 생성 실패 처리(applyFollowupFailed)와 이어하기 복구(SessionResumeService.recoverTurn). 어느 쪽이든 되살아나면 안 된다.

POOL 경로는 이미 안전하다

같은 경합이 질문 풀에도 있는지 확인했다. 이어하기 복구가 풀 생성을 재요청하는 경우, 원래 콜백과 새 콜백이 둘 다 도착할 수 있다. 그런데 applyInitialQuestion 에 이미 countBySessionId > 0 가드가 있어 두 번째는 무시된다 — 별도 수정이 필요 없었다.

테스트

apply_followupOnFailedPlaceholder_isDropped — FAILED placeholder 에 늦은 콜백이 와도 상태·문구가 유지되고 save 가 호출되지 않는지 확인.

backend test 통과(ArchUnit 포함).

영향 범위

  • DB 마이그레이션: 없음
  • API contract 변경: 없음
  • 동작: 이미 실패로 확정된 꼬리질문 자리는 어떤 콜백으로도 되살아나지 않는다

이어하기(#180)가 terminal 가드의 전제를 깼다. 종료 세션에 늦게 도착한 콜백은
`isTerminal()` 로 드롭되지만, **재개된 세션은 IN_PROGRESS 라 그대로 통과한다.**

경합:

1. 꼬리질문 요청 → placeholder("(생성 중)") 생성
2. 사용자 중단 → INTERRUPTED
3. 사용자 이어하기 → 복구가 placeholder 를 FAILED 로 확정하고 다음 일반질문 발행
4. **뒤늦게 AI 콜백 도착** → 세션이 IN_PROGRESS 라 terminal 가드를 통과 →
   `completeFollowup` 이 FAILED placeholder 를 덮어써 질문으로 되살림

결과적으로 살아있는 질문이 두 개가 되고(실패로 표시됐던 꼬리질문 + 복구가 발행한 일반질문),
TTS 도 그 자리에 붙는다.

`applyFollowup` 에서 placeholder 가 이미 FAILED 면 그 턴은 지나간 것으로 보고 드롭한다.
POOL 경로는 `countBySessionId > 0` 로 이미 멱등이라 같은 문제가 없다(재개 시 풀 재요청이
있어도 중복 저장되지 않는다).

테스트: `apply_followupOnFailedPlaceholder_isDropped` — 실패 상태·문구가 유지되고
save 가 호출되지 않는지 확인.
@i3months
i3months merged commit 93a551f into dev Aug 19, 2026
5 checks passed
@i3months
i3months deleted the fix/late-followup-callback-after-resume branch August 19, 2026 06:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant