Files
DongHyeonka d646c2f12f feat(messaging): 브로커 중립 메시징 플랫폼 24개 leaf 추가
messaging-superpowers-package 설계서/계획서 기반 구현.
registry를 19 → 43 leaf로 확장하고 src/messaging 아래 24개 leaf를 등록.

- core-api: M1 publish/consume + M2 batch·delayed·pause-resume
- policy/transport-spi: 재시도 결정, DLQ orchestration, admission control, lifecycle
- kafka·rabbit(Stable): contiguous commit, confirm/return 상관, 배치, 보안 설정
- pulsar·nats(Experimental): 기본 비활성, live 인증 없음을 코드로 기록
- outbox/inbox/claim-check: 트랜잭션 결합, lease, 무결성 검증
- admin: plan → approve → execute를 타입으로 강제
- 문서 9종, infra compose 7종, JMH 벤치마크 3종

검증: 아키텍처 게이트 3종 통과, 24개 leaf 전부 check 통과,
messaging 테스트 604개 통과/0 실패.

미완: 계획서가 요구한 실 브로커 IT 40개 중 7개만 작성.
Rabbit 13 / Outbox 6 / Inbox 4 / NATS·Pulsar·Share 5 / testkit 2 /
starter·admin 3, 그리고 TLS·ACL 2개가 남음.
2026-08-14 14:55:38 +09:00

98 lines
3.7 KiB
Markdown

# Experimental 정책
## Stable과 Experimental의 차이
**Stable**은 공통 Contract Suite(`MessagingAdapterContract`)를 변경 없이 통과한 어댑터다.
컴파일되는 어댑터가 아니라, 아래 7가지를 실제로 증명한 어댑터다.
```text
publishesAndConfirms
returnsAmbiguousWhenConfirmIsLost
redeliversWhenSettlementIsLost
preservesMessageIdAcrossRetryAndDlq
keepsSourceUnsettledWhenDlqPublishFails
rejectsOversizedPayloadBeforeTransport
stopsAcceptingNewWorkDuringShutdown
```
**Experimental**은 아직 그 증명이 끝나지 않은 어댑터다.
## 규칙
### 1. 기본 비활성
```yaml
messaging.experimental.kafka-share: false
messaging.experimental.pulsar: false
messaging.experimental.nats: false
```
활성화하지 않으면 validator가 `MessagingCapabilityUnavailableException`을 던진다.
Contract Suite가 아직 증명 중인 어댑터가 누군가의 기본 설정 때문에 load-bearing이 되어서는 안 된다.
### 2. Stable 모듈이 Experimental 모듈에 의존하지 않는다
Gradle 의존 그래프로 강제된다. `messaging-spring-boot-starter``allowed_dependencies`
`messaging-kafka-share-experimental`, `messaging-pulsar-experimental`,
`messaging-nats-experimental`, `messaging-spring-cloud-stream-bridge`**없다**.
`verifyCleanArchitectureDependencies`가 위반을 빌드 실패로 만든다.
### 3. Core 계약을 바꾸지 않는다
Experimental 어댑터는 브로커의 차이를 `MessagingCapabilities`로 표현할 뿐,
`messaging-core-api`의 타입을 바꾸지 않는다.
### 4. 없는 기능을 광고하지 않는다
| 어댑터 | 광고하지 않는 것 | 이유 |
|---|---|---|
| Kafka Share Group | orderedStream, keyedOrdering, replay, brokerTransaction | 경쟁 소비자 + 개별 ack는 partition 순서를 유지할 수 없다 |
| Pulsar | brokerTransaction | Pulsar에 있지만 플랫폼 Contract Suite로 증명되지 않았다 |
| Pulsar (Shared) | keyedOrdering | round-robin 분배 |
| NATS JetStream | nativeDeadLetter | delivery limit 초과 시 terminate할 뿐 라우팅하지 않는다 |
| NATS JetStream | keyedOrdering | subject 기반 모델에 per-key 순서가 없다 |
`false`인 capability를 요구하는 profile은 startup에서 실패한다.
조용히 약화되지 않는다.
### 5. 명시적 거부
| 조합 | 결과 |
|---|---|
| Kafka Share Group + ordering != NONE | 거부 |
| Kafka Share Group + pause/resume | `MessagingCapabilityUnavailableException` |
| Pulsar Shared + ordering=KEY | 거부 (Key_Shared 필요) |
| Pulsar + ordering=DESTINATION | 거부 |
| NATS Core + AT_LEAST_ONCE | 거부 (JetStream 필요) |
| NATS ordered consumer + 경쟁 워커 > 1 | 거부 |
| NATS + ordering=KEY | 거부 |
## Spring Cloud Stream bridge
Experimental이 아니라 **Optional**이다. 위험이 다르다.
Stream은 자체 binder 설정을 소유하므로, binding이 destination profile이 모르는
serializer·error handling·acknowledgement mode를 조용히 획득할 수 있다.
따라서 브리지는 **플랫폼 보장에 의존하지 않는 destination에만** 허용한다.
```text
ordering scope 선언 → 거부
retry policy 선언 → 거부
dead letter 선언 → 거부
```
이 셋 중 하나라도 필요하면 native adapter를 쓴다. 거기서만 실제로 강제되기 때문이다.
## 승격 조건
Experimental → Stable로 올리려면 전부 필요하다.
1. `MessagingAdapterContract` 7개 테스트를 변경 없이 통과
2. 장애 주입(연결 끊김, confirm 유실, settlement 유실) 하에서 통과
3. 지원 브로커 버전 범위 명시 및 CI 검증
4. `support-matrix.md`의 capability 표 갱신
5. ADR 작성
6. 기본 활성화 여부에 대한 별도 결정