Occurrent 0.11.0 is now available with some new features, bug fixes and dependency upgrades. The GenericApplicationService implementation now supports specifying a RetryStrategy. A default retry strategy is used that retries the WriteConditionNotFulfilledException for a maximum of 5 times (see changelog below for more details). You can of course disable or change this if you like.

Changelog:

  • Improved error message and version for write condition not fulfilled that may happen when parallel writers write to the same stream at the same time.
  • Upgraded to cloud events java sdk to version 2.1.1
  • Upgraded to Kotlin 1.5.21
  • Added a mapRetryPredicate function to Retry that easily allows you to map the current retry predicate into a new one. This is useful if you e.g. want to add a predicate to the existing predicate. For example:

      // Let's say you have a retry strategy:
      Retry retry = RetryStrategy.exponentialBackoff(Duration.ofMillis(100), Duration.ofSeconds(2), 2.0f).maxAttempts(5).retryIf(WriteConditionNotFulfilledException.class::isInstance);
      // Now you also want to retry if an IllegalArgumentException is thrown:
      retry.mapRetryPredicate(currentRetryPredicate -> currentRetryPredicate.or(IllegalArgument.class::isInstance))
    
  • The GenericApplicationService now has a RetryStrategy enabled by default. The default retry strategy uses exponential backoff starting with 100 ms and progressively go up to max 2 seconds wait time between each retry, if WriteConditionNotFulfilledException is caught. It will, by default, only retry 5 times before giving up, rethrowing the original exception. You can override the default strategy by calling new GenericApplicationService(eventStore, cloudEventConverter, retryStrategy). Use new GenericApplicationService(eventStore, cloudEventConverter, RetryStrategy.none()) to revert to previous behavior.
  • Upgraded spring-boot used in examples to 2.5.3
  • Upgraded spring-mongodb to 3.2.3
  • Upgraded the mongodb java driver to 4.3.1
  • Added ability to write a single event to the event store instead of a stream. For example:

      CloudEvent event = ...
      eventStore.write("streamId", event);
    

    This has been implemented for both the blocking and reactive event stores.