Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/delivery-and-settlement-models/concept/concept-messaging-runtime-core-c03.md
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

4.5 KiB
Raw Blame History

kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source, module
kind slug title topic project status sourceRevision rootTreeNode evidenceCapturedOn assets evidence source module
CONCEPT messaging-runtime-core-c03 바이트가 프로세스를 떠났는가가 REJECTED와 AMBIGUOUS를 가른다 delivery-and-settlement-models clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 concept:messaging-runtime-core-c03 2026-09-01
key file
messaging-runtime-core-c03 ../../../final/evidence/rendered/messaging-runtime-core-c03.svg
key file
messaging-runtime-core-c03-diagram ../../../final/assets/diagrams/messaging-runtime-core-c03.svg
../../../final/evidence/raw/messaging-runtime-core-c03.txt
원본 분석 절은 analysis/messaging/messaging-runtime-core.md#L128 이다.
messaging-runtime-core

바이트가 프로세스를 떠났는가가 REJECTED와 AMBIGUOUS를 가른다

실제 순서 여덟 단계: 1–7은 전부 REJECTED, 8만 AMBIGUOUS다. 그 경계가 정확히 "바이트가 프로세스를 떠났는가"다.

관계

  • 만들어 두고 흘리지 않는 진단값은 진단이 아니다 같은 분석 리프에서 끌어낸 규칙이다.
  • 증가한다고 문서화한 값이 리터럴이면 그 사실을 적는다 같은 분석 리프에서 끌어낸 규칙이다.
  • 안정 코드는 운영자의 행동이 갈리는 지점마다 나눈다 같은 분석 리프에서 끌어낸 규칙이다.
  • CompletionStage를 반환하는 메서드는 동기적으로 던지지 않는다 같은 분석 리프에서 끌어낸 규칙이다.

본문

순서가 인터셉터 map에서 조립되지 않고 고정돼 있으며, javadoc이 각 단계의 위치를 결정으로 적는다 — 목적지와 접근이 먼저라 인가되지 않은 발행이 payload를 인코딩하지 않고, 인코딩이 admission보다 먼저인 것은 admission 경계가 바이트에 걸려 있어 인코딩 전에는 바이트 수를 모르기 때문이며, 런타임 lease가 전송 직전 마지막인 것은 이미 in-flight 한도에 계상된 메시지 밑에서 rotation이 transport를 바꾸지 못하게 하기 위해서다.

발행 단계가 고정된 순서

:::evidence key="messaging-runtime-core-c03-diagram" alt="목적지와 접근에서 인코딩으로 이름 확인이 건너가고 인코딩에서 admission 으로 바이트 수가 건너가고 admission 에서 브로커 전송으로 permit 이 건너간다" caption="발행 단계가 고정된 순서" zoom="false" :::

여덟 단계 중 여덟만 AMBIGUOUS다

17은 전부 REJECTED, 8만 AMBIGUOUS다. 그 경계가 정확히 "바이트가 프로세스를 떠났는가"다. messaging-core-api의 3상태(§4.1)가 여기서 실제 분기가 된다. 그리고 rejected(...)가 만드는 PublishResultPublishEvidence.notTransmitted()를 쓰므로 PublishResult 생성자의 14가지 금지 조합 검증을 자연히 통과한다.

PublishResult 참조 위치

:::evidence key="messaging-runtime-core-c03" alt="코드베이스에서 PublishResult 를 검색한 출력 25줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="PublishResult 코드베이스 검색 — 25줄 · exit 0" zoom="true" :::

이미 기다리기를 그만둔 메시지를 보내지 않는다

remainingBudgettimeout - elapsedSince(startedAt)이고, 0 이하면 전송 전에 REJECTED로 끝낸다 — "Sending anyway would start a message the caller has already stopped waiting for."

copy 에 타임아웃을 거는 이유

orTimeout을 원본에 걸면 만료가 어댑터의 stage를 완료시켜 어댑터의 자기 정리가 깨진다. 복사본에 걸면 만료는 이쪽 경로만 끝내고 어댑터는 자기 in-flight를 계속 소유한다. 그 대가도 명시돼 있다 — permit과 lease는 복사본이 완료될 때 반납되므로, 브로커가 나중에 응답해도 이미 반납된 상태다. 그것이 의도다("holding them until a stalled broker answers is how a rotation waits forever").

두 경우를 한 블록에서 처리한다

handlewhenComplete와 달리 실패를 삼키고 값을 반환한다. lease.close()MessagingRuntimeLease 계약상 멱등이고(transport-spi §4.1), admission.complete도 미보유 목적지에 대해 무해하다(messaging-policy §4.3).

한 가지 비대칭

6번(admit)이 예외를 던지면 그 예외가 그대로 호출자에게 전파된다 — try 블록 밖이다. 다른 모든 실패는 PublishResult로 정규화되는데 admission 실패만 예외다.