Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Release 0.40.23 Spring Boot 3.2.*

Pre-release
Pre-release

Choose a tag to compare

@cloudcreate-dk cloudcreate-dk released this 10 Apr 20:30
· 13 commits to main since this release
6af9380

What's Changed

🚀 Release Highlights – v0.40.23

This release brings major improvements across observability, error handling, configuration, MongoDB integration, and internal architecture — now grouped for clarity.


🏢 Project Metadata

This will soon become the new home for the project


🧠 metrics

  • Introduced the MeasurementTaker API for pluggable performance tracking
    • Includes LoggingMeasurementRecorder and MicrometerMeasurementRecorder
  • Added support for per-subsystem execution time thresholds via configuration
  • Introduced:
    • RecordExecutionTimeCommandBusInterceptor
    • RecordExecutionTimeDurableQueueInterceptor
    • RecordExecutionTimeMessageHandlerInterceptor
    • RecordExecutionTimeEventStoreInterceptor
  • Logging can be configured for each interceptor with class-specific logger names
  • Most new properties to control metrics collection under essentials.metrics.*, others are under essentials.eventstore

📦 durable-queues

  • Introduced DurableQueueDeserializationException
  • DefaultDurableQueueConsumer:
    • Immediately marks failed deserialization messages as Dead-Letter-Messages
    • Supports new HandleQueuedMessage interceptor operation
  • Updated:
    • PostgresqlDurableQueues.getNextMessageReadyForDelivery
    • MongoDurableQueues.getNextMessageReadyForDelivery
  • Added RecordExecutionTimeDurableQueueInterceptor
  • Expanded DurableQueuesIT to test dead-letter behavior on deserialization failure

🧰 eventstore-postgresql

  • Introduced EventStoreSubscriptionObserver interface
  • Added MeasurementEventStoreSubscriptionObserver for tracking EventStoreSubscription delivery duration
  • DefaultEventStoreSubscriptionManager now uses MeasurementEventStoreSubscriptionObserver by default
  • Added:
    • RecordExecutionTimeEventStoreInterceptor for performance tracking
  • Improved:
    • Logging and exception description for OptimisticAppendToStreamException and AppendToStreamException
    • PollEventStoreTask poll logic to adapt to publishing activity
    • Handling of resolveBatchSizeForThisQuery edge case

🧱 eventsourced-aggregates

  • Improved logging in DefaultStatefulAggregateRepository
    • Changed default log level from TRACE to DEBUG

🔐 Mongo fenced-locking

  • Improved MongoFencedLockStorage handling of TransactionException and WriteConflict scenarios
  • Introduced MongoUtil.isWriteConflict and reused it across:
    • MongoFencedLockStorage
    • MongoDurableQueues
  • Adjusted DBFencedLockManagerIT for improved reliability under concurrency and connectivity issues
    • Improved reconnection timing logic for stability

🛠 unit-of-work

  • UnitOfWorkFactory and UnitOfWorkLifecycleCallback now use Throwable instead of Exception for broader rollback coverage
  • Unified error handling logic:
    • UnitOfWorkFactory.usingUnitOfWork now aligns with UnitOfWorkFactory.withUnitOfWork for consistent rollback behavior
  • SpringTransactionAwareUnitOfWorkFactory improved to correctly handle TransactionSynchronization.STATUS_UNKNOWN

🔄 command-handling

  • Introduced RecordExecutionTimeCommandBusInterceptor
  • Default bean name changed from commandBus to essentialsCommandBus for DurableLocalCommandBus
  • Improved bean configuration and auto-wiring consistency

📨 event-bus and messaging

  • Introduced RecordExecutionTimeMessageHandlerInterceptor
  • Default bean name changed from eventBus to essentialsEventBus for EventBus
  • Improved EventProcessor logging
  • Introduced InfrastructureLocalEventBus for technical/internal events

⚙️spring-starters

  • Added support for disabling ReactiveHandlersBeanPostProcessor via essentials.reactive-bean-post-processor-enabled
  • ReactiveHandlersBeanPostProcessor now ignores:
    • Beans with @AutoConfiguration
    • Beans with role BeanDefinition.ROLE_INFRASTRUCTURE

🧬 Module: essentials-types & essentials-types-jackson

  • Enhanced Jackson 2.18 compatibility:
    • AggregateType, EventName, EventType, CorrelationId, EventId, MessageId, SubscriberId, TenantId
    • CharSequenceType, CountryCode, CurrencyCode, EmailAddress
    • InboxName, LockName, OutboxName, QueueEntryId, QueueName
  • Improved documentation in both modules’ README.md files

