تكرار السؤال: …
الإجابة المختصرة
اطلب من العميل إرسال idempotency key فريد لكل عملية، وخزّنه مع نتيجتها في نفس المعاملة، وأعد النتيجة المخزنة إذا وصل نفس المفتاح مرة أخرى بدل التنفيذ من جديد.
الشرح
انتهاء المهلة لا يعني أن الخادم لم ينفذ الطلب؛ ربما نجح وضاع الرد، فيعيد العميل المحاولة فيُخصم المبلغ مرتين. خزّن المفتاح بقيد فريد (unique constraint) حتى لا ينجح طلبان متزامنان بنفس المفتاح، واحفظ بصمة جسم الطلب لرفض إعادة استخدام المفتاح مع بيانات مختلفة، وحدد مدة صلاحية للمفاتيح. هذا النمط تستخدمه واجهات الدفع مثل Stripe.
مثال بالكود
import json
def create_payment(conn, key: str, request: PaymentRequest) -> dict:
with conn:
row = conn.execute("SELECT response FROM idempotency WHERE key = ?", (key,)).fetchone()
if row:
return json.loads(row[0]) # أعد النتيجة السابقة
result = charge_card(request)
conn.execute(
"INSERT INTO idempotency (key, response) VALUES (?, ?)", # key عليه UNIQUE
(key, json.dumps(result)),
)
return resultأخطاء شائعة
- الاعتماد على العميل وحده لتجنب التكرار.
- فحص وجود المفتاح ثم الإدراج دون قيد فريد فيمر طلبان متزامنان.