
Idempotency in a software system guareantees us if the same call is done more than once the state of the system is changed just once. This is a must for improving fault tolerance in a system. Especially when it comes to a microservice oriented approach which is inherently a distributed system (more loose coupled components talking over a network). So you have more potential "points of failure" as you have it in a traditional client-server architecture.
​
A sample:
​
A client is doing a rpc call "CreatePersonAddressCmd" (Cmd stands for "Command" - as we want to change the state of the system). The return value of this call is the identifier (ideally a uuid/guid) from the newly created person address.
​
Let us assume the call fails and the middleware returns a "Internal server error" (http status code 500) or a timeout (http status code 408). If the caller was built with a retry-mechanism in mind it would try a again till it reaches a certain number.
​
Now lets first think where can things go wrong. For this look at this graphic:

Guess how many potential failure points you are seeing? At least 6 points. All the red lines (as this shows the network between - and yes, something can be wrong with the network) and then all the components (without the Caller).
From where do you know in this situation what exactely has failed? Even worse, your thread creating the person address in the address microservice is indeed running but because of network latency to the database takes longer and your client already timed out.
To reach idempotence in this situation we must look for "the deepest" point in the chain: The database. The basic idea: The caller instance creates some kind of "transactionId" (uuid/guid). "Transaction" is herer more a logical transaction. It is not a technical Db-transaction. This transaction id is part of the caller request. When the request reaches the address microservice it is first checked against the database if this transaction id is already there. If not the transaction id is inserted to the database together with the person address.
​
If there was a timeout or another error the same caller instance with the same transaction id can do some kind of retry without worrying about duplicate entries.
​
Where do I put this transaction id in the database. There are two ways: You keep this id in a separate table or make it part of your entity record. The later has the advantage you know under which transaction id your entity was created. Especially if you emmit further events you can pass this transaction id and you will have some kind a logical transaction bracket all around this original command initializing the transaction.