AI 연동의 실패 경로 네 곳이 "재스캔이 복구한다"를 안전망으로 전제하는데, 재스캔이 코드에 없다. @Scheduled도 @EnableScheduling도 레포 전체에 없다.
이 이슈는 결정 대기다. 사실을 잊지 않도록 남기는 것이고, 실행 주체가 정해지기 전에는 구현 티켓을 만들지 않는다. 담당자는 추적용이며 구현 소유를 뜻하지 않는다.
재스캔을 전제하는 네 곳
AiProcessClient.java:30·:57에도 같은 전제가 javadoc으로 적혀 있다.
없는 것
- 재스캔 스케줄러 —
@Scheduled / @EnableScheduling 0건
- retry / circuit breaker — Resilience4j 미도입,
build.gradle에 관련 의존성 없음
- 있는 것은 타임아웃뿐이다:
pinlog.ai.process.connect-timeout=1s, read-timeout=3s
증상
한 번 실패한 Context는 영구히 PENDING으로 남는다. 임베딩과 키워드가 절대 만들어지지 않고, 자연어 검색이 그 Context를 영원히 찾지 못한다. 상태만 보면 "처리 대기 중"이라 정상과 구별되지 않는다.
특히 PINLOG_AI_INTERNAL_SECRET이 비어 있으면 FastAPI가 전부 401을 주는데, AiProcessClient가 그것도 삼키고 WARN 로그만 남긴다. 즉 시크릿 주입이 빠진 채로 배포되면 아무 Context도 처리되지 않으면서 에러 응답은 하나도 나오지 않는다.
스키마가 이미 정해 둔 것
ai.context_ai_state(V100__ai_tables.sql)를 보면 몇 가지는 결정거리가 아니다.
CHECK (retry_count BETWEEN 0 AND 3) — 최대 재시도는 3회로 DB가 못 박아 뒀다
updated_at TIMESTAMPTZ NOT NULL DEFAULT now() — stale 판정의 시계로 쓸 값이 이미 있다
embedding_status와 keyword_status가 독립 전이한다. 한쪽만 PENDING인 행이 정상적으로 존재한다
- 상태는
PENDING·PROCESSING·COMPLETED·FAILED·CANCELLED 다섯
실행 주체가 미확정이다 — 이 이슈가 결정 대기인 이유
문서 근거가 갈린다.
- 백엔드 쪽:
S15P11A705-102의 쓰기 책임 매트릭스가 백엔드에 PENDING·CANCELLED·retry_count·**Finalizer FAILED**를 배정한다. Finalizer가 백엔드 몫이면 재스캔도 백엔드로 읽힌다.
- AI 쪽:
S15P11A705-121(AI 레포 결함 티켓) 본문이 "인증 실패가 재스캔 주기마다 무한 재시도된다"고 쓴다. AI 레포에 docs/spec/failure-recovery.md라는 재시도·복구 계약 문서가 따로 있다.
- 미결이라고 적힌 곳:
S15P11A705-97 확인 요청 4가 "stale 판정 기준(상태·시간), recovery 실행 주체·주기, idempotency, 동시성 잠금, 최대 재시도·dead-letter/관측 방식을 확정한다"고 그대로 미뤄 두었다.
S15P11A705-102는 제외 범위에 "재스캔 Scheduler·FAILED Finalizer — 별건"이라고 적고 미뤘다. 그 별건이 아직 티켓으로 존재하지 않는다.
정해야 할 것
- 실행 주체 — 백엔드 스케줄러인가, AI 워커인가, 별도 Job인가. 이 답이 나머지를 좌우한다.
- 대상 상태 범위 —
PENDING만인가, PROCESSING까지 회수하는가. PROCESSING은 -102 매트릭스상 AI 워커가 쓰는 상태라, 백엔드가 회수하면 남의 상태를 덮는다. 파트 간 합의가 필요하다.
- stale 기준 시간과 주기 — AI 후처리가 실제로 얼마나 걸리는지에 달려 있어 AI 파트 수치가 필요하다. 이 레포는 정책 수치를
@ConfigurationProperties로 빼는 선례가 있다(S15P11A705-120 Feed 가중치).
- 동시 실행 방지 — 여러 파드가 같은 행을 집지 않게 하는 방식.
- 관측 — 영구 PENDING이 쌓이는 것을 무엇이 알려주는가. 지금은 알려주는 것이 없다.
범위 밖
S15P11A705-121의 FastAPI 재시도·오류 분류 정정은 AI 레포 작업이며 이 이슈와 별개다. 다만 3번(기준 시간)이 그쪽 결론과 맞물린다.
- 재시도 상한 자체는 스키마가 3회로 고정했으므로 논의 대상이 아니다.
AI 연동의 실패 경로 네 곳이 "재스캔이 복구한다"를 안전망으로 전제하는데, 재스캔이 코드에 없다.
@Scheduled도@EnableScheduling도 레포 전체에 없다.이 이슈는 결정 대기다. 사실을 잊지 않도록 남기는 것이고, 실행 주체가 정해지기 전에는 구현 티켓을 만들지 않는다. 담당자는 추적용이며 구현 소유를 뜻하지 않는다.
재스캔을 전제하는 네 곳
AiIntegrationConfig.java:68AiProcessClient.java:90ContextAiRequestedListener.java:50ContextAiStateRepository.java:13AiProcessClient.java:30·:57에도 같은 전제가 javadoc으로 적혀 있다.없는 것
@Scheduled/@EnableScheduling0건build.gradle에 관련 의존성 없음pinlog.ai.process.connect-timeout=1s,read-timeout=3s증상
한 번 실패한 Context는 영구히
PENDING으로 남는다. 임베딩과 키워드가 절대 만들어지지 않고, 자연어 검색이 그 Context를 영원히 찾지 못한다. 상태만 보면 "처리 대기 중"이라 정상과 구별되지 않는다.특히
PINLOG_AI_INTERNAL_SECRET이 비어 있으면 FastAPI가 전부 401을 주는데,AiProcessClient가 그것도 삼키고 WARN 로그만 남긴다. 즉 시크릿 주입이 빠진 채로 배포되면 아무 Context도 처리되지 않으면서 에러 응답은 하나도 나오지 않는다.스키마가 이미 정해 둔 것
ai.context_ai_state(V100__ai_tables.sql)를 보면 몇 가지는 결정거리가 아니다.CHECK (retry_count BETWEEN 0 AND 3)— 최대 재시도는 3회로 DB가 못 박아 뒀다updated_at TIMESTAMPTZ NOT NULL DEFAULT now()— stale 판정의 시계로 쓸 값이 이미 있다embedding_status와keyword_status가 독립 전이한다. 한쪽만 PENDING인 행이 정상적으로 존재한다PENDING·PROCESSING·COMPLETED·FAILED·CANCELLED다섯실행 주체가 미확정이다 — 이 이슈가 결정 대기인 이유
문서 근거가 갈린다.
S15P11A705-102의 쓰기 책임 매트릭스가 백엔드에PENDING·CANCELLED·retry_count·**FinalizerFAILED**를 배정한다. Finalizer가 백엔드 몫이면 재스캔도 백엔드로 읽힌다.S15P11A705-121(AI 레포 결함 티켓) 본문이 "인증 실패가 재스캔 주기마다 무한 재시도된다"고 쓴다. AI 레포에docs/spec/failure-recovery.md라는 재시도·복구 계약 문서가 따로 있다.S15P11A705-97확인 요청 4가 "stale 판정 기준(상태·시간), recovery 실행 주체·주기, idempotency, 동시성 잠금, 최대 재시도·dead-letter/관측 방식을 확정한다"고 그대로 미뤄 두었다.S15P11A705-102는 제외 범위에 "재스캔 Scheduler·FAILED Finalizer — 별건"이라고 적고 미뤘다. 그 별건이 아직 티켓으로 존재하지 않는다.정해야 할 것
PENDING만인가,PROCESSING까지 회수하는가.PROCESSING은-102매트릭스상 AI 워커가 쓰는 상태라, 백엔드가 회수하면 남의 상태를 덮는다. 파트 간 합의가 필요하다.@ConfigurationProperties로 빼는 선례가 있다(S15P11A705-120Feed 가중치).범위 밖
S15P11A705-121의 FastAPI 재시도·오류 분류 정정은 AI 레포 작업이며 이 이슈와 별개다. 다만 3번(기준 시간)이 그쪽 결론과 맞물린다.