페이지 fetch 클라이언트의 라이브러리 자동 재시도를 끈다 - #50
Open
m-a-king wants to merge 1 commit into
Open
Conversation
- HttpClient5 는 I/O 오류를 기본으로 한 번 더 실행한다(maxRetries=1, 대기 0ms). 우리가 켠 적 없고 아무도 보고 있지 않던 재시도다 - 방침은 이미 코드에 적혀 있었다. application.yml 의 gemini.retry 주석이 "URL 파싱 재시도는 호출자의 recover 한 곳으로 모여 있다. 여기서 내부 재시도를 켜면 재시도가 이중으로 겹친다" 고 못박고 Gemini 쪽은 max-attempts=1 로 껐는데, fetch 쪽은 라이브러리 기본값이 살아 있었다 - 바로 윗줄 disableRedirectHandling() 과 같은 성격이다. 우리가 상위에서 관리하는 동작을 라이브러리가 몰래 또 하는 것인데, 리다이렉트는 껐고 재시도는 놓쳤다 - 성격이 다르다는 게 핵심이다. core 큐 재시도는 attempt 가 DB 에 남고 상한(MAX_ATTEMPTS=2)·메트릭·트레이스가 붙는데, 이쪽은 기록도 간격도 없이 방금 우리를 끊어낸 호스트를 즉시 다시 두드린다 prod 사고(2026-08-23)에서 드러났다. 에이블리 등록 1건이 실패했는데, 정적 fetch 한 번이 57초를 먹어 core 의 55초 예산을 통째로 소진했고 7초 만에 성공한 브라우저 렌더가 도착할 자리가 없었다. 그 57초의 절반이 이 재시도였다(12:27:04 SocketException -> 0ms 뒤 재실행 -> 24초 더 쓰고 403). 검증: 실제 소켓으로 못 박는 테스트를 넣었다. MockRestServiceServer 는 RestClient 위에 붙어 HttpClient 를 아예 안 타므로 이 설정을 못 잡는다. 연결을 받자마자 RST 로 끊는 로컬 소켓에 붙여 도착한 연결 수가 1인지 센다. 고친 줄을 빼면 이 테스트가 실패하는 것도 확인했다(negative control).
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Situation
maxRetries=1, 대기 0ms). 아무도 의도하지 않았고 아무도 보고 있지 않았다.Task
Action
PageFetchHttpClientConfig에.disableAutomaticRetries()한 줄.방침은 이미 코드에 적혀 있었다.
application.yml의gemini.retry주석이다.Gemini 쪽은 이 방침대로 껐는데 fetch 쪽은 라이브러리 기본값이 살아 있었다. 바로 윗줄
disableRedirectHandling()과 같은 성격이다 — 우리가 상위에서 관리하는 동작을 라이브러리가 몰래 또 하는 것인데, 리다이렉트는 껐고 재시도는 놓쳤다.겹치는 값이 아니라 성격이 다르다
attemptCount가 DB 에 남음MAX_ATTEMPTS=2, 초과 시 FAILED방금 우리를 끊어낸 호스트를 0ms 만에 다시 두드리는 동작이다.
검증
실제 소켓으로 못 박았다.
MockRestServiceServer는 RestClient 위에 붙어 HttpClient 를 아예 안 타므로 이 설정을 못 잡는다. 연결을 받자마자 RST 로 끊는 로컬 소켓을 두고 도착한 연결 수가 1인지 센다.고친 줄을 빼면 이 테스트가 실패하는 것도 확인했다(negative control). 357 tests 통과.
Result
escalatable=true라 브라우저 승격이 받고, core 의 attempt 2회도 그대로다.남은 것
이번 사고의 원인은 셋인데 그중 하나만 고친다.
read-timeout=15s는 전체 마감이 아니라 read 1회 간격(SO_TIMEOUT)이다. 여기에 redirect hop(최대 6회)과 A 레코드 개수가 곱해져 이론 최악이 300초를 넘는다. 벽시계 마감이 필요한데 상한 값은 fetch 성공 latency 분포 실측 후에 정해야 한다 — 지금 정하면 느리지만 결국 성공하던 몰을 자른다.headlessFirst가 요청 계약을 authorized 하나로 정리하고 헤드리스 게이트를 걷어낸다 #46 에서 제거됐고, 삭제 전 주석이 정확히 이 증상을 목적으로 적혀 있었다("plain 이 항상 차단되는 host 의 느린-실패 낭비를 없앤다"). 되살리려면 SSRF 가드 경계를 함께 세워야 해 부작용이 크다. 위 둘을 하고도 낭비가 측정되면 그때 판단.contracts/extraction-api.md§4 의 예산표가 코드와 어긋나 있다(hop 상한 3 vs 실제 5, 자동 재시도 미반영). 이 PR 로 재시도 항목은 사실이 되지만 hop 수는 여전히 다르다.연관 이슈