فشل Rake uploads:migrate_from_s3

اتبعت الخطوات هنا، ونشأت نسخة احتياطية من موقعي بالكامل، ثم قمت باستنساخ خزانة AWS S3 الخاصة بي، وغيرت اسم الخزانة في إعدادات Discourse من الخزانة الأصلية إلى النسخة الاحتياطية، وأغلقت خانة اختيار “تحميل الملفات إلى S3” في الإعدادات.

لذا فأنا مستعد أخيرًا لبدء عملية الهجرة بعيدًا عن S3… لكنها فشلت. :frowning:

رسالة الخطأ

root@ubuntu:/var/www/discourse# rake uploads:migrate_from_s3
Migrating uploads from S3 to local storage for 'default'...
rake aborted!
NoMethodError: undefined method `downcase' for nil:NilClass
/var/www/discourse/app/models/global_setting.rb:107:in `s3_bucket_name'
/var/www/discourse/app/models/site_setting.rb:157:in `absolute_base_url'
/var/www/discourse/lib/tasks/uploads.rake:138:in `migrate_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:118:in `block in migrate_all_from_s3'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.2.2/lib/rails_multisite/connection_management.rb:68:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.2.2/lib/rails_multisite/connection_management.rb:78:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:118:in `migrate_all_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:93:in `block in <top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => uploads:migrate_from_s3
(See full trace by running task with --trace)

(إليك السطر في GitHub حيث يحدث الفشل– أعتقد أنه لا يمكنه الحصول على قيمة s3_bucket؟)

أشياء أخرى جربتها

  • حاولت إضافة بيانات الاعتماد إلى سطر الأوامر، لكن ذلك لم يُحدث فرقًا. أي:
    DISCOURSE_S3_BUCKET="dn-forum-storage-backup" DISCOURSE_S3_REGION="us-east-1" DISCOURSE_S3_ACCESS_KEY_ID="xxxxxxxxxxxxxxxxxxxx" DISCOURSE_S3_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxx" DISCOURSE_S3_CDN_URL="https://dn-forum-storage-backup.s3.us-east-1.amazonaws.com" rake uploads:migrate_from_s3

  • كما جربت تغيير اسم خزانة S3 في إعداداتي إلى اسم الخزانة الأصلية، لكن دون جدوى، ونفس النتيجة.

  • كما جربت إعادة بناء التطبيق. ونفس النتيجة.

@vinothkannans هل تعرف ما الذي يحدث؟

من فضلكم ساعدوني يا أصدقاء Discourse!

ملاحظة جانبية صغيرة: rake --tasks لا يعرض هذه المهمة أو أي مهام تبدأ بـ uploads، لست متأكدًا مما إذا كان ذلك يعني شيئًا.

هل هناك مشكلة ذات صلة محتملة؟ cc @mcdanlj

@pnoeric نعم، يبدو أن الأمر بالضبط هو نفسه. لم أسمع أي رد في تلك المسألة بشأن ما هو الهدف تحديدًا من SiteSettings مقابل GlobalSettings لـ S3، لذا لا يمكنني تقديم أي مساعدة إضافية حاليًا سوى إضافته إلى SiteSettings عبر الإعدادات (النقطة 1 في منشوري).

مرحبًا، شكرًا لك على هذه الإجابة… لست متأكدًا حتى من معنى SiteSettings مقابل GlobalSettings — فليست لديّ خبرة كافية في برمجة RoR ولا أفهم الإعداد الكامل بشكل كافٍ. أنا أتبع فقط التعليمات الأساسية. :wink:

ولكن آمل أن ينضم @vinothkannans أيضًا؛ أعتقد أنه كتب الكود الخاص بمهام الهجرة. أو أي شخص آخر من فريق @team قد يكون على علم…

دعونا نبقى منتبهين لهذا الموضوع…

s3_bucket موجود في GlobalSettings، والذي يتم تعيينه عادةً من ملف config/discourse.conf الذي يُنشأ من متغيرات البيئة في ملف app.yml. أما SiteSettings فهي الإعدادات التي يمكنك تغييرها من خلال إعدادات المسؤول في التطبيق.

يبدو أنه عند إنشاء هذا لأول مرة، لم يكن بإمكانك تغيير إعدادات S3 إلا بإعادة بناء التطبيق، وفي الآونة الأخيرة أصبح من الممكن إدخال البيانات في إعدادات المسؤول. لا أستطيع تحديد ما كان المقصود بعدم إجراء ترحيل شامل عند إضافة إمكانية تعيين S3 في SiteSettings.

[تعديل: لقد عكست العنصرين بالخطأ عند نشر هذا الرد لأول مرة]

هههه، @mcdanlj، فقط للتأكيد، لم تتمكن من معرفة كيفية جعل migrate_from_s3 يعمل فعليًا، صحيح؟

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

مرحبًا @pnoeric و @mcdanlj،

قد تكون إحدى طرق التصحيح هي الدخول إلى وحدة تحكم Rails ثم إلقاء نظرة على إعدادات الموقع S2؟

على سبيل المثال، في تطبيق Docker قياسي لـ Discourse يعمل كحاوية منفردة:

root@localhost:~# docker exec -it app rails c
[1] pry(main)> SiteSetting.s3_upload_bucket
=> ""
[2] pry(main)> SiteSetting.enable_s3_uploads
=> false
[3] pry(main)

مقارنة إعدادات الموقع (عبر وحدة تحكم Rails) مع القيم الافتراضية المذكورة هنا:

ربما يكون التصحيح بهذه الطريقة مفيدًا (لا أعرف حقًا، لأننا لا نستخدم AWS أو S3)؟ ربما قد تساعد وحدة تحكم Rails قليلاً؟

أمر rake --tasks يعرض فقط المهام التي تحتوي على وصف. يمكنك عرض جميع المهام المتاحة عبر rake -AT.

لا أعتقد أن ذلك سيساعد، لأنني قمت بتشغيل هذه المهام مؤخرًا على موقع تجريبي. يبدو أن كلا الأمرين يعتمدان على تعريف متغيرات S3 في env، ومع ذلك، كان ذلك قبل بضعة أشهر ولم يعمل migrate_from_s3 بشكل جيد بالنسبة لي.

سؤال صعب. لقد قمتُ بإعداد s3_bucket في config/discourse.conf كما ذُكر في المنشور الذي أشرتَ إليه، وهو ما حلّ بالفعل هذا الخطأ المحدد، كما أشرتُ هناك.

هذا الملف موجود داخل الحاوية (./launcher enter app). لاحظ أنه لكي يبقى التغيير ساريًا بعد تشغيل ./launcher rebuild app، يجب عليك أيضًا إضافة DISCOURSE_S3_BUCKET إلى قسم env في ملف containers/app.yml الخاص بك.

حقيقة أنني قمتُ بإصلاحه هي السبب في أن هذا المنشور كان مخصصًا للمطورين وليس طلب دعم؛ كنتُ أسأل عن ما يراه المطورون أنه الحل الصحيح بينما أواصل العمل على هذا المشروع.

لدي حوالي 100 جيجابايت من الملفات في S3، لذا أنا أتحرك بحذر شديد. لقد طبقتُ حدًا للرسائل التي يتم فحصها، وأحتاج الآن إلى تطبيق حد للرسائل التي سيتم تعديلها. لقد حاولتُ تجربة شيء واحد في كل مرة. حقيقة أن هذا الكود يبدو أنه نادر الاستخدام، وقد رأيتُ هذا الخطأ مرارًا وتكرارًا، تجعلني قلقًا بشأن تدهور الكود، ولا أريد أن أتسبب فجأة في تشويه موقعي بالكامل بسبب خطأ، وهذا يبدو وكأنه طريقة جيدة لارتكاب مثل هذا الخطأ.

  • بالنسبة لـ upload:// (بالنسبة لي، هذا يعني الملفات غير الفيديو)، يبدو حتى الآن أن الأمر يعمل بشكل صحيح. أقوم بمعالجة ملف واحد في كل مرة ثم أراجع المنشور المتأثر للتأكد من أن كل شيء يعمل.

  • بالنسبة للملفات التي لا تستخدم صيغة upload:// (بالنسبة لي، هذا يعني ملفات الفيديو حسب ما أستطيع تحديده)، حيث يوجد مرجع حرفي للرابط في S3، فإن الروابط يتم تشويهها. هذا ليس خطأً صعب الإصلاح بمجرد أن أتأكد تمامًا مما يجب أن أغيره إليه، لكنني لم أفعل ذلك بعد. لذا، فمن المرجح أن يكون هذا أحد طلبات السحب (PRs) التي سأنشرها قريبًا.

هذا مشروع أقوم به في وقت فراغي، لذا لا توجد وعود بشأن التوقيت.

أهلاً، شكرًا لك! سأجرب ذلك.

أوه، لا حظ موفق بعد، @neounix @mcdanlj @vinothkannans. لا يزال الفشل قائمًا. لكن على الأقل ظهرت رسالة خطأ جديدة/مختلفة…

إليك ما جربته اليوم:

  1. الترقية إلى أحدث إصدار من Discourse، للتأكد من ذلك.

  2. إضافة s3_bucket الخاصة بي في config/discourse.conf.

  3. ./launcher enter app.

  4. تعديل containers/app.yml وإضافة متغير DISCOURSE_S3_BUCKET.

  5. محاولة تنفيذ rake uploads:migrate_from_s3 وفشل الآن برسالة خطأ جديدة (في السابق كانت المشكلة بسبب downcase، والآن يبدو أن المشكلة في start_with?):

/var/www/discourse# rake uploads:migrate_from_s3
Migrating uploads from S3 to local storage for 'default'...
rake aborted!
NoMethodError: undefined method `start_with?' for nil:NilClass
/var/www/discourse/app/models/site_setting.rb:161:in `absolute_base_url'
/var/www/discourse/lib/tasks/uploads.rake:138:in `migrate_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:118:in `block in migrate_all_from_s3'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:68:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:78:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:118:in `migrate_all_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:93:in `block in <main>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => uploads:migrate_from_s3
(See full trace by running task with --trace)
  1. ثم جربت ./launcher rebuild app.

  2. ثم مرة أخرى ./launcher enter app، ثم rake uploads:migrate_from_s3.

نفس المشكلة تمامًا:

/var/www/discourse# rake uploads:migrate_from_s3
Migrating uploads from S3 to local storage for 'default'...
rake aborted!
NoMethodError: undefined method `start_with?' for nil:NilClass
/var/www/discourse/app/models/site_setting.rb:161:in `absolute_base_url'
/var/www/discourse/lib/tasks/uploads.rake:138:in `migrate_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:118:in `block in migrate_all_from_s3'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:68:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:78:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:118:in `migrate_all_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:93:in `block in <main>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => uploads:migrate_from_s3
(See full trace by running task with --trace)

هل لديك أي أفكار أخرى؟

بالتوازي، هذه العملية مرهقة للغاية؛ يجب أن أجدول مسبقًا وأعلن عن توقف المنتدى قبل أيام، ثم في اليوم المحدد، أقوم بتغيير الموقع الرئيسي لمنع المستخدمين من الدخول إلى المنتدى، ثم أغلق خادم المنتدى على DigitalOcean وأقوم بأخذ نسخة احتياطية قبل المتابعة. هذا يستغرق حوالي 30 دقيقة فقط. ثم أعيده للعمل وأتمكن من تجربة الخطوات المذكورة أعلاه. أنا نادم جدًا على إعداد Amazon S3 لتخزين الوسائط! لقد قضيت ساعات في محاولة التراجع عن هذا القرار ولا يزال دون نجاح (ولا يزال هناك فاتورة كبيرة شهريًا من Amazon). أود حقًا معرفة السبب الجذري للمشكلة. كيف يمكنني المساعدة؟

هذا السطر هو:

        if SiteSetting.Upload.s3_region.start_with?("cn-")

يبدو أنه يتطلب أيضًا s3_region؛ ولا أستطيع فهم سبب عدم مواجهتي لهذه المشكلة من قبل.

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

لذا ربما يجب أن أكرر جميع الخطوات التي قمت بها أعلاه، لكنني سأضع s3_bucket و s3_region و s3_cnd_url و s3_secret_access_key وما إلى ذلك (في الأساس، كل متغير أملكه) في ملفات conf و yml؟ أفضل أن أعطيها أكثر مما قد تحتاجه، فقط لكي تعمل الأشياء فعليًا.

رأيت أن شخصًا ما في فريق Discourse اقترح عمل نسخة احتياطية كاملة للموقع المحلي قبل البدء في هذا الانتقال. وهو ما يتطلب مني إيقاف خادم Digital Ocean الخاص بي. :frowning:

صحيح. أنا أيضًا أبدأ بخطوات صغيرة… في كل مرة أحاول فيها، أنقل 0 ملفات. :grin:

لحسن الحظ، يُسمح للأعضاء فقط بتحميل ملفات JPG و GIF و PNG في منتداي، لذا يجب أن يكون الأمر على ما يرام.

أصابعي متشابكة على أمل النجاح.

النسخ الاحتياطي واللقطة (Snapshot) ليسا نفس الشيء. اللقطة هي أبسط شكل من أشكال النسخ الاحتياطي. يتوفر في وحدة تحكم المسؤول أداة للنسخ الاحتياطي. تأكد من إعدادها لنسخ الصور المصغرة احتياطيًا في الإعدادات أولاً.

الآن بعد أن عرفت أنه ليس عليك إيقاف موقعك، يجب أن تتمكن من الاسترخاء. يمكنك استخدام batch_migrate_from_s3 لنقل عدد محدود من الملفات المرفوعة. حاليًا، يحدد هذا الأمر المنشورات التي يتم أخذها في الاعتبار بدلاً من عمليات النقل المنفذة، وهي مشكلة أحتاج إلى حلها في طلب سحب (PR) مستقبلي. لكنني أحتاج أيضًا إلى حل مشكلة تحميل الفيديو، وأود النظر في طباعة ملاحظات تغذية راجعة، لأن أحد أهداف الحد هو القدرة على تأكيد نجاح النقل في المنشورات المتأثرة.

من المرجح أن أقوم بذلك خلال الأشهر 1-2 القادمة، لذا إذا كنت تفضل الانتظار حتى ذلك الحين، فقد يكون من الجيد دفع تكلفة إضافية لخدمة S3 لبضعة أشهر أخرى، الأمر متروك لك وأنا لا أقدم وعودًا بل مجرد بيان لنياتي.

@pnoeric بما أنك مهتم بوقت تشغيل الموقع، فقد أردت أن أنقل إليك ما تعلمته حتى الآن.

أجريت عملية الترحيل مباشرة، كما ذكرت. إذا لم أقم بتقييد معدل الترحيل، فإن الطوابير التي تقوم بمهام مثل إشعار المستخدمين بنشاط بعضهم البعض ستنسد، مما يقلل من تجربة المستخدم على الموقع.

تم ترحيل حوالي 500 منشور يحتوي على مقاطع فيديو وحوالي 30 ألف منشور يحتوي على صور، واستغرقت العملية حوالي أسبوعين للإكمال.

إذا كنت ترغب في تجربة الكود الذي استخدمته، فهو متاح حاليًا في:

يمكنك تنزيله ونسخه إلى تطبيقك لاستبدال محتويات lib/tasks/uploads.rake الحالية.

باستخدام هذا الكود، يمكنك القيام بما يلي:

bin/rake uploads:batch_migrate_from_s3[100,1000]

سيأخذ هذا الأمر في الاعتبار 1000 منشور فقط يحتوي على ملفات مرفقة، ويرسل الملفات من الحد الأقصى لـ 100 منشور قبل التوقف؛ في كل مرة يعدل فيها المنشور فعليًا بعد ترحيل الملفات المرفقة، سينتظر حتى تصبح الطابور فارغًا قبل البدء في التالي.

إذا قمت بنسخ الملف، فسيؤدي ذلك إلى كسر تحديثات الموقع المستقبلية_ ما لم تُلغِ التغيير. أسهل طريقة لإلغاء التغيير بعد أن تكون راضيًا هي ببساطة ./launcher rebuild app (على الرغم من أنني كمطور أستخدم git checkout HEAD lib/tasks/uploads.rake لإلغاء تعديلاتي…)

لاحظت أنه على الأقل مع مساحات Digital Ocean، أحيانًا يجب علي إعادة المحاولة عدة مرات قبل نجاح الترحيل. لا يعطي السكربت الحالي أي تحذير عند حدوث ذلك، وعليك فقط الاستمرار في تشغيله والانتظار لمعرفة النتيجة. لدي طلب سحب (PR) قيد المراجعة يطبع الأخطاء في هذه الحالة حتى تعرف على الأقل أن شيئًا ما قد فشل.

أضفت حلقة إعادة محاولة بسيطة، بالإضافة إلى رسالة الخطأ، ويبدو أن حلقة إعادة المحاولة تحل المشكلة. أيضًا، كان التحقق من القواعد الحالية يتم على محتوى المنشورات القديمة، مما قد يكسر الترحيل ويترك المنشورات التي تحتاج إلى إعادة طهي بصمت؛ وقد أصلحت ذلك أيضًا. لن ترغب بالتأكيد في إجراء ترحيل دون الحصول على إصلاح التحقق على الأقل، وهو أحد الالتزامات في طلب السحب (PR) الخاص بي قيد المراجعة حاليًا.

لقد أكملت عملية الترحيل، إلى أقصى حد من معرفتي. يحتوي طلب السحب (PR) الخاص بي على جميع الكود الذي استخدمته لإكمال الترحيل. لم يتم مراجعته بعد. أقترح متابعة التحديثات في Migrate_from_s3 problems إذا كنت ترغب في ذلك.

شكرًا لك! سأقوم بتجربة هذا خلال الأيام القليلة القادمة.

لقد أضفت ملاحظة في ذلك المنشور بشأن وجود خطأ واحد متبقٍ اكتشفناه اليوم، وهو أن صور الملفات الشخصية قد اختفت لدى بعض المستخدمين، ولا أعرف السبب. قمنا برفع أكتافنا وطلبنا من المستخدمين المتضررين استعادة البيانات مع اعتذارنا عن هذه المشكلة.

لقد قمت بالتأكيد بنسخ احتياطي متكرر خلال هذه العملية! :smiling_face:

حظاً موفقاً!

بجدية، هل يمكن أن يجعلني هذا أكثر جنوناً؟ :crazy_face:

إليك ما قمت به:

  1. قمت بنسخ كود lib/tasks/upload.rake الجديد الخاص بك إلى Discourse الخاص بي
  2. أضفت جميع متغيرات Amazon s3_ الخاصة بي إلى config/discourse.conf
  3. أضفتها أيضًا إلى app.yml (غير واضح ما إذا كان ذلك يفعل شيئًا، لكن لماذا لا)
  4. نفذت هذا الأمر وحصلت على…
root@:/var/www/discourse/config# rake uploads:batch_migrate_from_s3[100,1000]
You must disable S3 uploads before running that task.

وأكدت ذلك:

حسنًا، إذن. قمت بتعديل ملف uploads.rake وأزلت فقط هذا التحقق.

الآن أحصل على:

root@:/var/www/discourse/lib/tasks# rake uploads:batch_migrate_from_s3[100,1000]
Migrating uploads from S3 to local storage for 'default'...
Migrating up to 100 of 1000 posts...
... (lots of output here) ...
Modified 91/100: 28795: 28486/1 - https://example.com/t/topic-title-here/28486/1
... (lots of output here) ...

إذن بدا وكأنه يعمل! رائع!

بعد أن أكمل هذه الدفعة الأولى من 100 منشور، تحققت من sidekiq ورأيت أن منشوري التجريبي في قائمة الانتظار، لذا انتظرت حتى ينتهي…

…ثم عدت وتحققت… وما زال هذا المنشور يستخرج صورته من Amazon S3. :frowning: حاولت “إعادة بناء HTML” في المنشور ولم يتغير شيء.

لذا جربت العملية كاملة مرة أخرى، بدءًا من rake وحتى النهاية، وحصلت على نفس النتائج—تمت معالجة نفس الـ 100 منشور، وتمت إضافة نفس العناصر إلى قائمة الانتظار في sidekiq، وبعد السماح لها بالعمل، لا تزال الصورة في ذلك المنشور التجريبي قادمة من S3.

هه، لست متأكدًا مما يجب تجربته بعد. :man_shrugging:t2:

@mcdanlj أقدر أي اقتراحات أو نصائح قد تكون لديك :wink:

هذا بالضبط ما كنت أتوقعه إذا قمت بإزالة هذا الفحص. لست متأكدًا من سبب قرارك بإزالته. تم ذلك عمدًا. قم بإيقاف تشغيل التحميلات إلى S3 قبل بدء عملية الترحيل.

كانت غير مُفعّلة تمامًا. (هل صورة مربع الاختيار في منشوري تمثل الإعداد الصحيح؟) حتى أنني قمت بتفعيلها ثم إلغاء تفعيلها مجددًا، لكن دون جدوى.