Occurrent 0.18.0 is released with major changes and improvements to the Catch-up Subscription Model and introduction of subscription annotation support for Spring Boot. Here are all changes:

  • Major improvements to CatchupSubscriptionModel, it now handles and includes events that have been written while the catch-up subscription phase runs. Also, the “idempotency cache” is only used while switching from catch-up to continuous mode, and not during the entire catch-up phase.
  • Major changes to the spring-boot-starter-mongodb module. It now includes a CatchupSubscriptionModel which allows you to start subscriptions from an historic date more easily.
  • StartAt.Dynamic(..) now takes a SubscriptionModelContext as a parameter. This means that subscription models can add a “context” that can be useful for dynamic behavior. For example, you can prevent a certain subscription model to start (and instead delegate to its parent) if you return null as StartAt from a dynamic position.
  • Added annotation support for subscriptions when using the spring-boot-starter-mongodb module. You can now do:
    @Subscription(id = "mySubscription")
    void mySubscription(MyDomainEvent event) {
        System.out.println("Received event: " + event);

    It also allows you to easily start the subscription from a moment in the past (such as beginning of time). See javadoc in org.occurrent.annotation.Subscription for more info.

  • Added org.occurrent.subscription.blocking.durable.catchup.StartAtTime as a help to the CatchupSubscriptionModel to easier specify an OffsetDateTime or “beginning of time” when starting a subscription catchup subscription model. Before you had to do:
    subscriptionModel.subscribe("myId", StartAt.subscriptionPosition(TimeBasedSubscriptionPosition.beginningOfTime()), System.out::println);

    but now you can do:

    subscriptionModel.subscribe("myId", StartAtTime.beginningOfTime(), System.out::println);

    which is shorter. You’re using Kotlin you can import org.occurrent.subscription.blocking.durable.catchup.beginningOfTime and do:

    subscriptionModel.subscribe("myId", StartAt.beginningOfTime(), ::println)
  • Changed the default behavior of CatchupSubscriptionModel. Before it replayed all historic events by default if no specific start at position was supplied, but now it delegates to the wrapped subscription and no historic events will be replayed. Instead, you need to explicitly specify beggingOfTime or an OffsetDateTime as the start position. For example:
    subscriptionModel.subscribe("myId", StartAtTime.beginningOfTime(), System.out::println);
  • Upgraded Spring Boot from 3.2.1 to 3.2.5
  • Upgraded Mongo sync driver 4.11.1 to 4.11.2
  • Upgraded jobrunr from 6.3.3 to 7.1.1
  • Upgraded project reactor from 3.6.0 to 3.6.5
  • Upgraded jackson from 2.15.3 to 2.15.4
  • Upgraded Kotlin from 1.9.22 to 1.9.23
  • Upgraded spring-data-mongodb from 4.2.0 to 4.2.5
  • Upgraded cloudevents from 2.5.0 to 3.0.0