انتقل للمحتوى

    عربي أو إنجليزي · ↑↓ للتنقل · Enter للفتح · Esc للقفل

    English
    في الصفحة دي

    منع التكرار (Idempotency)

    كرر الطلب وانت مطمّن: هيدر Idempotency-Key بيضمن إن الإرسال أو الحملة أو الـ OTP يتنفذ مرة واحدة بالكتير.

    الشبكة بتقع. لو الطلب عمل timeout مش هتعرف الرسالة خرجت ولا لأ. ابعت Idempotency-Key مع كل عملية كتابة وكرر بـ نفس المفتاح: مرسلات بترجعلك أول رد بدل ما تعمل الشغل تاني.

    http
    Idempotency-Key: order-1042-shipped
    الحالةالرد
    أول طلبالردبيتنفذ عادي.
    نفس المفتاح + نفس الـ body (خلال 24 ساعة)الردالرد المتخزن، ومعاه Idempotent-Replayed: true. مفيش حاجة بتتبعت تاني.
    نفس المفتاح + body مختلفالرد409 IDEMPOTENCY_KEY_REUSED — استخدم مفتاح جديد لطلب جديد.
    نفس المفتاح والأول لسه شغالالرد409 IDEMPOTENCY_IN_PROGRESS — استنى شوية وكرر.
    ناقص في إرسال / حملة / OTPالرد400 IDEMPOTENCY_KEY_REQUIRED.
    أطول من 191 أو فيه حروف مش ASCII ظاهرةالرد400 IDEMPOTENCY_KEY_INVALID.

    إمتى يكون إجباري

    إجباري في POST /v2/messages و POST /v2/campaigns و POST /v2/otp. اختياري بس مقبول في أي عملية كتابة تانية. المفاتيح مربوطة بمفتاح الـ API اللي استخدمها: مفتاح تاني، حتى لو من نفس الحساب، عمره ما يرجّع رد غيره.

    تختار المفتاح إزاي

    • اعمله من الحدث بتاعك عشان التكرار يستخدمه لوحده: order-1042-shipped أو otp-login-<sessionId>.
    • متعملش مفتاح عشوائي لكل محاولة — كده الفكرة كلها بتبوظ.
    • الردود المتكررة فيها ids وحالات بس (عمرها ما فيها نص رسالة أو تعليق أو رابط).

    تكرار آمن

    Node.js
    async function sendWithRetry(body, key, attempts = 4) {
      for (let i = 0; i < attempts; i++) {
        const res = await fetch('https://mursilat.com/api/v2/messages', {
          method: 'POST',
          headers: {
            Authorization: `Bearer ${process.env.WASLA_API_KEY}`,
            'Idempotency-Key': key, // نفس المفتاح في كل محاولة
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(body),
        }).catch(() => null); // خطأ شبكة ← كرر
    
        if (res && res.ok) return res.json();
        if (res && res.status < 500 && res.status !== 409 && res.status !== 429) {
          throw new Error((await res.json()).error.code); // التكرار مش هيفيد
        }
        const wait = Number(res?.headers.get('Retry-After')) || 2 ** i;
        await new Promise((r) => setTimeout(r, wait * 1000));
      }
      throw new Error('gave up');
    }