Skip to content

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 08:24
· 66 commits to main since this release

Both sides of integration events: declared consumers join the publishing side, and the trace follows an event from the request that caused it to the handler that processes it. ddk-mall, a reference application with three bounded contexts, uses every starter side by side; building it surfaced the fixes below.

Added

  • ddk-examples/ddk-mall: a reference application with order, inventory and payment contexts in one modular monolith. It has the order context (an aggregate with a child table, Flyway migrations, audit fields), the inventory context (reservations under per-SKU locks), their integration through the outbox and RocketMQ with idempotent consumers, and the payment context (a simulated channel, refunds when a payment crosses a cancellation) with a scheduled job that closes unpaid orders, and a read side with cached products and stock, API docs grouped by context MCP tools for a support agent, and traces and metrics exported over OTLP to a one-container observability backend, tested end to end on MySQL, Redis and RocketMQ containers
  • Consuming integration events in ddk-event-starter: declare an IntegrationEventConsumer bean and DDK subscribes to RocketMQ (orderly by default), decodes the payload, exposes the contract headers as ReceivedEvent and can deduplicate through the inbox. ddk.event.local-delivery.enabled delivers in-process for development, and IntegrationEventDispatcher lets listeners of other brokers reuse the same handling
  • Integration events carry the trace: ddk-event-starter observes publishing and consuming (ddk.event.publish, ddk.event.consume), writes the trace context into the message headers and continues from it on the consuming side, over RocketMQ and local delivery alike. ddk-tracer-starter registers a ContextPropagatingTaskDecorator (ddk.tracer.async-propagation.enabled) so the trace reaches @Async methods and the post-commit event delivery
  • AggregateLocks.executeAll(type, ids, action) locks several aggregates of one type in a fixed order, so two operations that need the same aggregates cannot deadlock on each other
  • GenericRepositoryImpl has extension points for aggregates stored in a root table plus child tables: afterInsert, afterUpdate, afterLoad and beforeRemove run around the root table's reads and writes in the same transaction

Fixed

  • Numbers in error messages were written with grouping separators: an order ID 1234567 in 订单不存在:{0} came out as 1,234,567, which nobody can search for. ErrorCode.getMessage(args) now writes numbers as they are; a placeholder with an explicit format such as {0,number,#,##0.00} is still honoured
  • Trace export failed at runtime (NoSuchMethodError: okio.Okio.socket) in applications that use RocketMQ and the tracer starter together: rocketmq-client brings an old okio that Maven preferred over the one the OpenTelemetry exporter's OkHttp needs. The BOM now manages okio to the version OkHttp 5 requires
  • The Redis starter failed the application at startup when no RedisConnectionFactory existed, for example with Spring Boot's Redis auto-configuration excluded for a local profile. This also defeated the cache starter's local-only fallback. The redisTemplate bean is now created lazily, so the application starts and only using the template without a connection fails
  • The event starter's documentation claimed that events with the same key keep their order. A key only puts them in the same partition or queue; delivery after commit is concurrent by default and can send them out of order. The README now explains this and how to get ordered delivery