What is New in PHP Event Sourcing 3.9 & 3.10

Today we are talking about two releases for our PHP library patchlevel/event-sourcing: version 3.9.0 and version 3.10.0!

The first release, 3.9.0, was a smaller one mostly focused on some DX improvements. The second, 3.10.0, comes with some neat features for the subscription engine along with various updates and deprecations. So, let's start going through these changes.

3.9.0

EventDispatcher in Worker

We made a change in patchlevel/worker which makes using the worker even more valuable. You can now utilize the events from the worker by adding your own listeners to its internal events. Previously, we already used an event dispatcher internally, but you could not add any listeners to it.

Now this is possible, which can come in handy if, for example, you are using a long-running process, like the subscription engine, and have an error tracking tool such as Sentry in place. Without these changes, it was not possible to manually flush messages to send them to Sentry if something happened during the execution of the subscription engine.

In the bundle, we added a ResetServicesListener which already takes advantage of this new possibility. Now, after every run of the subscription engine, we are executing Symfony's ServiceResetter. This makes the subscription engine even more resource-efficient than before. Also, regarding the Sentry example, if you are using the Monolog variant, this now automatically flushes all errors to Sentry.

ChildAggregates: Usage of Private Properties

We streamlined the usage of ChildAggregates based on a user request. The issue was that the ChildAggregate was a private property of the aggregate and was implemented using our BasicAggregateRoot abstract class. This combination led to an error due to visibility issues, which we have resolved by using reflection.

Keep in mind that the ChildAggregate feature is still experimental and that we also have another feature which we believe is better suited in almost every case: micro aggregates. You should probably use that feature instead of ChildAggregates.

3.10.0

PHP 8.4 Support

We officially added PHP 8.4 support, and not much work was needed. PHP 8.4 is now included in our test matrix; therefore, everything is tested with this new version.

Deprecation of AggregateId ArgumentResolver

We deprecated the AggregateIdArgumentResolver because we believe that if you need it, you have already done something wrong. The Aggregate ID should be part of your event itself and not only part of our metadata. That's why we want to remove this class from our library, as it may lead to poor event design.

Subscription Engine: Different RetryStrategies for Subscribers

We already supported defining a RetryStrategy for the subscription engine to handle failed attempts. Now, we are taking it a step further by enabling you to define different strategies for your subscribers. This gives you more control over the behavior when something goes wrong.

To make this work, we now have a RetryStrategyRepository which holds a map of unique name to strategy. This name is then used for configuration. To configure a retry strategy for a subscriber, we offer a new attribute #[RetryStrategy] that expects the name of the strategy. The library comes with two strategies configured out of the box: default and no_retry. The default strategy utilizes the ClockBasedRetryStrategy, configured with 5 attempts, a base delay of 5 seconds, and a factor of 2. The no_retry strategy is self-explanatory — it simply does not retry.

Subscription Engine: OnFailed Hook

In version 3.7.0, we added a new status for subscriptions: the failed status. This status is reached when an error occurs and the retry strategy fails to recover from it. Now, we have polished this further by allowing you to easily hook into this case. We added a #[OnFailed] attribute that you can add to a method on the subscriber to handle the failed message. For example, you can add this message to a DeadLetter queue for later processing.

By doing this, you free the subscription engine from holding the subscription in the failed state. After successfully handling the #[OnFailed] method, the subscription status will move from failed to active. When using this with projections, be aware that data may then be missing from the table.

Conclusion

These two releases deliver some neat features, especially around the subscription engine, making it even more efficient and powerful. As always, we would love to hear your feedback about these features or any other topics related to event sourcing, so don't hesitate to open an issue on GitHub or start a discussion there. The next release is already in the pipeline, so stay tuned.

Other Recent Posts

RSS

What is New in PHP Event Sourcing 3.8

We are excited to announce the release of patchlevel/event-sourcing version 3.8.0! This update introduces features such as lookup, command bus, read-only event store, and the official release of the stream store. In this post, we will walk you through the key changes.

David Badura
David Badura
Software Entwickler

The Performance Factor in Event Sourcing: What You Need to Know

This article addresses the common concern regarding the performance of event sourcing, particularly the speed at which long-living aggregates with many events are loaded. It explores solutions such as snapshotting and stream splitting to optimize aggregate loading. Furthermore, projections allow for the creation of highly flexible and optimized read models, each can be tailored to specific needs.

Daniel Badura
Daniel Badura
Software Entwickler

What is new in patchlevel/event-sourcing in version 3.7

We’re excited to announce the release of our php library patchlevel/event-sourcing version 3.7.0. This release features better testing capabilities with InMemorySubscriptionStore::clear, improved subscription performance and a new #[Stream] attribute for micro aggregates!

Daniel Badura
Daniel Badura
Software Entwickler