أخبار التقنية التقنية بلغة عربية واضحة
تحديث تقني Laravel وPHP

Laravel Chores لإجراء عمليات البيانات الطويلة مع الاستئناف بعد التوقف

حزمة Laravel Chores الجديدة من Amr Lotfy Saleh تساعد مطوري Laravel على تنفيذ عمليات مثل backfill وتنظيف البيانات والحذف الدوري على دفعات تحفظ تقدّمها في قاعدة البيانات. عند توقف العملية بسبب deploy أو crash أو Ctrl+C، يمكن تشغيلها مجدداً لتتابع من آخر دفعة مكتملة، مع تسجيل السجلات الفاشلة بشكل منفصل.

المصدر: Laravel News
Laravel Chores لإجراء عمليات البيانات الطويلة مع الاستئناف بعد التوقف
Laravel

أبرز النقاط

  • تحفظ Laravel Chores آخر ID بعد كل batch في جدول `chore_runs`، لتستأنف العمليات المتوقفة من آخر نقطة تقدّم.
  • تستخدم الحزمة keyset pagination بالمفتاح الأساسي بدلاً من offset، ما يناسب تحديث السجلات أثناء معالجتها.
  • السجل الذي يفشل لا يوقف المهمة؛ يُسجل في جدول failures ويمكن فحصه أو إعادة محاولة معالجته لاحقاً.
  • تعمل الحزمة من دون Redis أو Queue workers، إذ تحفظ حالتها بالكامل في قاعدة البيانات.
  • تتضمن أوامر Artisan لإنشاء Chore وتشغيلها وإيقافها وعرضها وفحص الإخفاقات وإعادة المحاولة.
  • تتطلب PHP 8.2+ وLaravel 12 أو 13، وتدعم MySQL وPostgreSQL وSQLite.

عمليات البيانات الكبيرة لا تفشل دائماً بسبب الاستعلام نفسه؛ أحياناً يكفي deploy بعد ساعات من التشغيل كي تصبح معرفة السجلات التي عولجت بالفعل مشكلة بحد ذاتها. حزمة Laravel Chores تقدّم طريقة منظمة لتشغيل أعمال لمرة واحدة أو دورية، مثل backfills وعمليات التنظيف والحذف، عبر دفعات تحتفظ بنقطة تقدّم قابلة للاستئناف.

الحزمة، التي طوّرها Amr Lotfy Saleh، تكتب آخر ID تمت معالجته في جدول chore_runs بعد كل batch. لذلك، إذا انقطعت العملية بسبب crash أو إيقاف يدوي عبر Ctrl+C أو إعادة تشغيل أثناء deploy، فإن التشغيل التالي يستأنف من آخر checkpoint بدلاً من بدء المهمة من الصفر. لكن هذا الضمان يكون على مستوى الدفعة، لا السجل المفرد؛ فقد تُفحص سجلات الدفعة التي كانت قيد التنفيذ مرة أخرى بعد الاستئناف. لهذا يُنصح بأن تكون دالة process() idempotent قدر الإمكان.

تعتمد Laravel Chores على keyset pagination باستخدام المفتاح الأساسي بدلاً من offset. هذا مهم عند تعديل السجلات أثناء المرور عليها، لأن pagination المعتمدة على offset قد تؤدي إلى تخطي صفوف أو تحريكها خارج الدفعة الحالية. وتحتاج المجموعة إلى primary key قابل للترتيب، مثل auto-increment أو ULID.

كل Chore عبارة عن class يحدد دالتين أساسيتين: collection() لإرجاع query السجلات المستهدفة، وprocess() لمعالجة سجل واحد. يمكن إنشاء الهيكل المبدئي بالأمر:

php artisan make:chore

في مثال تطبيع أرقام الهواتف، يمكن أن تختار collection() المستخدمين الذين لديهم رقم هاتف لا يبدأ بـ +، ثم تحوّل process() الرقم إلى صيغة E.164. إذا لم يُحدَّد حجم الدفعة في الـ class، تستخدم الحزمة القيمة الافتراضية في ملف الإعدادات، وهي 500.

لتشغيل مهمة، يُستخدم الأمر php artisan chore:run NormalizePhoneNumbers، مع عرض تقدّم مباشر في الطرفية. كما توفر الحزمة أوامر لعرض المهام وسجل تشغيلها، وإيقاف مهمة عند نهاية الدفعة التالية، وفحص السجلات الفاشلة ثم إعادة محاولة معالجتها. إذا تسبب سجل واحد في exception، تسجل الحزمة السجل والخطأ في جدول failures وتتجاوز السجل لتواصل بقية التشغيل.

هذا الفصل بين التشغيل الرئيسي وإعادة المحاولة مفيد في المهام الطويلة: أخطاء عدد محدود من السجلات لا تعني إهدار ساعات من المعالجة، ويمكن إعادة محاولة السجلات التي فشلت بعد إصلاح سبب المشكلة بدلاً من إعادة المهمة كاملة.

لا تحتاج Laravel Chores إلى Redis أو Queue workers أو خدمات خارجية، إذ تحفظ حالتها في قاعدة البيانات. وتعمل حالياً في foreground مع worker واحد لكل chore. أما queued execution والـ parallel workers فمذكوران ضمن خارطة الطريق. وللمهام المتكررة، يمكن تشغيل الأمر من Laravel task scheduler، مثل مهمة شهرية لحذف السجلات المنتهية.

توفر الحزمة أيضاً مخرجات JSON مناسبة لـ CI، مع exit code بقيمة 0 عند نجاح التشغيل دون أخطاء، و1 عند اكتماله مع وجود سجلات فاشلة، و2 عند حدوث خطأ fatal.

تتطلب Laravel Chores كلاً من PHP 8.2 أو أحدث وLaravel 12 أو 13، وتدعم MySQL وPostgreSQL وSQLite. يبدأ التثبيت عبر:

composer require amrlotfy/laravel-chores

ثم نشر migrations وتشغيلها عبر php artisan vendor:publish --tag=chores-migrations وphp artisan migrate. ويمكن من ملف الإعدادات تعديل مسار classes وحجم الدفعة الافتراضي وأسماء الجداول وفاصل زمني بين الدفعات لتخفيف الحمل على قاعدة بيانات مشغولة.

لماذا يهم؟

عمليات backfill أو تنظيف ملايين السجلات قد تكون حساسة للتوقفات أثناء deploy وللأخطاء الفردية في البيانات. Laravel Chores تمنح هذه العمليات مساراً قابلاً للاستئناف وتفصل السجلات الفاشلة عن بقية العمل، من دون إدخال بنية Queue أو Redis إضافية. لكن على المطور كتابة `process()` بطريقة تتحمل إعادة فحص سجلات الدفعة غير المكتملة.

#Laravel#PHP#LaravelChores#Artisan#Database#Backfill