Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/runtime-reachability-and-composition/case/case-messaging-outbox-jdbc-postgresql-f01.md
T
DongHyeonkaandClaude Fable 5.1 b25357c48a docs(clean-architecture-backend-template): fold analysis into final and re-select one topic
- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다
- 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5
  (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를
  techviz 로 만들었다
- 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs
  돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다.
  Concept 이 인용한 코드가 SSOT 에 없어 뺐다
- candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 12:39:20 +09:00

5.3 KiB

kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source, module, priority
kind slug title topic project status sourceRevision rootTreeNode evidenceCapturedOn assets evidence source module priority
CASE messaging-outbox-jdbc-postgresql-f01 정리 작업이 무제한 DELETE 를 쏘고, 그것을 막는 오버로드는 호출되지 않는다 runtime-reachability-and-composition clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 case:messaging-outbox-jdbc-postgresql-f01 2026-09-01
key file
messaging-outbox-jdbc-postgresql-f01 ../../../final/evidence/rendered/messaging-outbox-jdbc-postgresql-f01.svg
key file
messaging-outbox-jdbc-postgresql-f01-diagram ../../../final/assets/diagrams/messaging-outbox-jdbc-postgresql-f01.svg
../../../final/evidence/raw/messaging-outbox-jdbc-postgresql-f01.txt
원본 분석 절은 final/document.md#a19-messaging-outbox-jdbc-postgresql#L876 이다.
messaging-outbox-jdbc-postgresql P1

정리 작업이 무제한 DELETE 를 쏘고, 그것을 막는 오버로드는 호출되지 않는다

OutboxCleanupJob:50 과 InboxCleanupJob:56 이 무제한 오버로드를 부른다. bounded 오버로드(purgePublishedBefore(Instant, int) / purgeProcessedBefore(Instant, int))는 두 포트에 선언되고 두 구현에 구현되어 있으며 호출부가 0건이다(EVD-294, EVD-311).

문제

OutboxCleanupJob:50 과 InboxCleanupJob:56 이 무제한 오버로드를 부른다.

bounded 오버로드(purgePublishedBefore(Instant, int) / purgeProcessedBefore(Instant, int))는 두 포트에 선언되고 두 구현에 구현되어 있으며 호출부가 0건이다(EVD-294, EVD-311).

결론

두 잡 모두 starter 빈이지만 스케줄러는 등록되지 않으며, 그것은 의도된 설계다(EVD-316).

즉 기본 배포에서는 아무 일도 일어나지 않고, 애플리케이션이 문서 지시대로 잡을 스케줄하는 순간 무제한 DELETE 가 발동한다.

잠재 결함이지 상시 결함이 아니다.

bounded 구현의 주석이 결과를 명시한다: "An unbounded DELETE holds locks and writes WAL in proportion to the whole backlog, which stalls the relay and the business writes behind retention." 3일치 백로그가 쌓인 테이블에서 이것은 릴레이 정지와 비즈니스 쓰기 정체를 뜻한다.

두 리프 모두 runtime_memberships: ["app-bootstrap"] 이고 두 잡 모두 starter 빈이다.

수정은 한 줄이다 — purgePublishedBefore(cutoff, batchLimit).

maxBatches 가 그제서야 의미를 갖는다.

배치 크기는 새 파라미터가 필요하고, OutboxProperties.batchSize(100)를 재사용하거나 별도 값을 둔다.

검증 환경

OpenJDK : 21.0.12 java -version 으로 확인 Gradle : 9.0.0 src/gradle/wrapper/gradle-wrapper.properties 의 distributionUrl 로 확인 확인 방식 : OutboxProperties 참조 28건 검색과 두 오버로드의 SQL·호출자·starter 배선 대조 소스 수정 : x

재현 조건

원문은 final/document.md#a19-messaging-outbox-jdbc-postgresql#L876 에 있다.

본문

OutboxCleanupJob:50InboxCleanupJob:56 이 무제한 오버로드를 부른다. bounded 오버로드(purgePublishedBefore(Instant, int) / purgeProcessedBefore(Instant, int))는 두 포트에 선언되고 두 구현에 구현되어 있으며 호출부가 0건이다(EVD-294, EVD-311).

두 형태의 락 구간

:::evidence key="messaging-outbox-jdbc-postgresql-f01-diagram" alt="호출되는 오버로드 쪽에 무제한 DELETE 와 전체 백로그 락이 빗금으로 놓이고 호출되지 않는 오버로드 쪽에 LIMIT 배치와 배치 단위 락이 놓인다" caption="두 형태의 락 구간" zoom="false" :::

OutboxProperties 참조 위치

:::evidence key="messaging-outbox-jdbc-postgresql-f01" alt="코드베이스에서 OutboxProperties 를 검색한 출력 28줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="OutboxProperties 코드베이스 검색 — 28줄 · exit 0" zoom="true" :::

잠재 결함이지 상시 결함이 아니다

두 잡 모두 starter 빈이지만 스케줄러는 등록되지 않으며, 그것은 의도된 설계다(EVD-316). 즉 기본 배포에서는 아무 일도 일어나지 않고, 애플리케이션이 문서 지시대로 잡을 스케줄하는 순간 무제한 DELETE 가 발동한다.

bounded 구현의 주석이 결과를 명시한다

"An unbounded DELETE holds locks and writes WAL in proportion to the whole backlog, which stalls the relay and the business writes behind retention." 3일치 백로그가 쌓인 테이블에서 이것은 릴레이 정지와 비즈니스 쓰기 정체를 뜻한다. 두 리프 모두 runtime_memberships: ["app-bootstrap"] 이다.

수정은 한 줄이고 대역도 함께 고쳐야 한다

purgePublishedBefore(cutoff, batchLimit) 로 바꾸면 maxBatches 가 그제서야 의미를 갖는다. 배치 크기는 OutboxProperties.batchSize(100)를 재사용하거나 별도 값을 둔다. 그리고 회귀 테스트가 성립하려면 RecordingRepository 를 고쳐야 한다 — 현재 대역의 bounded 구현은 Math.min(unbounded(), limit) 로 전부 지우고 숫자만 깎는다.

확인하지 못한 것

백로그가 쌓인 실제 테이블에서 무제한 DELETE 의 락 보유 시간을 측정하지 않았다. 두 SQL 과 호출부 부재로 도출했다.