Having the following business case:
Email promotional campaign says that first 1_000_000 users pressing the link will receive a Bonus. Users are going to see either the Bonus or "Sorry" message immediately during visiting web page.
Question: how to design this solution?
- Option 1: Monolith. AtomicInteger. Can the CAS issue take place here? Or 1_000_000 is not that amount that cause an issue in this case? What is the number which can "do" that?
- Option 2: Monolith. sync should work here with no issues ?
- Option 3: Microservices. Redis INCR method. Is there are any options for microservices architecture? Is there a way to use MySql for this purpose?
CodePudding user response:
Plain Old Java: Use in-memory synchronization using java lock semantics. You are correct about using AtomicInteger. However, this can only work if you have only one application instance running.
With MySql: There is a feature called
select for update
that helps you achieve what you are looking for. Whenever someone clicks on the link, you doselect for update
in MySql to see if the bonus is still available. If it is, you do update in DB in the same transaction. Meanwhile, all other parallel reads and writes will be blocked. Hence you get end-to-end fully atomic operation.Redis won't work because even if
INCR
is atomic, the whole flow of reading the value from Redis, performing the business logic, and updating the value in Redis won't be atomic. E.g. Say the user count in Redis was999_999
and 2 users concurrently click on the link. The application checks the count and it's under the threshold of1_000_000
which means, both users are eligible for a discount and you end up giving a discount to both.