I don’t mean to be nitpicking your post, but that’s actually not the definition of idempotency. Wikipedia’s has a good definition and subsequent explanation. From wikipedia (https://wikipedia.org/wiki/Idempotence):
Idempotence is the property of certain operations in mathematics and computer science that they can be applied multiple times without changing the result beyond the initial application.
It’s clarified in the Computer Science section:
In the case of methods or subroutine calls with side effects, for instance, it means that the modified state remains the same after the first call.
There’s a subtle yet _very_ important difference between the definition in Wikipedia and the definition in your post. A piece of code does not need to return the same value in subsequent calls (have the same behavior) for it to be considered idempotent.
In your example, if the notify_friends subroutine propagated the DB::NotUnique back to the caller it would still be idempotent (shitty design notwithstanding) even though its behavior would be different between the first two calls.
I also wanted to point out that using a relational database for recording a request is perfectly fine for production (that’s not to say it’s fine for _every_ production use case). I personally have used this solution to add idempotency to a HTTP service call in production that received thousands of requests per second during peak usage.
Plenty of RDBMS are “really quick on reads and writes”. What you want to make sure you use is a storage system that supports linearizable consistency. Cassandra does support it when used with lightweight transactions through a quorum. I’m not in anyway a Cassandra expert, but I would recommend this article: https://www.datastax.com/dev/blog/lightweight-transactions-in-cassandra-2-0
Hope this helps.