DomainEventStream usage in EventStore.appendEvents()

The EventStore interface has the following method for writing events:

public void appendEvents(String type, DomainEventStream events)

Question: is there a strong reason to have a DomainEventStream here vs a List? I assume the events are already in memory.

The reason I ask is that for a prototype EventStore implementation, I wrapped it with an EventStore implementation that would retry the appendEvents operation on the underlying EventStore in response to transient persistence issues. Problem is, if you read an event from the stream, encounter an issue & throw, there is no facility to reset the stream in order to retry the operation (ie you’ve lost some events from the head of the stream upon retry).

Thanks in advance. Really liking Axon so far.

Hi Mike,

it’s indeed very likely that the events are always available in-memory. The main reason for this interface is uniformity. It takes a stream, and returns a stream. Another reason is that I’ve made too many mistakes by making assumptions that didn’t hold. Being able to iterate over the events to store is the minimal the event store requires, so I decided to reflect that in the interface.

What you could do is keep track of the events (in a list, for example) while you are reading them. If a failure occurs, you wrap the list in a new DomainEventStream (SimpleDomainEventStream allows you to wrap a list) and pass them to the event store for a retry.

Cheers,

Allard

One option could be to make DomainEventStream be a Iterable. Iterable is a good type to use here, because it doesn’t require everything to be in memory, implies iteration (which is all the event store needs to do), and it’s a native interface. It also means you can use it with anything that uses the Iterable interface, including java’s for(Foo item : items) for-each, as well as libraries like Guava that provide a lot of powerful operations against Iterables.

Thanks Allard, I understand the concerns of limiting what capabilities are exposed in order to provide ‘room to move’ in the future. I worry less about uniformity though, and find that mutable inputs can be troublesome. It does seem safe to assume that appendEvents will almost always be called on in-mem Events. One could imagine implementing a copyEventStore(store1, store2) that worked best with uniform use of DES but using an intermediate List would be a small amount of work.

In this case, the work around of keeping the events while iterating over them will certainly work but is less elegant and makes retry-shims much harder (shim needs to work at underlying interface that uses List param instead of at EventStore intf).

Iterable makes a lot of sense (just throw UnsupportedOp for remove()). I tried to use the DES that way initially.

Hi,

Making DomainEventStream implement (extend) Iterable, in my opinion, doesn’t really make sense. Except for one implementation, none of them is actually iterable. The stream itself is more similar to the Iterator (except that it prescribes a peek() method and no remove() ). Iterable assumes that you can start iterating over the items in a collection at any time. With the DomainEventStream, that’s not the case.

The SimpleDomainEventStream is an exception; this implementation could implement Iterable, but that wouldn’t help in Mike’s case.

Creating a wrapper around a DomainEventStream that allows the stream to be ‘reset’ is pretty easy. If you think it helps in your case, let me know.

Cheers,

Allard

Yeah, that is fair enough regarding the use of the Iterable interface, I agree :slight_smile: