I’ve read the documentation and run some of my own tests and I am finding the idempotency behavior confusing. I have a few questions.
Right now, we pull requests off of PubSub and run a number of operations afterwards, one of which is saving the event to ESDB. If something fails during any of these operations, the message is reprocessed from the beginning.
We’d like to enforce idempotency for our events, so I create deterministic UUIDs from a seed that is provided in the message’s metadata.
Working with the Go Client, if I do not set the ExpectedRevision, trying to append an event with the same UUID goes as expected. The event is only appended once and it moves forward successfully and future events are processed normally. I would be fine moving forward with this, but according to the docs leaving this blank “does not 100% guarantee idempotency.” So I’m wondering, what can go wrong here on ESDB side?
If I set the ExpectedRevision to the previous events Version, the event is appended twice. It completely ignores the UUID and the next event I try to append, even to a different stream eventually times out. I would expect if this is set that it would still verify the UUIDs for the stream. Is that not the case? And why would this cause future events to fail?
I’m using eventstore:22.10.4-alpha-arm64v8 for my local testing and the latest Go client.
it’s based on a cache of recently appended events ID
so nothing could “go wrong” , just that the eventIds are not in the cache anymore .
There is no way to control the cache size ( I’m not sure about the size out of my head)
the cache could be emptied for various reasons
the reason for a limited cache is we can’t provide idempotency check on the full log
there are sometime billions of events in the database
some streams might contains hundreds of thousand of events
The idempotent feature is mainly meant for client processes that would send the exact same append request multiple time , in a relatively short period of time
( analogy: think the double-click problem of old in browser)
When setting an expected version and expected version == current version of the stream , the append will happen:
because what you would have happening in code is
Append ( expected version = 1, event Id=A, stream 1)
then
Append ( expected version = 2, event Id=A, stream 1)
it is not the same append
this is different than
Append ( expected version = 1, event Id=A, stream 1)
then
Append ( expected version = 2, event Id=B, stream 1)
then
Append ( expected version = 1, event Id=A, stream 1)
the first and last are the same append , and the result for the last one will vary between idempotent write and WrongExpectedVersion ( in this case it should be idempotent)
I’ve previously seen in the forums that AppendEvents is atomic. However, when I look at the Golang client, it looks like it is just making sequential gRPC calls.
Is the AppendEvents function in the go client atomic?
It occurred to me that you might have been referring to “atomicity” in the context of ACID properties. If that is the case, then yes, appending a batch of events is considered atomic from the database’s perspective. The Go client streams the events that the user wishes to append, but the database will not persist any data until it has received and processed the entire batch of events.