منع انتهاء مهلة التصدير: وظائف غير متزامنة، تقدم، وبث التنزيلات
منع انتهاء مهلة التصدير عبر وظائف تصدير غير متزامنة، مؤشرات تقدم، الترقيم، وتنزيلات متدفقة لتقارير CSV وPDF الكبيرة.

لماذا تنتهي مهلة التصدير بشكل مبسط
تنتهي مهلة التصدير عندما لا ينهي الخادم العمل قبل موعد نهائي. قد يحدده المتصفح، عكس وكيل، خادم التطبيق، أو اتصال قاعدة البيانات. بالنسبة للمستخدمين يبدو الأمر عشوائيًا لأن التصدير يعمل أحيانًا ويفشل أحيانًا.
على الشاشة عادةً يظهر كواحد من هذه الأمور:
- مؤشر تحميل (spinner) لا ينتهي
- تحميل يبدأ ثم يتوقف مع "network error"
- صفحة خطأ بعد انتظار طويل
- ملف يتم تنزيله لكنه فارغ أو تالف
التصديرات الكبيرة مُجهدة لأنها تضغط عدة أجزاء من نظامك مرة واحدة. قاعدة البيانات تحتاج لجلب وتجميع صفوف كثيرة. خادم التطبيق يجب أن ينسقها إلى CSV أو يصيرها إلى PDF. ثم المتصفح يجب أن يستقبل استجابة كبيرة دون أن ينقطع الاتصال.
المجموعات الضخمة هي المحفز الواضح، لكن حتى التصديرات "الصغيرة" قد تكون مكلفة. الاتصالات المكلفة (joins)، الحقول المحسوبة على كل صف، البحث لكل صف، والفلاتر غير المؤشرة يمكن أن تحول تقريرًا عاديًا إلى مهلة وقت. ملفات PDF خطرة بشكل خاص لأنها تتطلب تنسيقًا، خطوطًا، صورًا، فواصل صفحات، وغالبًا استعلامات إضافية لجمع بيانات مرتبطة.
المحاولات المتكررة غالبًا تجعل الأمور أسوأ. عندما يحدث تحديث الصفحة أو يضغط المستخدم Export مرة أخرى، قد يبدأ النظام نفس العمل مرتين. الآن قاعدة البيانات تشغّل استعلامات مكررة، وخادم التطبيق يبني ملفات مكررة، ويحدث ضغط عندما يكون النظام بالفعل تحت حمل.
إذا أردت منع انتهاء مهلة التصدير، عامل التصدير كمهمة خلفية وليس كتحميل صفحة عادي. حتى في أداة بدون كود مثل AppMaster، النمط أهم من الأداة: العمل الطويل يحتاج تدفقًا مختلفًا عن "اضغط زر، انتظر الاستجابة."
اختر نمط التصدير المناسب لتطبيقك
معظم حالات فشل التصدير تحدث لأن التطبيق يستخدم نمطًا واحدًا لكل الحالات، حتى عندما يختلف حجم البيانات ووقت المعالجة كثيرًا.
تصدير متزامن بسيط (يضغط المستخدم، الخادم يولد الملف، يبدأ التحميل) مناسب عندما يكون التصدير صغيرًا ويمكن التنبؤ به. فكر في بضع مئات من الصفوف، أعمدة أساسية، لا تنسيقات ثقيلة، وعدد قليل من المستخدمين في نفس الوقت. إذا أنهى دائمًا خلال ثانيتين إلى ثلاث ثوانٍ، البساطة عادةً الأفضل.
لأي شيء طويل أو غير متوقع، استخدم وظائف تصدير غير متزامنة. هذا يناسب مجموعات البيانات الكبيرة، الحسابات المعقدة، عمل تخطيط PDF، والخوادم المشتركة حيث يمكن أن يحجب تصدير بطيء الطلبات الأخرى.
الوظائف غير المتزامنة مناسبة عندما:
- التصديرات تستغرق بانتظام أكثر من 10 إلى 15 ثانية
- يطلب المستخدمون نطاقات زمنية واسعة أو "كل الوقت"
- تولّد PDFs مع رسوم بيانية، صور، أو صفحات عديدة
- فرق متعددة تقوم بالتصدير خلال ساعات الذروة
- تحتاج إلى إعادة محاولات آمنة عند فشل شيء ما
يمكن أن تساعد التنزيلات المتدفقة أيضًا عندما يكون الملف كبيرًا لكن يمكن إنتاجه بالتتابع. يبدأ الخادم بإرسال البايتات فورًا، مما يشعر بسرعة ويجنب بناء الملف كاملًا في الذاكرة أولًا. هذا ممتاز لتنسيقات CSV الطويلة، لكنه أقل فائدة إذا كان يجب حساب كل شيء قبل كتابة السطر الأول.
يمكنك دمج الأساليب: شغّل وظيفة غير متزامنة لتوليد التصدير (أو إعداد لقطة)، ثم قم ببث التنزيل عندما يصبح جاهزًا. في AppMaster، نهج عملي هو إنشاء سجل "Export Requested"، توليد الملف في عملية backend، وترك المستخدم يحمل النتيجة النهائية دون إبقاء طلب المتصفح مفتوحًا.
خطوة بخطوة: بناء وظيفة تصدير غير متزامنة
التغيير الأكبر بسيط: توقف عن توليد الملف داخل نفس الطلب الذي يضغط فيه المستخدم.
تقسم وظيفة التصدير غير المتزامنة العمل إلى جزأين: طلب سريع ينشئ وظيفة، وعمل في الخلفية يبني الملف بينما يبقى التطبيق مستجيبًا.
تدفق عملي من 5 خطوات
- سجل طلب التصدير (من طلب، الفلاتر، الأعمدة المختارة، صيغة الإخراج).
- أنشئ سجل وظيفة مع حالة (queued, running, done, failed)، الطوابع الزمنية، وحقل خطأ.
- نفّذ العمل الثقيل في الخلفية باستخدام قائمة انتظار، عامل مجدول، أو عملية عامل مخصصة.
- اكتب النتيجة إلى التخزين (object storage أو مخزن ملفات)، ثم احفظ مرجع التحميل في سجل الوظيفة.
- أخطر المستخدم عند الجاهزية بإشعار داخل التطبيق، بريد إلكتروني، أو قناة رسالة يستخدمها فريقك.
اجعل سجل الوظيفة مصدر الحقيقة. إذا حدّث المستخدم الصفحة، غيّر الجهاز، أو أغلق التبويب، يمكنك عرض نفس حالة الوظيفة وزر التحميل نفسه.
مثال: مدير الدعم يصدر كل التذاكر للربع السابق. بدلًا من الانتظار على تبويب يدور، يرى إدخال وظيفة ينتقل من queued إلى done، ثم يظهر التحميل. في AppMaster يمكنك نمذجة جدول الوظائف في Data Designer، بناء المنطق الخلفي في Business Process Editor، واستخدام حقل الحالة للتحكم في واجهة المستخدم.
مؤشرات تقدم يثق بها المستخدمون
مؤشر تقدم جيد يقلل القلق ويمنع الناس من الضغط على Export خمس مرات. كما يساعد في منع انتهاء المهلات بشكل غير مباشر لأن المستخدمين أكثر رغبة في الانتظار عندما يظهر التطبيق تقدمًا حقيقيًا.
اعرض التقدم بمصطلحات يفهمها الناس. النسبة المئوية وحدها غالبًا مضللة، فاقترن بشيء ملموس:
- الخطوة الحالية (Preparing data, Fetching rows, Building file, Uploading, Ready)
- الصفوف المعالجة من الإجمالي (أو الصفحات المعالجة)
- وقت البدء وآخر تحديث
- الوقت المقدر المتبقي (فقط إن بقي مستقرًا بشكل معقول)
تجنب الدقة الكاذبة. إذا لم تعرف إجمالي العمل بعد، لا تظهر 73%. استخدم معالم أولاً، ثم انتقل إلى النسبة عندما تعرف المقسوم عليه. نمط بسيط هو 0% إلى 10% للإعداد، 10% إلى 90% بناءً على الصفوف المعالجة، و90% إلى 100% لإنهاء الملف. لملفات PDF ذات أحجام صفحات متغيرة، تتبع حقائق أصغر مثل "السجلات المصوّرة" أو "الأقسام المكتملة."
حدّث الحالة بتواتر يشعر بأنها حية، لكن ليس بتواتر يضغط قاعدة البيانات أو قائمة الانتظار. نهج شائع هو كتابة التقدم كل 1 إلى 3 ثوانٍ، أو كل N صفوف (مثل كل 500 أو 1,000 صف)، أيهما أقل تكرارًا. أيضًا سجّل طابع قلب نابض خفيف حتى تقول الواجهة "لا يزال يعمل" حتى لو لم تتحرك النسبة.
امنح المستخدمين تحكمًا عندما يستغرق الأمر أطول من المتوقع. اسمح لهم بإلغاء التصدير الجاري، بدء واحد جديد دون فقدان الأول، وعرض سجل التصديرات مع الحالة (Queued, Running, Failed, Ready) بالإضافة إلى رسالة خطأ قصيرة.
في AppMaster، سجل نموذجي يبدو كـ ExportJob (status, processed_count, total_count, step, updated_at). الواجهة تستطلع ذلك السجل وتعرض تقدمًا صادقًا بينما تولّد الوظيفة الملف في الخلفية.
الترقيم والتصفية للحفاظ على عمل محدود
معظم انتهاء مهلات التصدير يحدث لأن التصدير يحاول فعل كل شيء دفعة واحدة: صفوف كثيرة، أعمدة كثيرة، روابط متعددة. أسهل تصحيح هو إبقاء العمل محدودًا حتى يصدر المستخدم جزءًا أصغر وأكثر وضوحًا من البيانات.
ابدأ من هدف المستخدم. إذا احتاج أحدهم "فواتير الشهر الماضي التي فشلت"، لا اجعل الافتراضي "كل الفواتير على الإطلاق". اجعل الفلاتر تبدو عادية، ليست عبئًا. نطاق تاريخ بسيط مع حالة غالبًا يقطع مجموعة البيانات بنسبة 90%.
نموذج طلب تصدير جيد عادةً يتضمن نطاق تاريخ (افتراضات معقولة مثل آخر 7 أو 30 يومًا)، حالة أو حالتين رئيسيتين، بحث اختياري أو اختيار عميل/فريق، ومعاينة عدد عندما يكون ذلك ممكنًا (حتى لو كانت تقديرية).
على جهة الخادم، اقرأ البيانات على شرائح باستخدام الترقيم (pagination). هذا يحافظ على ذاكرة مستقرة ويعطيك نقاط تحقق طبيعية للتقدم. دائمًا استخدم ترتيبًا ثابتًا عند الترقيم (مثلاً order by created_at, then id). بدون ذلك، قد تدخل صفوف جديدة في صفحات سابقة وتفقد أو تكرر سجلات.
البيانات تتغير أثناء التصديرات الطويلة، لذا قرّر ماذا يعني "متسق". نهج بسيط هو تسجيل وقت لقطة عند بدء الوظيفة، ثم تصدير الصفوف حتى ذلك الطابع الزمني فقط. إذا كنت تحتاج اتساقًا صارمًا، استخدم قراءة متسقة أو معاملة حيث تدعمها قاعدة البيانات.
في أداة بدون كود مثل AppMaster، هذا يترجم بشكل واضح إلى عملية تجارية: تحقق من الفلاتر، عيّن وقت اللقطة، ثم كرر عبر الصفحات حتى لا يبقى شيء للقراءة.
بث التنزيلات بدون كسر الخادم
البث يعني أنك تبدأ بإرسال الملف للمستخدم بينما لا تزال تولده. لا يحتاج الخادم لبناء CSV أو PDF كامل في الذاكرة أولًا. إنها واحدة من أكثر الطرق الموثوقة لمنع انتهاء مهلات التصدير عندما تصير الملفات كبيرة.
البث لا يجعل الاستعلامات البطيئة أسرع بشكل سحري. إذا استغرق عمل قاعدة البيانات خمس دقائق قبل أن يصبح أول بايت جاهزًا، قد ينتهي الطلب بمهلة. التصحيح المعتاد هو دمج البث مع الترقيم، بحيث تُجلب شريحة، تُكتب، وتستمر.
للحفاظ على ذاكرة منخفضة، اكتب أثناء التقدم. ولّد شكلًا واحدًا (مثلاً 1,000 صف CSV أو صفحة PDF واحدة)، اكتبها في الاستجابة، ثم افرغ so the client keeps receiving data. تجنب جمع الصفوف في مصفوفة كبيرة "فقط لتقوم بفرز لاحقًا." إذا احتجت ترتيبًا حتميًا، افرز في قاعدة البيانات.
الرؤوس، الأسماء وأنواع المحتوى
استخدم رؤوسًا واضحة حتى يتعامل المتصفح والتطبيقات المحمولة مع التنزيل بشكل صحيح. عيّن نوع المحتوى الصحيح (مثل text/csv أو application/pdf) واسم ملف آمن. يجب أن تتجنب الأسماء أحرفًا خاصة، تبقى قصيرة، وتشتمل على طابع زمني إذا كان المستخدمون يصدرون نفس التقرير عدة مرات.
الاستئناف والتنزيلات الجزئية
قرّر مبكرًا إن كنت تدعم الاستئناف. البث الأساسي غالبًا لا يدعم استئناف الطيف البايتي، خصوصًا للـ PDFs المولّدة. إذا دعمت ذلك، يجب عليك التعامل مع طلبات Range وتوليد مخرجات متسقة لنفس الوظيفة.
قبل الإطلاق، تأكد من:
- إرسال الرؤوس قبل كتابة الجسم، ثم الكتابة على دفعات وافراغها
- إبقاء أحجام القطع ثابتة حتى تبقى الذاكرة ثابتة تحت الحمل
- استخدام ترتيب حتمي حتى يثق المستخدمون بالمخرجات
- توضيح ما إذا كان الاستئناف مدعومًا وما يحدث إذا انقطع الاتصال
- إضافة حدود على جانب الخادم (حد أقصى للصفوف، زمن أقصى) وإرجاع خطأ ودي عند الوصول لها
إذا بنت التصديرات في AppMaster، احتفظ بمنطق التوليد في تدفق خلفي وابث من جهة الخادم، لا من المتصفح.
تكتيكات عملية لتصديرات CSV كبيرة
لـ CSV كبير، توقف عن التعامل مع الملف كقطعة واحدة. ابنِه كحلقة: اقرأ شريحة من البيانات، اكتب صفوفًا، كرّر. هذا يحافظ على ذاكرة ثابتة ويجعل إعادة المحاولة أكثر أمانًا.
اكتب صف CSV صفًا صفًا. حتى لو كنت تولّد التصدير في وظيفة غير متزامنة، تجنّب "جمع كل الصفوف ثم stringify." احتفظ بكاتب مفتوح وأضف كل صف فورًا عند الجاهزية. إذا يدعم نظامك مؤشرات قاعدة بيانات أو الترقيم بالصفحات، استخدمها حتى لا تحمل ملايين السجلات دفعة واحدة.
صحة CSV مهمة بقدر السرعة. الملف قد يبدو سليمًا حتى يفتحه شخص ما في Excel فتختل أعمدة.
قواعد CSV التي تمنع الملفات المكسورة
- اهرب من الفواصل، الاقتباسات والأسطر الجديدة دائمًا (غلف الحقل بالكامل باقتباس، وضع اقتباسًا مزدوجًا لأي اقتباس داخلي)
- أخرج UTF-8 واختبر الأسماء غير الإنجليزية من النهاية إلى النهاية
- استخدم صف رأس ثابت وحافظ على ترتيب الأعمدة ثابتًا عبر التشغيلات
- نمّط التواريخ والأرقام العشرية (اختر صيغة واحدة والتزم بها)
- تجنّب الصيغ إذا كان الحقل قد يبدأ بـ = أو + أو - أو @
الأداء غالبًا يموت عند الوصول إلى البيانات، لا عند الكتابة. راقب N+1 lookups (مثل تحميل كل عميل داخل حلقة). جلب البيانات المرتبطة في استعلام واحد، أو قم بتحميل ما تحتاجه مسبقًا، ثم اكتب الصفوف.
عندما تكون التصديرات ضخمة فعلاً، قسّمها عمدًا. نهج عملي هو ملف واحد لكل شهر، لكل عميل، أو لكل نوع كيان. "5 سنوات من الطلبات" يمكن أن تصبح 60 ملفًا شهريًا، كل ملف يولد مستقلاً، حتى لا يحجب شهر بطيء كل شيء.
إذا كنت تستخدم AppMaster، نمذج مجموعة البيانات في Data Designer وشغّل التصدير كعملية خلفية تكتب الصفوف أثناء الترقيم عبر السجلات.
تصدير PDF كبير: اجعله قابلًا للتوقع
توليد PDF أبطأ عادةً من CSV لأنه مكثف على المعالج. أنت لا تنقل بيانات فقط، بل تنسق صفحات، تضع خطوطًا، ترسم جداولًا وغالبًا تغيّر أحجام الصور. عامل الـ PDF كمهمة خلفية بحدود واضحة، لا كاستجابة سريعة.
اختيارات القالب تحدد ما إذا كان تصدير دقيقتين يصبح عشرين دقيقة. التصاميم البسيطة تفوز: أعمدة أقل، جداول متداخلة أقل، وفواصل صفحات متوقعة. الصور من أسرع الأشياء إبطاءً للعمل، خصوصًا إن كانت عالية الدقة أو محمّلة من مستودع بعيد أثناء التصيير.
قرارات القالب التي تحسّن السرعة والموثوقية عادةً:
- استخدم خطًا أو خطين وتجنب سلاسل بدائل ثقيلة
- اجعل الرؤوس والتذييلات بسيطة (تجنّب رسوم بيانية ديناميكية على كل صفحة)
- فضّل الأيقونات المتجهية على الصور النقطية الكبيرة
- حدّ من تخطيطات "الملاءمة التلقائية" التي تعيد قياس النص عدة مرات
- تجنّب الشفافية المعقّدة والظلال
للتصديرات الكبيرة، صيّر على دفعات. ولّد قسمًا واحدًا أو نطاق صفحات صغيرًا في كل مرة، اكتبها إلى ملف مؤقت، ثم اجمع الـ PDF النهائي. هذا يحافظ على ذاكرة ثابتة ويجعل إعادة المحاولة آمنة إذا تعطل عامل في منتصف الطريق. كما يتوافق جيدًا مع الوظائف غير المتزامنة والتقدم الذي يتحرك في خطوات مفهومة (مثل: "تحضير البيانات"، "تصيير الصفحات 1-50"، "إنهاء الملف").
واستجوب إن كان الـ PDF هو ما يحتاجه المستخدم فعلاً. إذا كانوا يريدون صفوفًا وأعمدة للتحليل، قدّم CSV جنبًا إلى جنب مع "Export PDF." يمكنك أيضًا توليد ملخص PDF أصغر للتقارير بينما تبقي مجموعة البيانات الكاملة في CSV.
في AppMaster، هذا ينسجم طبيعيًا: شغّل توليد PDF كوظيفة خلفية، بلّغ عن التقدم، وسلم الملف النهائي للتنزيل بعد إكمال الوظيفة.
أخطاء شائعة تسبب انتهاء المهلات
فشل التصدير عادةً ليس غامضًا. بعض القرارات تعمل جيدًا مع 200 صف، ثم تنهار عند 200,000.
الأخطاء الأكثر شيوعًا:
- تنفيذ التصدير كله داخل طلب ويب واحد. المتصفح ينتظر، عامل الخادم يبقى مشغولًا، وأي استعلام بطيء أو ملف كبير يدفعك عبر الحدود الزمنية.
- عرض التقدم استنادًا إلى الزمن بدلاً من العمل. مؤقت يتسابق إلى 90% ثم يتوقف يجعل المستخدمين يحدثون الصفحة، يلغون، أو يبدؤون تصديرًا آخر.
- قراءة كل صفوف الذاكرة قبل كتابة الملف. سهل التنفيذ، وطريقة سريعة لضرب حدود الذاكرة.
- الاحتفاظ بمعاملات قاعدة بيانات طويلة أو تجاهل الأقفال. استعلامات التصدير قد تحجب الكتابات، أو تُحجب بواسطة كتابات، وبطءها ينعكس على التطبيق.
- السماح بتصديرات غير محدودة بدون تنظيف. النقرات المتكررة تكدس الوظائف، تملأ التخزين، وتترك ملفات قديمة بلا حاجة.
مثال ملموس: قائد الدعم يصدر كل التذاكر للسنتين الماضيتين ويضغط مرتين لأن لا شيء يبدو أنه يحدث. الآن تصديران متطابقان يتنافسان على نفس قاعدة البيانات، كلاهما يبني ملفات ضخمة في الذاكرة، وكلاهما ينتهي بمهلة.
إذا كنت تبني هذا في أداة بدون كود مثل AppMaster، نفس القواعد تنطبق: أبقِ التصديرات خارج مسار الطلب، تتبع التقدم حسب الصفوف المعالجة، اكتب المخرجات أثناء التقدم، وضع حدود بسيطة حول عدد التصديرات التي يمكن للمستخدم تشغيلها في آنٍ واحد.
فحوصات سريعة قبل الإطلاق
قبل إطلاق ميزة التصدير للإنتاج، قم بجولة سريعة بعقلية المؤقت. العمل الطويل يحدث خارج الطلب، يرى المستخدم تقدمًا صادقًا، والخادم لا يحاول فعل كل شيء دفعة واحدة.
قائمة تحقّق سريعة قبل الإطلاق:
- التصديرات الكبيرة تعمل كوظائف خلفية (الصغيرة يمكن أن تكون تزامنية إذا كانت تنتهي بسرعة)
- المستخدمون يرون حالات واضحة مثل queued, running, done, أو failed، مع طوابع زمنية
- تُقرأ البيانات على دفعات مع ترتيب ثابت (مثلاً وقت الإنشاء زائد فاصل تعادل
id) - يمكن تحميل الملفات المنتهية لاحقًا دون إعادة تشغيل التصدير، حتى لو أغلق المستخدم التبويب
- هناك حد وخطة تنظيف للملفات القديمة وتاريخ الوظائف (حذف بناءً على العمر، حد وظائف لكل مستخدم، حدود تخزين)
فحص صحة جيد هو تجربة أسوأ حالة: صدر أكبر نطاق زمن تسمح به بينما شخص آخر يضيف سجلات. إذا رأيت تكرارات، صفوف مفقودة، أو تقدم متوقف، ترتيبك أو تقسيمك ليس ثابتًا.
إذا بنيت على AppMaster، هذه الفحوصات تتطابق مع قطع حقيقية: عملية خلفية في Business Process Editor، سجل وظيفة التصدير في قاعدة البيانات، وحقل حالة تقرأه الواجهة وتحدّثه.
اجعل الفشل يبدو آمناً. يجب أن تحتفظ الوظيفة الفاشلة برسالة الخطأ، تسمح بإعادة المحاولة، وتتجنّب إنشاء ملفات جزئية تبدو "مكتملة" لكنها ناقصة.
مثال: تصدير سنوات من البيانات دون تجميد التطبيق
مدير العمليات يحتاج إلى تصديرين كل شهر: CSV لآخر سنتين من الطلبات للتحليل، ومجموعة PDF شهرية للفواتير للمحاسبة. إذا حاول تطبيقك بناء أي منهما خلال طلب ويب عادي، ستصل في النهاية إلى حدود الوقت.
ابدأ بتحديد العمل. شاشة التصدير تطلب نطاق تاريخ (افتراضي: آخر 30 يومًا)، فلاتر اختيارية (حالة، منطقة، مندوب مبيعات)، وخيار أعمدة واضح. هذا التغيير وحده كثيرًا ما يحول مشكلة 2 سنة و2 مليون صف إلى شيء يمكن التحكم به.
عندما يضغط المستخدم Export، ينشئ التطبيق سجل Export Job (type, filters, requested_by, status, progress, error_text) ويضعه في قائمة الانتظار. في AppMaster، هذا نموذج بيانات في Data Designer بالإضافة إلى Business Process يعمل في الخلفية.
أثناء تشغيل الوظيفة، تعرض الواجهة حالة يثق بها المستخدم: queued, processing (مثلاً 3 من 20 chunks), generating file, ready (زر تحميل)، أو failed (خطأ واضح وإعادة محاولة).
التقسيم هو التفصيل الرئيسي. مهمة CSV تقرأ الطلبات على صفحات (مثلاً 50,000 صف في كل مرة)، تكتب كل صفحة إلى المخرجات، وتحدّث التقدم بعد كل قطعة. مهمة PDF تعمل بالمثل على دفعات الفواتير (مثلاً شهر واحد في كل مرة)، حتى لا يحجب شهر بطيء كل شيء.
إذا انهار شيء (فلتر خاطئ، إذن مفقود، خطأ تخزين)، تُعلَن الوظيفة Failed برسالة قصيرة يمكن للمستخدم التعامل معها: "تعذّر توليد فواتير مارس. الرجاء إعادة المحاولة، أو تواصل مع الدعم مع Job ID 8F21." تعيد المحاولة استخدام نفس الفلاتر فلا يضطر المستخدم للبدء من جديد.
خطوات لاحقة: اجعل التصديرات ميزة مدمجة لا حالة طوارئ
أسرع طريقة لمنع انتهاء مهلات التصدير طويل الأمد هي التوقف عن اعتبار التصديرات زرًا مرة واحدة واجعلها ميزة معيارية بنمط متكرر.
اختر نهجًا افتراضيًا واستخدمه في كل مكان: وظيفة غير متزامنة تولّد ملفًا في الخلفية، ثم يحصل المستخدم على خيار تحميل عندما يصبح جاهزًا. هذا القرار الواحد يزيل معظم مفاجآت "اشتغل في الاختبار" لأن طلب المستخدم لا يحتاج الانتظار حتى اكتمال الملف.
سهّل على المستخدمين العثور على ما سبق توليده. صفحة سجل التصديرات (لكل مستخدم، لكل مساحة عمل، أو لكل حساب) تقلل التصديرات المتكررة، تساعد فرق الدعم على الإجابة عن "أين ملفي؟"، وتمنحك مكانًا طبيعيًا لعرض الحالة، الأخطاء، والانتهاء.
إذا كنت تبني هذا النمط داخل AppMaster، يفيدك أن المنصة تولد شفرة مصدر فعلية وتدعم منطق الخلفية، نمذجة قواعد البيانات، وواجهة ويب/موبايل في مكان واحد. للفرق التي تريد شحن وظائف تصدير غير متزامنة موثوقة سريعًا، يُستخدم appmaster.io كثيرًا لبناء جدول الوظائف، عملية الخلفية، وواجهة تقدم التحديثات دون توصيل كل شيء يدويًا.
ثم قِس ما يضر فعلًا. تتبع الاستعلامات البطيئة، زمن توليد CSV، وزمن تصيير PDF. لست بحاجة إلى رصد مثالي لتبدأ: سجل مدة التشغيل وأعداد الصفوف لكل تصدير سيظهر بسرعة أي تقرير أو مجموعة فلاتر هي المشكلة الحقيقية.
عامل التصديرات كأي ميزة منتج أخرى: متسقة، قابلة للقياس، وسهلة الدعم.
الأسئلة الشائعة
يحدث انتهاء مهلة التصدير عندما لا ينتهي العمل قبل حد زمني محدد في مسار الطلب. هذا الحد قد يأتي من المتصفح، عكس وكيل (reverse proxy)، خادم التطبيق، أو اتصال قاعدة البيانات، لذلك قد يبدو عشوائياً حتى لو كان السبب الجذري مرتبطاً بتحميل ثابت أو استعلامات بطيئة.
استخدم تصديرًا تزامنيًا بسيطًا فقط عندما يكون من المؤكد أنه ينتهي خلال ثانيتين أو ثلاث reliably وبحجم بيانات متوقع. إذا كانت التصديرات عادةً تأخذ أكثر من 10–15 ثانية، أو تشمل نطاقات زمنية كبيرة، حسابات مكلفة، أو ملفات PDF مع تنسيقات ورسومات، فانتقل إلى وظيفة غير متزامنة حتى لا يظل طلب المتصفح مفتوحًا.
أنشئ سجلًا للوظيفة أولاً، ثم نفّذ العمل الثقيل في الخلفية، وفي النهاية اترك للمستخدم تحميل الملف النهائي. في AppMaster، الإعداد الشائع هو نموذج ExportJob في Data Designer وعملية خلفية في Business Process تحدث حقل status وحقول التقدم وتخزن مرجع الملف أثناء التشغيل.
تتبّع العمل الفعلي، لا الوقت المنقضي فقط. نهج عملي هو تخزين حقول مثل step، processed_count، total_count (عند المعرفة)، وupdated_at، ثم تجعل الواجهة تستطلع هذه الحقول وتعرض حالات واضحة حتى لا يشعر المستخدم أنه عالق ويضغط التصدير مرارًا.
اجعل طلب التصدير آي-ديمبوتنت (idempotent) وخذ سجل الوظيفة كمصدر الحقيقة. إذا ضغط المستخدم مرة أخرى، اعرض الوظيفة الجارية الموجودة (أو امنع التكرارات لنفس الفلاتر) بدلاً من بدء نفس العمل المكلف مرتين.
اقرأ واكتب على دفعات حتى تبقى الذاكرة ثابتة وتحصل على نقاط تحقق طبيعية. استخدم ترقيم صفحات ثابتًا مع ترتيب حتمي (مثلاً بالترتيب حسب created_at ثم id) حتى لا تفوّت أو تكرر صفوفًا عندما تتغير البيانات أثناء التصدير الطويل.
سجّل وقت لقطة (snapshot) عند بدء الوظيفة وصدر فقط الصفوف حتى ذلك الطابع الزمني حتى لا "يتحرك" الناتج أثناء التشغيل. إذا كنت تحتاج ضمانات أقوى، استخدم القراءات المتسقة أو استراتيجيات المعاملات التي تدعمها قاعدة بياناتك، لكن ابدأ بقواعد لقطة واضحة يفهمها المستخدمون.
البث مفيد عندما يمكنك إنتاج المخرجات بالترتيب وبدء إرسال البايتات مبكرًا، خاصة لملفات CSV الكبيرة. لكنه لن يصلح استعلامات بطيئة تأخذ دقائق قبل أول بايت، ويمكن أن ينتهي القالب بنفسه إذا لم يُكتب شيء لفترة طويلة، لذا يعمل البث أفضل عند دمجه مع التقسيم الذي يكتب دفعات مستمرة.
اكتب الصفوف أثناء الوصول إليها واتبع قواعد الهروب في CSV حتى لا يتلف الملف عند فتحه في Excel أو أدوات أخرى. حافظ على ترميز ثابت (عادة UTF-8)، صف رأس ثابت وترتيب أعمدة ثابت، وتجنّب عمليات البحث لكل صف التي تحوّل تصديرًا واحدًا إلى آلاف الاستعلامات الإضافية.
توليد PDF مكلف CPU لأنّه يتضمن تخطيطًا، خطوطًا، صورًا وتقسيم صفحات، لذلك عالجه كوظيفة في الخلفية مع حدود واضحة. اجعل القوالب بسيطة، تجنب الصور الكبيرة أو المستضافة عن بُعد أثناء التصيير، وأبلغ عن التقدم في خطوات مفهومة حتى يعرف المستخدم أن العملية تعمل.


