Skip to content

배포: Fly idle_timeout 상한(900초)에 맞춰 프록시 읽기 한도에 상한을 둔다 - #12

Closed
NiceTry3675 wants to merge 1 commit into
mainfrom
fix/fly-idle-timeout
Closed

NiceTry3675 wants to merge 1 commit into
mainfrom
fix/fly-idle-timeout

Conversation

@NiceTry3675

Copy link
Copy Markdown
Owner

원인

2026-09-03 Deploy API to Fly 실행(#33744350356)이 실패했습니다.

failed to update VM: Services [0] Ports [0] HTTP options Idle timeout must be less than or equal to 900

직전 커밋(5b0c997)이 fly.toml의 idle_timeout을 2,100초로 올렸는데, Fly가 허용하는 최댓값은 900초입니다.

해결

edge를 읽기 한도에 맞출 수 없으니 읽기 한도를 edge에 맞춥니다.

  • fly.toml: idle_timeout = 900 (Fly 최댓값)
  • apps/api/main.py: 상류 읽기 한도는 출력 토큰 상한 × 30ms에 비례하되 HARNEST_PROXY_MAX_TIMEOUT(기본 780초)에서 멈춤
  • apps/web/src/lib/llm.ts: 공유 경로 클라이언트도 같은 상한 + 60초(840초)까지만 대기
  • 순서 유지: 서버 504(780초) → 클라이언트 시간 초과(840초) → edge 단절(900초)
  • README·SPEC §7.1·테스트 갱신

영향

공유 키 경로에서 13분을 넘기는 생성은 504로 끝납니다(약 26,000토큰 분량 기준). 그보다 긴 생성은 본인 키 직행 경로를 써야 합니다. 본인 키 경로는 변경 없음.

검증

  • cd apps/api && python3 test_api.py 통과
  • npm run typecheck 통과
  • npx vitest run apps/web/src/lib/llm.test.ts 106개 통과

Fly는 http_options.idle_timeout을 900초까지만 받아 2,100초 설정이 배포를 거부했다
(Idle timeout must be less than or equal to 900). edge를 읽기 한도에 맞출 수 없으니 반대로
읽기 한도를 edge에 맞춘다: 서버의 상류 읽기 한도는 출력 토큰 상한 × 30ms에 비례하되
HARNEST_PROXY_MAX_TIMEOUT(기본 780초)에서 멈추고, 브라우저 공유 경로 클라이언트도 같은 상한에
60초 여유를 더해 840초까지만 기다린다. 서버 504(780초) → 클라이언트 시간 초과(840초) → edge
단절(900초) 순서가 유지되어 재시도 금지·본인 키 권장 안내가 사용자에게 닿는다.
Copilot AI lite review requested due to automatic review settings September 3, 2026 11:30
@NiceTry3675

Copy link
Copy Markdown
Owner Author

main에 직접 푸시하기로 해서 닫습니다.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

새로 추가된 웹 테스트에서 fake timer가 복구되지 않는 문제 등(테스트 신뢰성/설정 드리프트)으로 CI 안정성과 유지보수성에 영향을 줄 수 있습니다.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Fly.io edge의 idle_timeout 상한(900초) 제약 때문에 배포가 실패한 문제를 해결하기 위해, shared-key 프록시 경로의 서버 상류(read) 타임아웃을 edge 한도 아래로 “상한” 처리하고, 웹 클라이언트도 그 상한(+60초)까지만 기다리도록 맞춘 PR입니다. 프록시 경로에서 서버 504 → 클라이언트 타임아웃 → edge 단절 순서를 보장해 사용자에게 안내가 도달하도록 하는 목적이 코드/문서/테스트에 반영돼 있습니다.

Changes:

  • fly.toml의 idle_timeout을 Fly 허용 상한인 900초로 조정하고, 관련 운영 제약을 주석으로 정리
  • API 프록시 상류 읽기 한도에 HARNEST_PROXY_MAX_TIMEOUT(기본 780초) 상한을 추가하고 계산식을 상한 적용으로 변경
  • 웹 shared 프록시 요청도 동일 상한(+60초)까지만 대기하도록 캡을 추가하고, SPEC/README/테스트를 갱신
File summaries
File Description
SPEC.md shared-key 프록시의 “전송 계층 제한” 설명에 edge 유휴 한도 제약을 명시
fly.toml Fly edge idle_timeout을 900초로 낮추고 상류/클라이언트 타임아웃 상호관계를 주석으로 업데이트
apps/web/src/lib/llm.ts shared 프록시 요청 타임아웃을 780초 상한(+60초 마진)으로 캡핑
apps/web/src/lib/llm.test.ts shared 프록시 기본 타임아웃 상한(840초) 동작을 검증하는 테스트 추가
apps/api/test_api.py API 상류 read timeout 상한(780초) 동작을 테스트로 고정
apps/api/README.md Fly 상한 및 HARNEST_PROXY_MAX_TIMEOUT 도입에 따른 운영/설정 가이드 갱신
apps/api/main.py _upstream_read_timeout에 상한(HARNEST_PROXY_MAX_TIMEOUT)을 적용하도록 변경
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1599 to +1621
it("기본 한도는 서버 읽기 한도 상한(780초) + 60초에서 멈춘다 — edge 유휴 한도(900초)보다 먼저 끊지 않고, 출력 상한이 커도 그 이상 기다리지 않는다", async () => {
vi.useFakeTimers();
const hanging = (init?: RequestInit) =>
new Promise<Response>((_, reject) => {
init?.signal?.addEventListener("abort", () =>
reject(new DOMException("The user aborted a request.", "AbortError")),
);
});
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => hanging(init));
vi.stubGlobal("fetch", fetchMock);
// 64,000토큰 × 30ms = 1,920초 — 상한 없이는 edge(900초)가 먼저 끊어 시간 초과 안내가 닿지 않는다
const assertion = expect(
createSharedOpenAIClient("gpt-5.6-sol", { apiBase: "http://api.test", retryBaseMs: 0 }).complete(
"생성",
{ maxOutputTokens: 64_000 },
),
).rejects.toThrow("OpenAI(공유) 요청 시간 초과 (840000ms)");
await vi.advanceTimersByTimeAsync(839_999);
expect(fetchMock).toHaveBeenCalledTimes(1);
await vi.advanceTimersByTimeAsync(1);
await assertion;
expect(fetchMock).toHaveBeenCalledTimes(1);
});
Comment thread apps/web/src/lib/llm.ts
Comment on lines +71 to +74
// 서버의 읽기 한도 상한(apps/api HARNEST_PROXY_MAX_TIMEOUT 기본값) — 서버는 벤더 응답을 다 받은
// 뒤에야 첫 바이트를 보내므로 배포 edge의 유휴 한도(Fly 최댓값 900초) 아래에 머물러야 한다. 클라이언트도
// 같은 상한을 알아야 서버 504(상한 + 0초)와 edge 단절(900초)보다 늦게, 즉 상한 + 60초에 끊는다.
const SHARED_PROXY_TIMEOUT_CEILING_MS = 780_000;

This branch was successfully deployed

1 active deployment
github-pages — fb53baf4 Deployed Sep 3, 2026 by NiceTry3675 via deploy #37
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.

2 participants