Skip to content

[Feat] run 명시적 취소·CANCELED 확정·상태별 사용량과 반복 요청 제한 검증 [1.84] - #239

Merged
chowon442 merged 4 commits into
feat/s07-run-coordinationfrom
worktree-task-1.84
Oct 18, 2026
Merged

chowon442 merged 4 commits into
feat/s07-run-coordinationfrom
worktree-task-1.84

Conversation

@chowon442

@chowon442 chowon442 commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

📌 관련 이슈

🏷️ PR 타입

  • ✨ 기능 추가 (Feature)
  • 🐛 버그 수정 (Bug Fix)
  • ♻️ 리팩토링 (Refactoring)
  • 📝 문서 수정 (Documentation)
  • 🎨 스타일 변경 (Style)
  • ✅ 테스트 추가 (Test)

📝 작업 내용

  • POST /api/ai-runs/{runId}/cancel — 1.86 BrowserRunController 확장 지점에 추가. 판정 순서 = browser-run-v1 cancel/cases.json (401 → body 있음 RUN4001(run 조회 전) → 접근 RUN4041 → 상태). 응답 ApiResponse<RunCancelResult>.
  • RunCancelStore (Note FOR SHARE → run FOR UPDATE, 1.82 잠금 순서):
    • PENDING: 조건부 PENDING∧attempt=0 → CANCELED + message CANCELED + run.canceled + 1.77 보상(PENDING_CANCELED) 한 transaction. Brain 미호출. claim(SKIP LOCKED)과 하나만 이김.
    • RUNNING/RETRYING: 현재 attempt·fence 조건 → CANCELING(+run.canceling, grant 폐기, lease 유지).
    • CANCELING → already_canceling, terminal → already_terminal (멱등).
  • RunCancelFinalizer (내부 executor, bean 아님): 취소 직후 + sweep-interval마다 CANCELING run에 Brain cancel(멱등) → ack state terminal이면 확정, absent는 run lease 만료·로컬 미실행일 때만 확정, 그 밖은 cleanup-timeout(기본 2m) 뒤 안전 확정. 확정 = CANCELING → CANCELED + message + run.canceled + usage settle(사용자 취소는 차감 유지) → RunClaimStore.reserveRuntimeCleanup → RunCoordinator.release.
    • 확정 전까지 전역 슬롯·Note Active Run 자리 유지(coordinator heartbeat에 의존하지 않음). 재시작·다른 인스턴스는 DB sweep로 이어받음.
  • 반복 요청 제한: 1.79 RUN4291 재사용(중복 구현 없음), 성질을 DB 테스트로 고정. task 84 대비 차이는 아래 참고.
  • coordinator 패키지·RunTerminalService·schema 변경 없음(migration 추가 없음 — V5는 1.85 recovery_count, 1.85 merge 반영 후 충돌 없음). application.yaml 변경 없음(proovy.run.cancel.*는 @DefaultValue).
  • 문서: docs/contracts/run-cancel.md.

📸 스크린샷

로컬(eclipse-temurin:21-jdk 컨테이너, 격리 Postgres :24432):

  • --tests 'com.proovy.domain.run.cancel.*' — RunCancelPostgresTest 13/13, RunCancelCoordinatorPostgresTest 1/1 통과
  • 회귀: BrowserRunSsePostgresTest 14, RunCoordinatorPostgresTest 15, run.contract.* 37 — 실패 0
  • 1.85 merge(0cc79e3) 반영 뒤 재실행: cancel 14 + RunCoordinatorPostgresTest 15 + RunRecoveryPostgresTest 12 — 실패 0
  • 전체 테스트는 CI 결과로 확인

✅ 체크리스트

  • 코드 리뷰를 받을 준비가 완료되었습니다
  • 테스트를 작성하고 모두 통과했습니다
  • 문서를 업데이트했습니다 (필요한 경우)
  • 코드 스타일 가이드를 준수했습니다
  • 셀프 리뷰를 완료했습니다

📎 기타 참고사항

