پاسخ کوتاه: انتشار خودکار محصول از اودو به اینستاگرام با یک دکمه انجام میشود ولی زیر آن یک معماری دو مرحلهای است: کانتینر رسانه (ساخت تصویر با کد یکتا) و صف انتشار با سهمیهی روزانه و قفل تکرار — تا هیچ پستی دوبار نرود و هیچ ریکوئستی بلاک نشود. جزئیات مهندسیاش در همین مقاله.
چرا «صف» قلب این سیستم است؟
- سهمیهی روزانه اینستاگرام واقعی است؛ انتشار پشتسرهم = اکشن بلاک
- قفل یکتا روی شناسه محصول: باگ یا تلاش مجدد، پست تکراری نمیسازد
- تلاش مجدد با فاصله نمایی: خطای موقت اینستاگرام ماجرای نصفهکاره نمیسازد
محصول نهایی: شاپ اینستاگرام ابرک.
ملخص الإجابة: النشر التلقائي لمنشور ليس «طلب HTTP واحداً». واجهة إنستغرام الرسمية تنفّذ النشر على مرحلتين (إنشاء حاوية الوسائط أولاً، ثم نشرها)، ويجب أن تكون الصورة قابلة للجلب من عنوان عام لزاحف ميتا، ولكل حساب حصة يومية، وقد تنقطع الشبكة أيضاً. المعمارية الصحيحة تُخرج هذه العملية من معاملة المستخدم وتُسندها إلى طابور صادر بمفتاح فريد.
لماذا يُعدّ النشر المباشر أثناء معاملة المستخدم خطأً؟
الإغراء الأول هو أن يضغط المستخدم الزر فيرسل الكود الطلب إلى API في اللحظة نفسها ويعرض النتيجة. وهذا التصميم له ثلاثة إخفاقات متوقعة:
- قفل طويل لقاعدة البيانات: تبقى المعاملة مفتوحة حتى نهاية جولة الشبكة، وتحت الحمل يُبطئ ذلك النظام كله.
- حالة غير محددة: إن انقطع الاتصال بعد إرسال الطلب وقبل استلام الرد، لن تعرف إن نُشر المنشور أم لا. وقد تؤدي إعادة المحاولة إلى إنشاء منشور مكرر.
- تراجع معاملة (rollback) زائف: إذا تراجعت معاملة Odoo لأي سبب، يُحذف سجل المنشور لكن المنشور الذي نُشر فعلياً على إنستغرام يبقى قائماً.
القاعدة العامة: لا ينبغي إجراء أي إدخال/إخراج شبكي داخل معاملة المستخدم. يجب أن يقتصر عمل المستخدم على «تسجيل النية»؛ أما التنفيذ الفعلي فهو مهمة عامل في الخلفية (background worker).
خط النشر: خمس خطوات
- التحضير: تخصيص رمز فريد، إنشاء صورة بالنسبة والحجم المسموحين، وصياغة تعليق من قالب. مخرجات هذه الخطوة محلية بالكامل ولا تحتاج إلى أي شبكة.
- الإدراج في الطابور: يُنشأ سجل مهمة (job) بـمفتاح محتوى فريد. إذا أُدرج المحتوى نفسه مجدداً، يعود السجل نفسه لا سجل جديد.
- إنشاء حاوية الوسائط: ترسل العملية الخلفية الرابط العام للصورة ونص التسمية التوضيحية إلى نقطة
/mediaوتحصل على معرّف حاوية. - النشر: يُرسَل معرّف الحاوية إلى نقطة
/media_publishويعود معرّف الوسائط النهائي؛ وهو ما يجعل المنشور قابلاً للتتبع دائماً. تفاصيل هذا التدفق في توثيق نشر المحتوى من Meta وارد. - المزامنة: يُقرأ الرابط الدائم للمنشور ويُحفظ على السجل حتى تُربط التعليقات والإحصاءات لاحقًا بالمنشور نفسه.
مسألة الصورة: يجب أن يتمكن الزاحف (crawler) من قراءتها
في هذه المعمارية أنتم لا ترفعون الصورة؛ بل تقدّمون رابطًا وتقوم المنصة نفسها بجلب الصورة. وهذا قيد جاد: يجب أن يكون الرابط عامًا، بلا مصادقة، ويمكن الوصول إليه من خوادم ميتا. أكثر أخطاء هذه المرحلة شيوعًا (خطأ جلب الوسائط) تكاد تعود دائمًا إلى أحد هذه الأسباب: رابط داخلي أو خلف تسجيل دخول إجباري، شهادة TLS غير صالحة، صيغة غير مسموحة (يجب أن تكون الصورة JPEG)، حجم يتجاوز السقف، أو نسبة أبعاد خارج النطاق المسموح.
للتركيبات التي لا يمكن الوصول إلى خادمها من الخارج، الحل هو مُرحِّل وسيط: تُرفع الصورة مرة واحدة إلى المُرحِّل، الذي يُنشئ عنواناً عاماً ومؤقتاً برمز عشوائي، وبعد النشر يُحذف الملف بواسطة منظّف مجدول. الميزة الجانبية أن صورة منتجكم لا تبقى إلى الأبد على عنوان يمكن تخمينه.
الحصة: اسأل ولا تخمّن
لكل حساب سقف محدد للنشر عبر API خلال 24 ساعة. والمهم ألّا تخمّن هذا الرقم: فواجهة API نفسها توفر نقطة للاستعلام عن الحصة المستهلكة، والتصميم الصحيح يستعلم عنها قبل كل نشر. فإن نفدت الحصة فالسلوك الصحيح ليس «إعطاء خطأ»؛ بل أن يبقى المنشور في حالة «انتظار الحصة» وأن يُنشر تلقائيًا بعد فتح النافذة. ومن وجهة نظر البائع فالفرق بين السلوكين هو الفرق بين «النظام تعطّل» و«النظام يعرف عمله».
الحماية من التكرار: مفتاح فريد وعديم التأثير (idempotent)
في أي نظام موزّع «إعادة المحاولة» أمر لا مفر منه، وبلا حماية تعني إعادة المحاولة منشورًا مكررًا. المفهوم الحاسم هو عدم التأثر بالتكرار (idempotency)، وهو المبدأ نفسه الذي طُبّق في RFC 9110 معرَّفة لطرق HTTP: تنفيذ العملية عدة مرات يجب أن يُحدث نفس أثر تنفيذها مرة واحدة.
التنفيذ العملي بسيط: من المحتوى الفعلي للمنشور (الحساب، المنتج، الرمز، بصمة الصورة والتعليق التوضيحي) يُنشأ UUID الإصدار 5 — أي معرّف مبني على الاسم وفق RFC 9562 — يُنشأ ويُفرض عليه قيد تفرّد في جدول قائمة الانتظار. المحتوى نفسه يُنتج دائمًا المفتاح نفسه، فلا يُنشأ سجل ثانٍ أبدًا. وإذا تغيّر التعليق أو الصورة، يتغيّر المفتاح ويُسمح بنشر جديد — وهذا بالضبط السلوك المتوقَّع.
الأخطاء: أيها نعيد محاولته؟
ليست كل الأخطاء متساوية، والتعامل معها بالطريقة نفسها مكلف. التصنيف العملي:
| الفئة | مثال | السلوك الصحيح |
|---|---|---|
| عابر | انقطاع الشبكة، وحدّ المعدّل، وخطأ مؤقت في سحب الوسائط | إعادة المحاولة بتأخير أُسّي |
| الحصة | انتهاء الحد الأقصى اليومي (24 ساعة) | الإبقاء حتى تُفتح النافذة دون احتسابه فشلًا |
| دائم | رمز باطل، وصول مرفوض، محتوى غير مسموح به | التوقف الفوري وإبلاغ المستخدم؛ إعادة المحاولة لا تؤدي إلا إلى استهلاك الموارد |
التأخير الأسي (exponential backoff) مع قدر من التشتت العشوائي هو النمط القياسي للفئة الأولى: كل فشل يضاعف فترة الانتظار حتى لا تتفاقم حالة الخدمة المرهقة بهجوم من المحاولات المتزامنة.
مساران للاتصال: مباشر وعبر وسيط
طبقة تجريد رقيقة فوق استدعاءات واجهة برمجية — بتطبيقين «مباشر» و«ترحيل (Relay)» — تتيح كتابة كل منطق المعالجة الأولية (الطابور، الحصة، الأخطاء) مرة واحدة، مع جعل تغيير مسار الاتصال مجرد خيار في نموذج الحساب. في وضع الترحيل، يُوقَّع كل طلب باستخدام HMAC على الثلاثية «الطابع الزمني، nonce، المحتوى» (RFC 2104) ويُسجَّل nonce لمرة واحدة على جانب الوسيط (relay) بحيث يتعذّر إعادة تشغيل الطلب. كما يتم التحقق من الأحداث الواردة بالتوقيع الرسمي لميتا قبل تفسير أي بايت من محتواها.
ما الذي نسجّله (وما الذي لا نسجّله أبداً)؟
لاستكشاف الأخطاء، من الضروري تسجيل: نقطة النهاية المستدعاة، رمز الحالة، معرّف خطأ المنصة، المدة الزمنية، معرّف المهمة، ورقم المحاولة. وقاعدة بلا استثناء: يجب ألا يُكتب رمز الوصول أبداً في السجل — لا كاملاً ولا مقتطعاً. الرمز ظاهر فقط في سجل الحساب لمجموعة مدير النظام، ويُنظَّف من نصوص الأخطاء قبل تسجيلها أيضاً.
الخلاصة
يتكون خط نشر موثوق من أربعة عناصر: إبعاد الشبكة عن معاملة المستخدم، مفتاح فريد لضمان عدم التكرار (Idempotency)، تصنيف صحيح للأخطاء، والاستعلام عن الحصة بدلًا من تخمينها. هذه العناصر الأربعة هي الفارق بين «سكريبت يعمل أحيانًا» و«قدرة يمكن الاعتماد عليها في مبيعات الشركة». لمشاهدة النتيجة النهائية على Odoo، دليل الإعداد وللمسار التكميلي للتحويل، مقال من التعليق إلى الرسالة المباشرة للاطلاع عليه.