Skip to content

NXDOMAIN(호스트 조회 실패)을 확정 실패로 내려 재시도를 태우지 않는다 #42

Description

@m-a-king

dev 에서 https://df 를 등록한 건(trace 3f8fd4ab9ab9fd2f9278a1a324c88629, 2026-08-15T16:06:29Z)이 이렇게 흘렀다.

  1. InternalHostGuard.verify 가 host 조회에 실패해 UnknownHostException 을 받는다
  2. 그것을 PageFetchException.upstreamError() 로 번역한다 (code UPSTREAM_ERROR, permanent=false) → 502
  3. core 의 RemoteExtractionContract.translate 는 422 만 확정 실패로 보므로 502 는 무조건 일시 실패다 → RETRYABLE 로 재시도
  4. 두 번째 시도도 같은 지점에서 실패 → item.parse.result result=failed reason=retry_exhausted

어긋나는 것이 둘이다.

운영 사유가 실제와 다르다. retry_exhausted 는 "외부가 불안정했다, 재시도 여력이나 대상 장애를 보라"는 신호인데 실제 사유는 "사용자가 존재하지 않는 주소를 넣었다"이다. 운영 액션이 정반대라, reason 을 운영 액션 기준으로 재분류한 TeamPiKi/core#938 의 취지와 어긋난다.

확정적으로 실패할 주소에 매번 호출 2회를 태운다. 같은 https://df 가 2026-08-01 과 2026-08-15 두 번 등록됐고(canonical_hash 로 item 19 재사용), 두 snapshot(32, 344) 모두 attempt_count=2 를 소진한 뒤 FAILED 로 끝났다. host 가 resolve 되지 않는다는 사실은 재시도로도 재등록으로도 바뀌지 않는다.

무엇을

InternalHostGuard 가 host 조회 실패를 확정 실패로 내린다.

  • UnknownHostExceptionPageFetchException 의 확정 팩토리로 번역한다 (code INVALID_URL, permanent=true, escalatable=false).
  • code 는 기존 INVALID_URL 을 재사용한다. 카탈로그에 이미 disposition: permanent, bucket: not_product 로 있고 core 의 PERMANENT_TRANSLATIONSnotProductPage() 로 매핑해 두었다. 따라서 core 변경은 없다 — extractor 가 code 를 바꿔 내리는 순간 core 는 재시도 없이 즉시 markFailed 로 끝낸다.
  • escalatable=false — resolve 되지 않는 host 는 헤드리스 브라우저도 같은 이유로 도달하지 못한다. "SSRF(BLOCKED_HOST)만 무조건 폴백의 예외"라는 현재 정책에 두 번째 예외가 생기므로, PageFetchException 의 그 주석과 카탈로그 주석을 함께 고친다.
  • infra 카탈로그는 INVALID_URL 엔트리에 escalatable: false 를 더한다(additive). 이 code 가 이제 fetch 경로에서도 나오기 때문이다. 머지 순서는 infra 먼저.

DNS 리졸버 일시 장애는 구분하지 않는다. InetAddress.getAllByName 은 NXDOMAIN 과 SERVFAIL, 타임아웃을 모두 같은 UnknownHostException 으로 던져 구분할 수 없다. 리졸버 장애는 박스 전역 문제라 그 자체로 별도 관측 대상이고, 그 짧은 창에서 확정 처리된 건은 사용자가 재등록하면 새 snapshot 으로 다시 시도된다. 정확한 구분이 필요해지면 RCODE 를 보는 리졸버 도입을 별건으로 다룬다.

검증

  • 단위: InternalHostGuardUnknownHostException 을 받으면 permanent=true, escalatable=false 인 PageFetchException 을 던진다
  • 통합: 조회 불가 host 로 POST /internal/extractions/link 를 호출하면 422 + {"code":"INVALID_URL"} 을 반환한다
  • 카탈로그 대조: ExtractionErrorCodeCatalogTest 가 shared-infra 카탈로그와 계속 일치한다
  • 회귀: SSRF 차단(BLOCKED_HOST)은 확정 + escalatable=false 를 그대로 유지한다

참고

  • 실패 trace: 3f8fd4ab9ab9fd2f9278a1a324c88629
  • 관련 좌표: InternalHostGuard.java:38, PageFetchException.java, TeamPiKi/infra 의 contracts/extraction-error-codes.yaml

Metadata

Metadata

Assignees

Labels

fix외부 가시적 결함 수정

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions