قد يساعد في تحديد المشكلة التحقق من أي إصدار من مكتبة aws-sdk-s3 يتم تحميله فعليًا داخل الحاوية قيد التشغيل.
التغيير في Discourse الذي أدخل Aws::S3::TransferManager قام أيضًا بترقية aws-sdk-s3 من 1.182.0 إلى 1.227.0:
في إصدار Discourse الذي أشرت إليه، يجب أن يكون ملف Gemfile.lock لا يزال يستخدم aws-sdk-s3 الإصدار 1.227.0، والذي يوفر Aws::S3::TransferManager.
هل يمكنك محاولة الدخول إلى الحاوية:
cd /var/discourse
./launcher enter app
ثم، داخل الحاوية:
cd /var/www/discourse
bundle info aws-sdk-s3
bundle exec ruby -e '
require "aws-sdk-s3"
puts "gem: #{Gem.loaded_specs["aws-sdk-s3"]&.full_name}"
puts "path: #{Gem.loaded_specs["aws-sdk-s3"]&.full_gem_path}"
p Aws::S3.autoload?(:TransferManager)
p Aws::S3::TransferManager
'
قد يكون من المفيد أيضًا التحقق من التطبيق نفسه تحت بيئة Rails:
RAILS_ENV=production bundle exec rails runner '
puts "aws-sdk-s3: #{Gem.loaded_specs["aws-sdk-s3"]&.version}"
p Aws::S3.autoload?(:TransferManager)
p Aws::S3::TransferManager
'
ثم اترك الحاوية باستخدام الأمر:
logout
إذا أفاد الأمر بإصدار أقدم من aws-sdk-s3، أو إذا كان TransferManager مفقودًا،
فسيفسر ذلك استثناء النسخ الاحتياطي، وسيشير إلى أن المكتبات المثبتة في الحاوية لا تتطابق مع ملف Gemfile.lock الحالي لـ Discourse.
إذا أفاد الأمر بالإصدار 1.227.0 ونجح في حل Aws::S3::TransferManager، فإن المشكلة تكون أكثر غرابة، وسنعرف أن علينا النظر فيما يختلف بين عملية النسخ الاحتياطي في Sidekiq وتلك البيئة التفاعلية.
بما أنك تستخدم ./launcher rebuild app، يبدو ذلك أنه يتبع سير عمل discourse_docker القياسي؛ الأوامر المذكورة أعلاه ستخبرنا بدقة أكبر بما انتهى به الحال في الحاوية المُعاد بناؤها.
أثناء البحث في هذه المسألة، تذكّرت أنني استخدمت هذا الحل البديل للالتفاف على مشكلة عدم عمل AWS SDK مع Backblaze. بعد الاطلاع على آخر مستجدات الموضوع، يبدو أن Backblaze حدّثت واجهة برمجية (API)، مما يجعل الحل البديل غير ضروري.
بعد إزالة الحل البديل، نجحت عملية النسخ الاحتياطي! شكرًا على المساعدة.
فكرة واحدة من هذا: قد تكون قوالب التوافق المؤقتة مثل هذه أكثر أمانًا إذا كانت تحتوي على نوع من الشروط الذاتية الانتهاء أو الحماية، بدلاً من الاستمرار في تجاوز تبعيات Discourse بشكل غير محدود.
على سبيل المثال، مع عمليات الاستيراد المؤقتة للمصدر، أخطط لاستخدام الخطافات (hooks) في بيئة الإنتاج التي تتحقق أولاً مما إذا كان الإصلاح الموجود في المصدر الأصلي (upstream) موجودًا بالفعل، وتطبق الرقعة (patch) فقط إذا كانت لا تزال مطلوبة.
في هذه الحالة، كان من الممكن أن يمنع شيء على هذا الخط استمرار تثبيت aws-sdk-s3 1.177.0 القديم بمجرد أن بدأ Discourse نفسه في الاعتماد على وظائف SDK الأحدث:
hooks:
after_bundle_exec:
- exec:
cd: $home
cmd:
- |
if grep -q "Aws::S3::TransferManager" lib/s3_helper.rb; then
echo "Discourse now requires Aws::S3::TransferManager; skipping obsolete Backblaze aws-sdk-s3 downgrade"
else
echo "Applying temporary Backblaze aws-sdk-s3 compatibility pin"
bundle config set frozen false
sed -i 's/gem "aws-sdk-s3", require: false/gem "aws-sdk-s3", "1.177.0", require: false/' Gemfile
bundle update aws-sdk-s3
bundle add aws-sdk-core --version 3.215
fi
إن تلك الفحصية المحددة مجرد مثال توضيحي - من المرجح أن يكون فحص إصدارات أكثر عمومية أو فشلًا صريحًا عند تجاوز Discourse للإصدار المتوقع من SDK أفضل.
حتى الفشل بصوت عالٍ سيكون على الأرجح تفضيليًا على إنتاج حاوية بصمت حيث لم تعد جوهاتها (gems) تطابق الإصدارات التي يتوقعها Discourse.
أوافق على أنه كان من الجيد أن يفشل النظام بصوت عالٍ، لكن الأمر كان كذلك من قبل لأنني أردت ألا تتطابق الجواهر (gems) مع الإصدارات التي يتوقعها Discourse، لأن الإصدار الأحدث من aws-sdk-s3 كان يرسل ترويسات (headers) لا تدعمها Backblaze، وكنت أريد أن تعمل النسخ الاحتياطية.
لا أعلم ما إذا كان هناك فحص يمكنني ضبطه بشكل استباقي مسبقًا لإشعاري عندما لم يعد الحل البديل ضروريًا. لقد طبّقت الحل البديل قبل عام ونصف، في أبريل 2025، قبل أن يصبح الإصلاح متاحًا.
أعتقد أن أفضل ما كان بوسعي فعله هو إضافة تاريخ انتهاء، لإجباري على التحقق مما إذا كان الحل البديل لا يزال ضروريًا أم لا. قد تكون ميزة من هذا النوع مفيدة. أو ربما تقع المسؤولية على عاتقي لتكون أكثر استباقية وضبط تذكيرات للتحقق مما إذا كان الحل البديل لا يزال ضروريًا. ساعدني وجود بعض الملاحظات في هذا الصدد.