후속 계약 메모

  • 1.87: 경로 POST /api/ai-runs/{runId}/cancel(body 없음). 실제 Brain cancel 왕복·wind-down 실측과 cleanup-timeout 확인.
  • 1.85: CANCELING run(lease 만료 포함)은 이 경로 소유. 합의대로 1.85는 RUNNING|RETRYING만.
  • S13: asset_deleting 취소는 RunCancelStore.cancelPending/markCanceling(cause) 재사용 가능. Brain runtime cleanup 호출은 S13.
  • 운영 확정 수치(S14): proovy.run.cancel.cleanup-timeout 2m · sweep-interval 2s, 1.79 rate limit 20건/1분.

반복 요청 제한 — 후속 태스크(S14 수치와 함께) (사용자 결정)

이 PR 범위는 1.79 RUN4291 재사용(20건/1분)뿐이다. 새 requestId·취소/실패/clarification으로 순사용량 0이 된 run도 세고(우회 불가), replay는 세지 않고, 다른 사용자에 영향이 없다(테스트로 고정). task 84 문구 대비 남은 차이는 후속 태스크로 미룬다:

  1. 반복 실패/clarification 남용을 "구분"하는 별도 제한·무료 결과 누적 상한이 없다(20/분 안에서는 무료 실행 계속 가능).
  2. 보완 요청 구별이 없다(같은 창으로 셈 — 더 엄격한 제한이 없어 부당하게 막히지도 않음).
  3. 제안: 보상된 run을 browser fingerprint(run_request_bindings) 기준으로 세는 추가 상한(같은 입력 반복만 제한, 보완 요청은 fingerprint가 달라 제외, code는 RUN4291). 창·건수는 S14에서 기존 수치와 함께 확정.

1.85 결정표 중 1.84 소유 항목 (docs/contracts/run-cancel.md "1.85 회수 결정표 중 1.84 소유 항목")

  • FINAL_CANCEL_PENDING(Brain canceling ↔ Server RUNNING|RETRYING): 1.84 흐름에서는 발생하지 않음 — Brain cancel은 RunCancelFinalizer만 부르고 대상은 CANCELING commit 뒤의 status='CANCELING' 행뿐, CANCELING→RUNNING 전이 없음. 보이면 Server 밖 cancel 신호이고 deadline sweep이 끝냄. 코드 변경 없음.
  • FINAL_CHECK·재전달 소진 실패 직전 Brain cancel: 이 PR에서 하지 않음 — 실패 지점이 coordinator 패키지(수정 금지)이고 internal-run-v1 CancelCause에 Server 실패 값이 없어 계약 추가가 먼저. 후속(S13): 실패 직전 best-effort BrainRunClient.cancel 후 응답과 무관하게 failByServer.

🤖 Generated with Claude Code

…meout 뒤 CANCELED, 반복 요청 제한 검증 (#224)

- POST /api/ai-runs/{runId}/cancel (cancel/cases.json 판정 순서: body RUN4001 → 접근 RUN4041 → 상태)
- RunCancelStore: Note → run 잠금, 조건부 PENDING→CANCELED(+보상)·RUNNING|RETRYING→CANCELING(+run.canceling)
- RunCancelFinalizer: Brain cancel ack state로 정리 확인, absent는 lease 만료 뒤, cleanup-timeout 안전 확정,
  reserveRuntimeCleanup·RunCoordinator.release (coordinator 패키지 미수정, schema 변경 없음)
- 실제 Postgres·HTTP·BrainRunClient·coordinator 테스트, docs/contracts/run-cancel.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chowon442 and others added 3 commits October 19, 2026 06:10
…복 요청 추가 상한 후속 태스크 명시 (#224)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…패 행 backoff, timeout 경과 시 Brain 미호출·남은 시간 상한, DB 시각 timeout, stop 시 inFlight 정리 (#224)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chowon442
chowon442 merged commit 6125b9a into feat/s07-run-coordination Oct 18, 2026
1 check passed
@chowon442
chowon442 deleted the worktree-task-1.84 branch October 19, 2026 16:00
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