Microservice Idempotency: 7 Production Patterns to Eliminate Duplicate Orders & Payments

This article presents seven production-ready idempotency patterns for microservices — frontend debounce, token mechanism, database unique indexes, state machine validation, Redis caching, MQ consumer deduplication, and distributed locks — organized as a layered defense from frontend to database, with code examples and a real duplicate-payment incident analysis.

Internet Backend Architecture Stack
Internet Backend Architecture Stack
Internet Backend Architecture Stack
Microservice Idempotency: 7 Production Patterns to Eliminate Duplicate Orders & Payments

Idempotency ensures a request produces the same business result regardless of how many times it executes, preventing dirty or duplicate data. Naturally idempotent operations include GET queries and DELETE; high-risk non-idempotent operations are POST creates, deductions, inventory decrements, coupon issuance, points changes, and status updates — any write interface without idempotency will eventually fail in production.

Why Duplicate Requests Are Unavoidable in Microservices

The author identifies six architectural sources of duplication, emphasizing that 90% stem from infrastructure mechanisms, not user error:

Frontend debounce failure or rapid user clicks

Gateway retries and timeout auto-retries

Feign remote call retries

RabbitMQ/RocketMQ redelivery (at-least-once semantics)

Nginx timeout retries

Business exception retries and compensation task retries

Conclusion: duplicate requests are an inherent property of distributed architecture; they can only be intercepted, never eliminated.

Seven Production Idempotency Patterns (Layered Defense)

1. Frontend Button Debounce (Layer 1: UX)

Disables the button after click, re-enables after request completes. Only prevents user double-clicks; cannot stop backend retries, MQ redelivery, or malicious replay. Auxiliary only, not a sole guarantee.

2. Unique Token Mechanism (High-Concurrency Core, Enterprise Standard)

Applies to high-concurrency ordering, flash sales, promotions. Full flow:

On order page load, backend generates unique idempotent token, stores in Redis with 10-minute TTL

Frontend sends token with order request

Backend interceptor validates token existence

If exists, delete token and execute business

Second request finds token missing, returns "Do not submit repeatedly"

// Generate idempotent token
public String generateIdempotentToken() {
    String token = UUID.randomUUID().toString();
    redisTemplate.opsForValue().set("idemp:token:" + token, "1", 10, TimeUnit.MINUTES);
    return token;
}
// Interceptor validation
public boolean checkToken(String token) {
    if (token == null) {
        return false;
    }
    // Delete success = first request
    Boolean delete = redisTemplate.delete("idemp:token:" + token);
    return Boolean.TRUE.equals(delete);
}

Advantages: completely blocks duplicate submission, interface replay, fits flash-sale/high-concurrency scenarios.

3. Database Unique Index (Ultimate Safety Net, Final Defense)

Core idea: every business write must have a unique index on the business key. Order table, payment log table, points ledger table — all keyed by unique business number.

ALTER TABLE `order` ADD UNIQUE INDEX `uk_order_no`(`order_no`);
ALTER TABLE `pay_log` ADD UNIQUE INDEX `uk_pay_no`(`pay_no`);

Principle: duplicate insert throws error; database layer blocks dirty data. Even if all code layers fail, data remains correct.

4. State Machine Idempotency (Order/Payment Core Scenarios)

Best for payment callbacks, order status updates, refund callbacks. Core logic: only process initial state; non-initial states return success immediately without action.

Payment callback example:

Order status = WAIT_PAY → allow update to PAID

Order status = PAID/CANCELLED → return success, no processing

@Transactional(rollbackFor = Exception.class)
public void payCallback(String orderNo) {
    Order order = orderMapper.selectByNo(orderNo);
    // State machine idempotency core
    if (!order.getStatus().equals(OrderStatus.WAIT_PAY.getCode())) {
        return;
    }
    // Execute post-payment business
}

Solves: callback duplication, MQ duplicate consumption, infinite retries.

5. Redis Cache Idempotency (Flash-Sale First Choice)

For ultra-high concurrency where database pressure is high; Redis acts as front-end deduplication.

public boolean isRepeat(String bizNo) {
    String key = "idemp:biz:" + bizNo;
    if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {
        return true;
    }
    redisTemplate.opsForValue().set(key, "1", 24, TimeUnit.HOURS);
    return false;
}

Flow: after processing, store unique business number in Redis; TTL set per business expiry; repeat requests intercepted.

6. MQ Message Idempotency (Solves Duplicate Consumption)

Problem essence: MQ guarantees at-least-once delivery; duplicate consumption is inevitable. Solution: message carries unique MSG_ID; before consumption, check table/Redis for prior consumption. Already consumed → skip; not consumed → execute business.

7. Distributed Lock Idempotency (Ultimate Strong Consistency)

For ultra-sensitive scenarios — deductions, funds, inventory. Uses Redisson distributed lock; same business number allows only one thread at a time, eliminating concurrent duplicates entirely.

Production-Grade Layered Idempotency Architecture (Standard Template)

Do not rely on a single pattern; large companies use multi-layer defense:

Frontend Layer — Button debounce: Reduce user-side duplicate requests

Gateway Layer — Global token interception: Block illegal replay requests

Interface Layer — Redis idempotency check: Intercept short-term duplicate requests

Business Layer — State machine judgment: Guarantee business state does not jump incorrectly

Data Layer — Unique index safety net: Final data absolute safety

Layer upon layer; if one layer is breached, the next still catches.

Real Production Incident Postmortem (Duplicate Deduction)

Symptom

Some users experienced multiple deductions for the same order; fund reconciliation failed.

Root Cause Analysis

Payment gateway timeout triggered auto-retry

Backend interface lacked idempotency check

Database had no unique index safety net

Result: same payment flow written multiple times, multiple deductions

Fix

Add unique index to payment flow table

Add Redis idempotency interception to payment interface

Add state machine judgment to callback interface

Disable unnecessary gateway retries

After fix: duplicate deduction issue completely eliminated.

Architect Summary (Idempotency Core Principles)

All write interfaces must be idempotent by default; no wishful thinking.

Duplicate requests are not bugs; they are the norm in distributed architecture.

Frontend debounce only optimizes UX; cannot guarantee data safety.

High-concurrency ordering: prefer Token + Redis idempotency.

Callbacks and status updates: prefer state machine idempotency.

All business flow tables must have unique index safety net.

MQ consumption must be idempotent; otherwise reconciliation anomalies are guaranteed.

Idempotency is the last line of defense for microservice data safety — more critical than rate limiting or circuit breaking.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

distributed-systemsmicroservicesdatabaseRedispayment systemsMessage Queuedistributed lockIdempotency
Internet Backend Architecture Stack
Written by

Internet Backend Architecture Stack

Over ten years of hands-on Java backend architecture experience, focusing on sharing mainstream internet technologies such as Java backend, microservices, distributed systems, high concurrency, performance optimization, and source code analysis. Building a platform for Java technologists to exchange and grow, collaborating with peers to advance together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.