فشل النسخ الاحتياطي إلى Cloudflare R2 أثناء التحميل متعدد الأجزاء باستخدام aws-sdk-s3 1.182.0 (طريقة 'downcase' غير معرفة لـ nil)

الأولوية/الشدة:

عالية للنسخ المستضافة ذاتيًا التي تستخدم تخزين نسخ احتياطية متوافق مع S3، حيث تفشل النسخ الاحتياطية المجدولة بعد إنشاء الأرشيف.

المنصة:

Discourse مستضاف ذاتيًا على أحدث فرع.

الإصدار الحالي المباشر عند الملاحظة: v2026.4.0-latest

Ruby: 3.4.0

aws-sdk-s3: 1.182.0

الوصف:

تفشل النسخ الاحتياطية إلى Cloudflare R2 في الخطوة النهائية “جاري تحميل الأرشيف…”.

يتم إكمال عملية تصدير قاعدة البيانات وإنشاء الأرشيف المحلي بنجاح، لكن عملية التحميل متعدد الأجزاء للأرشيف النهائي تفشل.

النتيجة الفعلية:

يفشل النسخ الاحتياطي مع الرسالة:

EXCEPTION: multipart upload failed: undefined method 'downcase' for nil

يتضمن تتبع المكدس:

aws-sdk-s3-1.182.0/lib/aws-sdk-s3/multipart_file_uploader.rb
lib/backup_restore/s3_backup_store.rb:48
lib/backup_restore/creator.rb:434

النتيجة المتوقعة:

يجب أن يتم تحميل أرشيف النسخ الاحتياطي بنجاح إلى مخزن النسخ الاحتياطي المتوافق مع S3 المُهيأ.

خطوات التكرار:

  1. قم بتكوين تخزين النسخ الاحتياطي لـ Cloudflare R2 باستخدام مسار النسخ الاحتياطي المتوافق مع S3.
  2. استخدم أرشيف نسخ احتياطي أكبر من عتبة التحميل متعدد الأجزاء.
  3. قم بتشغيل نسخة احتياطية يدوية أو مجدولة.
  4. راقب الفشل أثناء “جاري تحميل الأرشيف…”.

الإعدادات ذات الصلة:

  • DISCOURSE_BACKUP_LOCATION=s3
  • DISCOURSE_S3_ENDPOINT=https://.r2.cloudflarestorage.com
  • DISCOURSE_S3_FORCE_PATH_STYLE=true
  • DISCOURSE_S3_BACKUP_BUCKET=
  • AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED
  • AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_REQUIRED

مقتطف من تتبع المكدس الملاحظ:

algorithm = resp.context.params[:checksum_algorithm]
k = "checksum_#{algorithm.downcase}".to_sym

هذا يشير إلى أن checksum_algorithm هو nil في مسار التحميل متعدد الأجزاء.

سياق إضافي:

هناك موضوع حديث مشابه على Meta للنسخ الاحتياطية إلى Backblaze B2:

أيضًا، تبدو مدخلات سجل التغييرات لـ aws-sdk-s3 بعد الإصدار 1.182.0 ذات صلة:

  • 1.201.0: إصلاح التحميل متعدد الأجزاء لاحترام وضع request_checksum_calculation عند when_required
  • 1.210.2: العودة إلى استخدام تجزئات الطلب عبر الرؤوس عند استخدام نقاط نهاية مخصصة أو موفري نقاط نهاية لعمليات PutObject و UploadPart

يبدو أن Discourse main لا يزال يقيد aws-sdk-s3 حاليًا على الإصدار 1.182.0:

https://raw.githubusercontent.com/discourse/discourse/main/Gemfile.lock

لم ألقِ نظرة على هذا منذ فترة، لكن إليك كيف تعاملت مع هذا في الماضي:

لا يعتبرونه #خطأً لأنهم لا يدّعون دعم كل خدمة غير متوافقة مع S3 على كوكب الأرض.

لا أتذكر بالضبط المواقع التي كنت أقوم بذلك لها، لكنني لا أتذكر تغيير أي شيء في هذا الأمر مؤخرًا، لذا أعتقد أن هذا لا يزال “أفضل” حل بديل.

أعتقد أن هناك بعض المواضيع الأخرى حول هذا الأمر عندما أطلقت AWS المكتبة الجديدة التي عطلت عروض الآخرين.

إعجابَين (2)

شكرًا لك، لقد حلّ هذا المشكلة بالنسبة لي.

طبقت الحل البديل مباشرة في app.yml عبر after_bundle_exec، وقمت بتثبيت إصدار aws-sdk-s3 على 1.177.0 و aws-sdk-core على 3.215، ثم أعيد بناء الحاوية. بعد ذلك، نجحت عمليات النسخ الاحتياطي اليدوي إلى Cloudflare R2 مرة أخرى، وبدأت أيضًا عمليات التحميل من المتصفح التي كانت تفشل سابقًا بالعمل بنجاح.

في حالتي، ظهرت الأخطاء على شكل multipart upload failed: undefined method 'downcase' for nil مع aws-sdk-s3 1.182.0.

أقدر الحل البديل المقدم.

إعجاب واحد (1)

تصحيح… لقد نجح هذا الحل البديل معي أيضًا، كان عليّ فقط وضعه في كتلة hooks: خاصة به وعدم إضافته إلى كتلة hooks: موجودة، يا له من غباء مني.