Skip to content

feat(S15P11A705-290): Context→AI 요청 경로의 인메모리 큐를 Kafka로 교체 - #179

Draft
minyongP wants to merge 8 commits into
devfrom
feat/S15P11A705-290-context-ai-kafka
Draft

feat(S15P11A705-290): Context→AI 요청 경로의 인메모리 큐를 Kafka로 교체#179
minyongP wants to merge 8 commits into
devfrom
feat/S15P11A705-290-context-ai-kafka

Conversation

@minyongP

@minyongP minyongP commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

요약

Record 저장 커밋 후 FastAPI 호출에 쓰던 인메모리 큐(@Async + aiCallExecutor)를 Kafka 발행 → back 내부 컨슈머 경로로 교체합니다. FastAPI 계약과 재스캔 안전망은 그대로입니다. 브로커 선택(Kafka)의 근거와 트레이드오프, back#129의 AI 파트 질문 5개에 대한 답은 BD-48에 있습니다.

Jira (필수)

  • S15P11A705-290

관련 GitHub Issue (선택)

변경 사항

  • 커밋 후 리스너가 HTTP 대신 Kafka 토픽(context-ai.process)에 발행 (ContextAiProcessPublisher). 발행 실패는 기존 의미론대로 삼키고(PENDING 유지 → 재스캔 복구), max.block.ms=1000으로 브로커 장애가 요청 스레드를 붙잡는 상한을 걸었습니다
  • back 내부 컨슈머(ContextAiProcessConsumer)가 소비해 기존과 동일한 POST /internal/v1/context/process 호출 수행 — AI 파트 코드·계약 변경 없음
  • 실패 격리: 5xx·연결 실패는 @RetryableTopic 재시도 토픽 체인(지수 백오프 1s→2s→4s), 4xx·역직렬화 실패는 DLT 직행, DLT 격리는 ERROR 로그
  • 멱등 가드: ai.context_ai_state 기준 — 두 단계 모두 PENDING을 지난 Context는 중복 전달을 생략
  • aiCallExecutor·@EnableAsync 제거(이 리스너 전용이었음), AiProcessClient에 던지는 진입점 processOrThrow() 추가(삼키는 process()는 재스캔용 불변)
  • 로컬: compose.yaml에 Kafka(KRaft 단일 노드) 추가. 테스트: Testcontainers apache/kafka:4.1.0, 컨텍스트별 토픽·그룹 격리
  • 문서: BD-48 신규, BD-17 상태 → Superseded(전달 수단에 한함), worklog 항목

테스트 / 검증

  • ./gradlew clean check --no-daemon — BUILD SUCCESSFUL (3m 52s, 테스트·checkstyle·jacoco 80% 게이트 포함)
  • DB 변경 시 PostgreSQL 통합 테스트 — 스키마 변경 없음, 상태 검증은 기존 Testcontainers 경로 사용

RED → GREEN (이 세션의 TDD 기록):

  • RED: 소비자 구현 전 ContextAiKafkaPipelineTests.messageOnTheTopicReachesFastApiThroughTheConsumer FAILED (발행만 되고 호출 없음)
  • RED: 재시도 체인 구현 전 serverErrorsExhaustTheRetryChainAndLandInTheDlt · badRequestGoesStraightToTheDltWithoutRetry FAILED
  • RED: 멱등 가드 구현 전 duplicateDeliveryForAnAlreadyHandledContextIsSkipped FAILED
  • GREEN: ./gradlew test --tests ContextAiKafkaPipelineTests --tests ContextAiEnqueueTests — 13 tests, BUILD SUCCESSFUL
  • Regression: 기존 ContextAiEnqueueTests 8개(커밋-호출 순서·롤백·삭제 생략)가 새 경로 위에서 그대로 통과

배경

  • back#129 안 C. 유실 방지는 이미 DB State가 해결하므로 이 변경의 실익은 복구 지연 단축(재스캔 5분 → 백오프 수 초)과 실패 격리(DLT)이고, 나머지 절반은 학습 가치입니다 — BD-48에 그렇게 명시했습니다.

리뷰 포인트

  1. 재시도 주체 이중화 경계 — 체인(순간 장애)과 재스캔(그 밖 전부)의 역할 구분이 ContextAiProcessConsumer·AiRescanScheduler Javadoc과 BD-48에 있습니다
  2. 5xx·연결 끊김 기존 테스트가 재시도 3회를 전부 소비하도록 바뀐 것 — 의미 변화의 명시적 기록입니다

미결 / 후속

  • 머지 선행 조건: INFRA의 Kafka 브로커 배포(dev). 그때까지 draft로 둡니다. KAFKA_BOOTSTRAP_SERVERS 주입 필요 (BD-46과 같은 원칙)
  • ⚠️ 문서 충돌(직접 고치지 않았습니다): AI 파트 소유 docs/ai/spec/ai-integration.md 4장이 인메모리 큐·@Async를 서술 — 갱신을 요청드립니다. 공용 계약 10_MVP_기능범위 §2(MQ 제외)는 back#129 합의로 대체 — docs 레포 후속 PR 필요
  • DLT 지표·알림은 /metrics prod 승격 승인 이후 후속. 안 B(완료 이벤트 역방향)는 별도 논의

🤖 Generated with Claude Code

minyongP and others added 8 commits August 4, 2026 09:32
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
발행 실패는 삼킨다 — PENDING이 커밋되어 있어 재스캔이 복구한다(기존 의미론 유지).
aiCallExecutor·@EnableAsync는 이 리스너 전용이었으므로 함께 제거한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5xx·연결 실패는 백오프를 늘려 가며 재시도하고, 4xx·역직렬화 실패는 몇 번을
보내도 같으므로 재시도 없이 DLT로 직행한다. DLT 격리는 ERROR 로그로 남긴다 —
상태는 PENDING으로 남아 있어 최종 처분은 여전히 재스캔·Finalizer의 몫이다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
at-least-once 전달에서 중복은 전제다. 걸러 내는 근거는 브로커가 아니라
진실의 원본인 ai.context_ai_state다 — 두 단계 모두 PENDING을 지났으면 생략한다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
캐시된 컨텍스트들이 토픽·그룹을 공유하면 리밸런스 재전달이 다른 클래스의
'호출 없음' 검증 구간에 흘러든다. Hikari 풀도 5로 줄인다 — 컨텍스트가 하나
늘며 Postgres max_connections(100)를 넘겼다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@minyongP minyongP added the enhancement 새 기능·개선 (feat) label Aug 4, 2026
@minyongP minyongP self-assigned this Aug 4, 2026
minyongP

This comment was marked as low quality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement 새 기능·개선 (feat)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant