feat(mq): add kafka adapter and broker-neutral contract suite

Phase 2 of the mq abstraction design: the acceptance bar (TCK) plus the
kafka adapter, both passing the full contract suite against live brokers.

dc3-common-mq-tck (contract suite, reusable by community adapters):
- abstract 12-case suite covering round-trip envelope fidelity, load
  balance exactly-once across instances, broadcast fan-out, delay via the
  port fallback, reject-to-dead-letter, reject-with-requeue redelivery,
  sendAsync confirmation, 100-message burst, batch ack committing the
  whole batch, retry exhaustion dead-lettering instead of dropping,
  durability while no consumer runs, and per-instance subscription expiry
- rabbitmq and kafka harnesses on testcontainers 2.x, skipped gracefully
  without a container runtime; kafka harness also honors TCK_KAFKA_BOOTSTRAP
  for externally managed brokers (testcontainers 2.0.5 configures
  apache/kafka 3.9.0 with a nonroutable advertised listener on some runtimes)
- per-run unique consumer groups plus post-subscription settle keep runs
  isolated on log-based brokers with auto.offset.reset=latest

dc3-common-mq-kafka (adapter, dc3.mq.type=kafka):
- topics map to dc3.<topic>; logical dead topics map to dc3.<topic>.dlq so
  rejects and dead-letter subscriptions land on the same topic
- partition key becomes the record key (per-key ordering); LOAD_BALANCE
  rides consumer groups, BROADCAST uses per-instance group ids
- auto.offset.reset=latest mirrors the rabbit fresh-queue semantics: a new
  group only sees messages published after it joins
- batch delivery with synchronous bounded retry and backoff mirroring the
  rabbit stateless retry advice; exhaustion republishes the whole batch to
  the dead-letter topic and commits instead of dropping silently (spring's
  DefaultErrorHandler committed exhausted batches without publishing)
- non-poison failures on single deliveries nack for redelivery; poison
  messages are republished to the dead-letter topic and acknowledged

rabbit adapter adjustments surfaced by the suite: delayedMessage capability
is now false (only the intrinsic TTL+DLX topics delay server-side; arbitrary
delays go through the port fallback), POINT_VALUE_DEAD is subscribable for
dead-letter auditing, spec instanceTtl overrides the configured queue
expiry, subscriptions with a named group get a group-suffixed copy of the
platform-shared queue (blank group keeps the pre-port names), and shared
topology moved to a descriptor table

Verified: RabbitMQ 12/12 and Kafka 11+1-skipped against live brokers via
podman; constant/data/driver/manager unit suites unchanged and green.
This commit is contained in:
pnoker
2026-08-19 20:52:27 +08:00
parent 28efa5c8fc
commit b8aee2cf69
12 changed files with 1306 additions and 114 deletions
+10
View File
@@ -766,6 +766,16 @@
<artifactId>dc3-common-mq-rabbitmq</artifactId>
<version>${dc3.version}</version>
</dependency>
<dependency>
<groupId>io.github.pnoker</groupId>
<artifactId>dc3-common-mq-kafka</artifactId>
<version>${dc3.version}</version>
</dependency>
<dependency>
<groupId>io.github.pnoker</groupId>
<artifactId>dc3-common-mq-tck</artifactId>
<version>${dc3.version}</version>
</dependency>
<dependency>
<groupId>io.github.pnoker</groupId>
<artifactId>dc3-common-repository</artifactId>