Idempotency-Key: gọi lại mà không bị trừ tiền hai lần

bởi CIA cập nhật 21/09/2026 đọc 4 phút

Cách Idempotency-Key ngăn việc trừ credit hai lần

Bài này cũng có ở: English

Mạng lỗi giữa lúc request tới server và lúc response về là chuyện xảy ra thường xuyên. Khi đó code của bạn không biết lượt chạy đã diễn ra hay chưa, nên nó thử lại. Không có Idempotency-Key, lần thử lại đó là một lượt mới và bị trừ credit lần nữa.

Khoá hoạt động thế nào

Bạn gửi một chuỗi tự sinh trong header Idempotency-Key. Hệ thống lưu khoá đó cùng kết quả của lượt chạy, duy nhất theo người dùng và khoá.

Gửi lại cùng một khoá thì hệ thống trả kết quả cũ và không trừ credit lần hai. Gửi khoá khác thì đó là một lượt mới và bị tính tiền.

Nghĩa là quy tắc rất đơn giản: một ý định = một khoá. Thử lại thì giữ khoá; muốn chạy lượt mới thì đổi khoá.

Cách sinh khoá đúng

Khoá nên gắn với ý định của bạn, không gắn với thời điểm gọi. Ba cách dùng được:

UUID sinh một lần rồi giữ lại. Sinh trước khi gọi, lưu vào biến hoặc vào cơ sở dữ liệu của bạn, rồi dùng cho mọi lần thử lại của đúng ý định đó.

Băm từ các tham số cộng một mốc thời gian bạn chọn. Ví dụ băm của "báo cáo kênh X, ngày 21/09/2026". Cùng ý định thì ra cùng khoá.

Mã bản ghi trong hệ thống của bạn. Nếu mỗi lượt chạy tương ứng một dòng trong cơ sở dữ liệu của bạn, dùng mã dòng đó.

Ba lỗi thường gặp

1. Sinh khoá mới trong vòng lặp retry. Đây là lỗi hoàn toàn triệt tiêu tác dụng của khoá. Sinh trước vòng lặp.

2. Dùng dấu thời gian làm khoá. Mỗi lần thử lại có dấu thời gian khác, nên mỗi lần là một lượt mới.

3. Dùng lại một khoá cho ý định mới. Nếu bạn muốn chạy lại cùng một kênh vào tuần sau để có dữ liệu mới, phải đổi khoá — nếu không bạn nhận lại kết quả tuần trước.

Lỗi thứ ba là lỗi ngược với hai lỗi đầu, và cũng gây nhầm: người dùng nghĩ dữ liệu không cập nhật, trong khi họ đang yêu cầu đúng kết quả cũ.

Mẫu đúng, viết bằng lời

khoa = sinh_uuid()            # MỘT lần, ngoài vòng lặp
lan_thu = 0
lặp:
    ket_qua = goi_api(tham_so, header={"Idempotency-Key": khoa})
    nếu thành công: dừng
    nếu lỗi tạm thời và lan_thu < 3:
        lan_thu += 1
        chờ (1s, 4s, 9s)
        tiếp tục            # giữ NGUYÊN khoa
    ngược lại: báo lỗi

Ba mốc chờ tăng dần là cách chờ thông thường. Điều quan trọng là khoa không đổi trong suốt vòng lặp.

Với công cụ chạy nền

Công cụ chậm trả về HTTP 202 kèm mã lượt chạy thay vì kết quả. Idempotency-Key vẫn hoạt động như trên: gửi lại cùng khoá thì bạn nhận lại đúng lượt chạy đó, không tạo lượt mới. Xem gọi API lấy dữ liệu.

Câu hỏi thường gặp

Khoá có hết hạn không? Khoá là duy nhất theo người dùng và khoá. Đừng dựa vào việc nó hết hạn; đổi khoá khi bạn muốn một lượt mới.

Hai người dùng dùng cùng một khoá thì sao? Không xung đột. Tính duy nhất là theo cặp người dùng và khoá.

Có bắt buộc gửi khoá không? Không bắt buộc, nhưng không gửi thì mọi lần thử lại đều bị tính tiền.

Xem thêm bài cùng chủ đề: Dữ liệu & API