Question

I'm trying to implement microservices and I'm still super new to the subject, but, I was able to answer most of questions.

However, one of the questions that I can't come up with a good solution to is how do I make my consumer idempotent when my publisher publishes at least once?

Graph A

What happens without making Consumer idempotent:

Our consumer receives Event A multiple times, and Event A is asking to pay X dollar to User A, without handling this correctly, we've paid User A 3 * X times.

Possible solution

What I've come up with is this solution:

We create an Events table in Service A (publisher), we create an entity with an id and serviceName (in this case serviceA) inside Events table, then we proceed to publish the event.

In Service B (consumer), we create a ReceivedEvents table, which holds both eventId and serviceName as primary key, this way, whenever we have a new event, we will first check if the event is inside ReceivedEvents, if not, we proceed to complete the task.

Is this approach good enough? Is there an alternative to this approach?

Was it helpful?

Solution

For something like payments, you would simply append a timestamp to it and shift your DB insert to be “insert into pmts where not exist payment with this amount and this timestamp”. For something like users, the unique constraint might be username.

Entities not in a DB like this will require a different approach. Emails for example might just be fine to duplicate given how infrequently the event duplication happens. Otherwise a transient db/cache owned by the receiving microservice is usually used to persist events for a short while. There can be race conditions there, so take care with your design.

OTHER TIPS

That's kinda a bad design as the central database undermines the distributed nature of your event queue.

Instead I would make each consumer idempotent in isolation.

ie the PaymentConsumer would record payments made and thus detect duplicate payment requests and reject/ignore them.

the PackageSenderConsumer would similarly record it id of orders it had processed and not send two packages etc etc

This is essentially the same solution without the central 'Events' database

Licensed under: CC-BY-SA with attribution
scroll top