Skip to content

perf(session): 매 스텝 summarize 가 세션 전체를 읽지 않게 하기 (upstream #30127) - #335

Merged
ksy90101 merged 2 commits into
mainfrom
perf/summary-no-full-load
Nov 10, 2026
Merged

ksy90101 merged 2 commits into
mainfrom
perf/summary-no-full-load

Conversation

@ksy90101

@ksy90101 ksy90101 commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

배경

opencode 컨테이너(2GiB) OOM 대응의 세 번째 단계입니다(#333 턴 요약, #334 prune). dev 실측(#334)에서 남은 OOM 은 매 스텝 도는 SessionSummary.summarize 가 세션 전체를 읽는 구간에서 났습니다. 이 함수는 스텝마다(processor.ts step-finish, prompt.ts 첫 스텝) Session.messages 로 세션 전체를 올린 뒤 snapshot 해시로 diff 를 계산합니다.

그런데 우리 환경에서는 snapshot 이 구조적으로 꺼져 있습니다. 작업 폴더의 .git 은 project id 마커라(enk/workspace-repo.ts) git rev-parse 에 실패해 프로젝트 vcs 가 비고, snapshot 은 vcs === "git" 일 때만 켜집니다. 10월 OOM 팀 4곳의 step part 약 2.3만 개, dev 팀 266 의 208개 모두 snapshot 이 없었고, 저장된 턴 diff 도 전부 [] 였습니다. 즉 매 스텝 세션 전체를 읽고 빈 결과를 쓰고 있었습니다.

upstream 은 V1 에서 같은 문제를 anomalyco/opencode#30127(2026-05-31, 포크 분기 이후)로 고쳤고, V2 는 매 스텝 요약을 없애고 요청 시 인덱스로 필요한 행만 읽습니다.

변경사항

  • upstream fix(opencode): remove automatic full session diffs anomalyco/opencode#30127 의 summary 부분을 이식했습니다.
    • summarize: 세션 요약은 0, session.diff 이벤트는 빈 목록으로 보낸 뒤, snapshot: false 면 세션을 읽지 않고 끝냅니다. snapshot 이 켜진 경우에만 세션을 읽어 턴 diff 를 질문 메시지에 남깁니다.
    • SessionSummary.diff: messageID 가 없으면(세션 전체 diff) 빈 목록, 있으면 그 질문 메시지에 저장된 턴 diff 를 돌려줍니다.
    • Session.diff(공유 기능용)도 빈 목록을 돌려줍니다.
  • docker/opencode.jsonc 끝에 "snapshot": false 를 넣어(develop 의 permission 변경과 충돌하지 않게 파일 끝에 둠) 파드에서 위 조기 종료가 타게 했습니다. 원래 꺼져 있던 기능이라 다른 동작은 바뀌지 않습니다.
  • fix(opencode): remove automatic full session diffs anomalyco/opencode#30127 의 TUI 대기 표시 수정은 이번 작업과 무관해 넣지 않았습니다. 되돌리기(revert.ts)의 diff 계산은 그대로입니다.

대안 분석

  • SQL 로 snapshot part 만 조회: 세션을 읽지 않고 step part(최대 169바이트)만 크기로 먼저 거른 뒤 해석하면, 1955 팀 세션(209MB)에서 30ms, 0.75MB 로 결과가 완전히 같습니다. 다만 upstream 과 다른 우리만의 코드가 되어, upstream 코드를 그대로 가져오는 쪽을 택했습니다.
  • 이 방식의 차이: 새 질문 메시지에 summary: { diffs: [] } 를 쓰지 않습니다. 이 값을 읽는 곳(웹 session.tsx, UI message-nav.tsx·session-turn.tsx, 서버 diff API)은 모두 summary?.diffs ?? [] 로 처리하고, rails·어드민·vite·user-rails 는 읽지 않아 화면과 동작은 같습니다.

검증

  • 새 테스트 test/session/summary.test.ts 3개
    • snapshot 이 꺼져 있으면 Session.messages 를 부르지 않고 빈 요약과 빈 diff 이벤트만 남김
    • snapshot 이 켜져 있으면 질문 메시지에 턴 diff 를 남김
    • 세션 전체 diff 는 빈 목록, 턴 diff 는 저장된 값을 경로를 풀어 돌려줌
    • 예전 코드로 돌리면 1·3번이 실패하는 것을 확인했습니다.
  • test/session, test/server, test/share 369 pass, typecheck 통과
10월 OOM 팀 DB 실측 (로컬 Docker Linux, bun 1.4.4)

운영 어드민에서 받은 10월 OOM 팀 4곳의 DB 사본(현재 저장 형식), 팀별 가장 큰 메인 세션의 마지막 질문으로 SessionSummary.summarize 를 5번(스텝 5번) 호출했습니다. 설정은 파드와 같은 방식(OPENCODE_CONFIG_DIR)으로 snapshot: false 만 넣었고, 예전 코드는 main 입니다. 추가 메모리는 프로세스 기본(약 225MB)을 뺀 VmHWM 피크의 3회 중앙값입니다.

팀 예전 추가 메모리 새 코드 추가 메모리 호출당 시간(예전 → 새)
1821 +288MB +5MB 48~58ms → 5ms
1834 +641MB +5MB 216~272ms → 5ms
1955 +948MB +5MB 251~318ms → 5ms
1957 +230MB +5MB 55~75ms → 5ms

세션 요약 값(추가·삭제 0, 파일 0)은 두 코드가 같습니다. 1955 팀은 해커톤 동안 이 호출이 약 4,400번 있었습니다.

dev 실측: 같은 세션으로 기준(A1+A3) 이미지와 A2 이미지 비교 (2026-11-10)

팀 266 세션(메시지 약 140개)의 오래된 도구 part 20개에 8MB 씩 metadata.diff(약 160MB)를 넣고 그 뒤 도구 결과 하나에 정리 표시를 해 실제 긴 세션처럼 만들었습니다. 화면을 닫고 API 로 같은 요청을 보냈습니다. 파드 /config 응답에서 snapshot: false 가 적용된 것을 확인했습니다.

이미지 턴 OOMKilled RSS 샘플 최대(15초)
기준 2026-11-10T17-20-14 (A1, A3) 4 2회 (스텝 중 1, 그 뒤 재시작 반복으로 파드가 내려감) 1,722MB
A2 2026-11-10T21-08-25 5 0회 1,559MB
  • 매 스텝 session.diff 이벤트와 버전 기록 저장(history … saved)은 매 턴 정상이었고, 참가자 화면도 정상으로 열렸습니다.
  • OOM 은 사라졌지만 턴 중 피크는 여전히 1.2~1.6GB 입니다. 남은 원인은 매 스텝 요청을 만들 때 마지막 압축 이후를 모두 읽는 경로입니다(이 테스트 세션은 압축된 적이 없어 사실상 전체). 다음 작업 대상입니다.
  • 측정 후 세션 데이터는 원래대로 되돌렸습니다.

🤖 Generated with Claude Code

@ksy90101
ksy90101 marked this pull request as ready for review November 10, 2026 13:03
@ksy90101
ksy90101 merged commit 706eca7 into main Nov 10, 2026
5 checks passed
@ksy90101
ksy90101 deleted the perf/summary-no-full-load branch November 10, 2026 13:03
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.

1 participant