🧠 Module: shared

  • Introduced:
    • QuadFunction: a generic 4-arg functional interface
    • InvocationTracker: for tracking method execution via PatternMatchingMethodInvoker
    • FunctionalInterfaceLoggingNameResolver: for logging-friendly names from lambdas and method references

📚 Kotlin event-sourcing

  • Added Kotlin doc examples to GivenWhenThenScenario

📦 Dependency & Plugin Updates (All Modules)

  • Upgraded core dependencies:
    • Spring Framework, Reactor, Netty, SLF4J, Jackson, JUnit, Mockito, Testcontainers, Awaitility, JDBI
  • Security: upgraded Tomcat to 10.1.39 to resolve CVE in 10.1.33 (included with Spring Boot 3.2.12)
  • Maven Plugin upgrades:
    • maven-compiler-plugin, maven-surefire-plugin, dependency-check-maven, and more

Full Changelog: 0.40.22...0.40.23

All changes:

  • Updated the project's organization and organizationUrl to Trustworks and https://www.trustworks.dk as this will become the new home for the project
  • Updated 3rd party dependencies:
    • spring-framework 6.1.18
    • reactor 2023.0.16
    • slf4j 2.0.17
    • awaitility 4.3.0
    • netty 4.1.119.Final
    • junit 5.12.1
    • testcontainers 1.20.6
    • jdbi3 3.49.0
    • jackson 2.18.3
    • mockito 5.16.1
    • logback 1.5.18
    • tomcat 10.1.39 (Due to CVE in version 10.1.33 included by Spring Boot 3.2.12)
  • Updated maven plugins:
    • maven-project-info-reports-plugin 3.9.0
    • maven-clean-plugin 3.4.1
    • maven-install-plugin 3.1.4
    • maven-deploy-plugin 3.1.4
    • maven-failsafe-plugin / maven-surefire-plugin 3.5.3
    • maven-compiler-plugin 3.14.0
    • dependency-check-maven 12.1.1
    • flatten-maven-plugin 1.7.0
  • Added configuration of MeasurementEventStoreSubscriptionObserver and RecordExecutionTimeEventStoreInterceptor which can be configured using these properties:
    •   # Event Store metrics configuration
        essentials.event-store.metrics.enabled=true
        essentials.event-store.metrics.thresholds.debug=25ms
        essentials.event-store.metrics.thresholds.info=200ms
        essentials.event-store.metrics.thresholds.warn=500ms
        essentials.event-store.metrics.thresholds.error=5000ms
      
        essentials.event-store.subscription-manager.metrics.enabled=true
        essentials.event-store.subscription-manager.metrics.thresholds.debug=25ms
        essentials.event-store.subscription-manager.metrics.thresholds.info=200ms
        essentials.event-store.subscription-manager.metrics.thresholds.warn=500ms
        essentials.event-store.subscription-manager.metrics.thresholds.error=5000ms
      
    • and logging can be configured using
      <logger name="dk.cloudcreate.essentials.components.eventsourced.eventstore.postgresql.observability.micrometer.MeasurementEventStoreSubscriptionObserver" level="DEBUG"/>
      <logger name="dk.cloudcreate.essentials.components.eventsourced.eventstore.postgresql.interceptor.micrometer.RecordExecutionTimeEventStoreInterceptor" level="DEBUG"/>
  • Introduced essentials.reactive-bean-post-processor-enabled to disable the ReactiveHandlersBeanPostProcessor
  • Changed default bean name:
    • essentialsCommandBus instead of commandBus for DurableLocalCommandBus
    • essentialsEventBus instead of eventBus for EventBus
  • Auto configuration of RecordExecutionTimeMessageHandlerInterceptor, RecordExecutionTimeCommandBusInterceptor and RecordExecutionTimeDurableQueueInterceptor for essentials metrics collection and logging
    • Performance tracking is not enabled per default
    • To enable tracking and controlling logging you can use
    # Durable Queues metrics configuration
    essentials.metrics.durable-queues.enabled=true
    essentials.metrics.durable-queues.thresholds.debug=25ms
    essentials.metrics.durable-queues.thresholds.info=200ms
    essentials.metrics.durable-queues.thresholds.warn=500ms
    essentials.metrics.durable-queues.thresholds.error=5000ms
    
    # Command Bus metrics configuration
    essentials.metrics.command-bus.enabled=true
    essentials.metrics.command-bus.thresholds.debug=25ms
    essentials.metrics.command-bus.thresholds.info=200ms
    essentials.metrics.command-bus.thresholds.warn=500ms
    essentials.metrics.command-bus.thresholds.error=5000ms
    
    # Message Handler metrics configuration
    essentials.metrics.message-handler.enabled=true
    essentials.metrics.message-handler.thresholds.debug=25ms
    essentials.metrics.message-handler.thresholds.info=200ms
    essentials.metrics.message-handler.thresholds.warn=500ms
    essentials.metrics.message-handler.thresholds.error=5000ms
    and logging levels using:
    <logger name="dk.cloudcreate.essentials.components.foundation.interceptor.micrometer.RecordExecutionTimeCommandBusInterceptor" level="DEBUG"/>
    <logger name="dk.cloudcreate.essentials.components.foundation.interceptor.micrometer.RecordExecutionTimeDurableQueueInterceptor" level="DEBUG"/>
    <logger name="dk.cloudcreate.essentials.components.foundation.interceptor.micrometer.RecordExecutionTimeMessageHandlerInterceptor" level="DEBUG"/>
  • Expanded DurableQueuesIT to verify json_deserialization_problem_causes_message_to_be_marked_as_dead_letter_message
  • Expanded PostgresqlDurableQueues.getNextMessageReadyForDelivery and MongoDurableQueues.getNextMessageReadyForDelivery to handle DurableQueueDeserializationException and immediately mark the failed message as a Dead-Letter-Message
  • Introduced the QuadFunction
  • Introduced MeasurementTaker and its supporting classes MeasurementContext, MeasurementRecorder
    • LoggingMeasurementRecorder supports logging performance measurements to the log with configurable logging levels according to the LogThresholds
    • MicrometerMeasurementRecorder which uses Micrometer's Timer to record execution times.
  • Added InvocationTracker that can be used with PatternMatchingMethodInvoker to track invocation performance
  • Introduced FunctionalInterfaceLoggingNameResolver that attempts to extract informative names from lambda expressions and method references - useful for logging
  • Improved ReactiveHandlersBeanPostProcessor. It now skips post-processing for Beans with AutoConfiguration annotation or role BeanDefinition.ROLE_INFRASTRUCTURE
  • Improved README.md for the types-jackson module
  • CharSequenceType, CountryCode, CurrencyCode and EmailAddress are now compatible with Jackson version 2.18.*
  • Improved README.md for the types module
  • Improved EventProcessor logging
  • Introduced EventStoreSubscriptionObserver which is used for tracking EventStoreSubscription statistics
    • Added MeasurementEventStoreSubscriptionObserver as the default EventStoreSubscriptionObserver implementation
    • Added EventStoreSubscriptionObserver to DefaultEventStoreSubscriptionManager
  • Added isExclusive, isAsynchronous and isInTransaction methods to EventStoreSubscription
  • Introduced RecordExecutionTimeEventStoreInterceptor that records execution time for event store operations using the MeasurementTaker API
  • Added more OptimisticAppendToStreamException message explanation and improved logging formatting
  • Improved SeparateTablePerAggregateTypePersistenceStrategy's message and logging in case of OptimisticAppendToStreamException or AppendToStreamException during persist
  • Improved PostgresqlEventStore:
    • Added support for resolveBatchSizeForThisQuery corner case when no events have been persisted for an aggregate type.
    • Improved PollEventStoreTask poll interval logic if events were published vs when no events were published
  • Added examples to GivenWhenThenScenario's Kotlin doc
  • AggregateType, EventName, EventType, CorrelationId, EventId, MessageId, SubscriberId and TenantId are now compatible with Jackson version 2.18.*
  • Introduced InfrastructureLocalEventBus for publishing internal technical events
  • Introduced DurableQueueDeserializationException to indicate Message JSON payload deserialization issues
  • Added HandleQueuedMessage as an DurableQueuesInterceptor operation.
  • DefaultDurableQueueConsumer:
    • Immediately marks messages that fail due to DurableQueueDeserializationException as dead-letter-messages
    • Added HandleQueuedMessage interception
  • InboxName, LockName, OutboxName, QueueEntryId and QueueName are now compatible with Jackson version 2.18.*
  • Introduced RecordExecutionTimeCommandBusInterceptor, RecordExecutionTimeDurableQueueInterceptor and RecordExecutionTimeMessageHandlerInterceptor,
    which measure processing time for the CommandBus, DurableQueues and @MessageHandler annotated methods, using the new MeasurementTaker API.
  • Improved DefaultStatefulAggregateRepository logging and changed default level from TRACE to DEBUG
  • Improved MongoFencedLockStorage TransactionException and WriteConflict handling
  • Added MongoUtil.isWriteConflict and called it from MongoFencedLockStorage and MongoDurableQueues
  • Adjusted DBFencedLockManagerIT timeout and reconnection logic
  • UnitOfWorkFactory and UnitOfWorkLifecycleCallback switched to working with Throwable instead of Exception for rollbacks
  • Improved handling of TransactionSynchronization.STATUS_UNKNOWN in SpringTransactionAwareUnitOfWorkFactory