--- kind: CONCEPT slug: messaging-transport-spi-c04 title: 선언된 종료 순서와 실제 종료 경로 topic: state-machines-and-ownership project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: concept:messaging-transport-spi-c04 evidenceCapturedOn: 2026-09-01 assets: - key: messaging-transport-spi-c04 file: ../../../final/evidence/rendered/messaging-transport-spi-c04.svg evidence: - ../../../final/evidence/raw/messaging-transport-spi-c04.txt source: - 원본 분석 절은 final/document.md#a19-messaging-transport-spi#L326 이다. module: messaging-transport-spi --- # 선언된 종료 순서와 실제 종료 경로 발행·수신·회전·종료 네 경로가 있고, 종료는 실제 경로가 따로 있다. ## 관계 - **멱등 종료를 보장하는 컴포넌트는 종료 이후의 등록도 정의한다** 같은 분석 리프에서 끌어낸 규칙이다. - **같은 개념의 sentinel은 계층을 넘어 하나로 정한다** 같은 분석 리프에서 끌어낸 규칙이다. ## 본문 **발행** — 상위(`DefaultMessagePublisher`)가 `TransportPublishRequest`를 만들어 `MessagingTransport.publish` → 어댑터가 `TransportPublishResult(PublishResult)` 반환. **수신** — 상위가 `TransportConsumerSpec(profile, sink)`로 `register` → 어댑터가 메시지마다 `sink.apply(TransportDelivery)` → 상위가 `TransportSettlement`으로 정산. ## DefaultMessagePublisher 참조 위치 :::evidence key="messaging-transport-spi-c04" alt="코드베이스에서 DefaultMessagePublisher 를 검색한 출력 22줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="DefaultMessagePublisher 코드베이스 검색 — 22줄 · exit 0" zoom="true" ::: ## 회전과 실제 종료 경로 **회전** — 새 `MessagingRuntime` 생성 → `registry.install(runtime, now)` → 옛 세대 `retire` → lease가 0이면 즉시 close, 아니면 `draining`에 적재 → 스케줄러가 `closeExpiredDraining(now)` 호출. **종료(실제 경로)** — `MessagingShutdownLifecycle.stop()` → `admission.stopAcceptingNewWork()` → `drain.beginDrain(now)` → 50 ms 폴링으로 `isDrained` 대기 → 마감 도달 시 중단.