Transactions: Best Approach

Hi Guys,

I’m currently checking out the transaction stuff that is in Event Store and I was wondering what peoples experience is with it and also some suggestions on the best way to go about using them.

I’ve currently got a simple implementation that works, but I’m sure there is plenty of room for improvement.

Here is what I have:

private bool DoTransaction(string streamId, IEnumerable eventDatas)

{

using (EventStoreTransaction transaction = _connection.StartTransactionAsync(streamId, ExpectedVersion.Any).Result)

{

try

{

transaction.WriteAsync(eventDatas).Wait();

transaction.CommitAsync().Wait();

}

catch (Exception ex)

{

transaction.Rollback();

return false;

}

}

return true;

}

``

What is it you are trying to do?

This is to ensure that if writing fails part way through a collection of events, none of them are committed to the event store. The process will retry at some point in the future.

This was more a general advice around using ES transactions though, rather than a “Solve this problem for me post”. Though if there is a better way of achieving what I am trying, I’m all ears :slight_smile:

You can write more than one event at a time in a batch
How big is this collection?

The collection is n items long, potentially in the many millions. Is there an upper limit to transactions or batch writing.

Is the Batch stuff you talk about the AppendToStreamAsync? If not, can you point me to the docs for what that is?

Yeah append to string takes an array.

Millions is not good for that though :slight_smile:

So sticking with transactions is probably the best way forward then?

Yeah but we have been considering depreciating them ...

Is this a one off import or?

Nope. This will run periodically, prompted by receipt of a file.

OK.

Can I ask why you have millions of events to one stream on an import?
Why is this not many many streams?

Conceptually, it doesn’t make sense to split these events down into many streams, as they would then be millions of streams all with one event in, and these events are part of an audit trail in relation to one entity.

Millions is possible, but unlikely. The majority of times this runs will be dealing with a few hundred thousand but we need to be able to cater for the worst.

When I evangelize event sourcing, this question or variants on it, is probably the most common. (We are an OLTP shop.) What follows is my generalist answer, caveat that it may not apply to your business.

The question is generally a smell that the questioner is thinking too much “classic DB” and not enough “event stream.” The stream approach is to model a transaction as a series of events, with a “commit” or “finalizer” event to logically complete the transaction. That is, a transaction’s “completeness” is interpreted by the READER side (who looks for a finalizing event), not the WRITER side (who would roll back the data). I ask people to think of transactions not as single atomic actions, but as an FSM that events drive forward.

There are advantages to this approach. The biggest (as always with ES) is avoiding information loss. That is, the fact that a transaction was even STARTED (and then cancelled) is often valuable info. An atomic rollback erases that, which usually means you need to capture it in a logging system, what have you.

Classic example is a long webform. In the old mindset, if your computer crashes mid-entry (you lose the cookie), you never committed anything and have to start all over. In a stream mindset, every fine-grained change is captured as you go, and you can pick up where you left off. If you are storing a lot of progress “state” on the side, you are stream processing in spirit, if not in name.