مشاكل في Migrate_from_s3

When migrating from S3 to local storage, we see a number of issues.

The main issue is that the migrate_from_s3 rake task is not taking the Uploads table as a starting point, but the posts. This causes it to skip a lot of uploads which are being left on S3.

  • uploads used as logo’s because they are not referenced in a post
  • uploads for avatars because they are not referenced in a post
  • uploads that are (for some reason) referenced by their CDN URL in raw because they do not match the regex that is being used to identify the uploads
  • uploads that are on non-AWS S3 storage because they do not match the regex because it requires amazonaws in the URL
  • uploads that for some reason do not match the second, different regex (we’re seeing this with non-image uploads like mp3 files, not sure why this is happening)
إعجابَين (2)

We’re working on improving the way we associate uploads to posts (by using the upload:// scheme) that will make these storage migrations much more bulletproof. There’s little point to fixing these rake tasks before that’s done.

7 إعجابات

لقد فتحتُ مؤخرًا طلب سحب (PR) جديدًا للسماح بنقل عدد أقل من المنشورات في كل مرة (مثل اختبار منشور واحد في كل مرة)، وأضفت اختبارات للمهمة.

يبدو من المنطقي البدء بالمنشورات، حيث ترغب في إعادة طهي المنشورات لتغيير الرابط في المنشور المطبوخ بعد كل عملية نقل؛ فانتقال جميع الملفات المرفقة ثم البدء في إعادة الطهي سيجعل الموقع معطلاً للغاية لفترة طويلة محتملة في المواقع الكبيرة (أحتاج إلى نقل حوالي 100 جيجابايت من S3 إلى محلي، لذا فهذا الأمر مهم بالنسبة لي). لكن ما كتبته قد يساعد في بدء كتابة مهمة migrate_uploads_from_s3 التي سيتم تشغيلها بعد migrate_from_s3 لتنظيف الملفات المرفقة التي لم تكن جزءًا من المنشورات.

@zogstrip ما هي الحالة الحالية لـ “نحن نعمل على…” — هل لا تزال قيد التغيير أم أن هذا الانتقال يستحق الآن الانتباه إليه؟

5 إعجابات

لقد قمنا بالكثير من العمل في مجال التحميلات لضمان وجود ارتباطات أفضل بين المنشورات والتحميلات.

يمكن تحسين مهام الهجرة في أي وقت :+1:

إعجابَين (2)

سأكتشف ما إذا كان يستحق وقتي البحث في المشاركات غير المنشورة بعد أن أتمكن من استخدام عمليات الرفع الدُفعية لنقل موقعي خارج أوقات العمل! :smiling_face: شكراً لمراجعة طلب السحب!

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

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

أيضًا، عند تحديد max، من المنطقي أن نكون واضحين ومفصلين بشأن ما يتم معالجته لأغراض التصحيح، لذا أود جعل المخرجات مفصلة إذا لم يكن max يساوي nil — وهذا سيسمح للمستخدمين بالتحقق من العملية قبل المتابعة، نظرًا لأن هذا هو الاستخدام الرئيسي لهذا العمل.

أعتقد أن ما سأفعله هو تحديد max كمعلمة أولى، وحد اختياري كمعلمة ثانية، لأن max هو الأهم حقًا؛ أما الحد فهو مجرد وسيلة لجعل “نقرة واحدة فقط” أقل تكلفة.

الأمر الثاني هو غير الرفع: الرفع. قبل أكثر من عام، حاولت رفع فيديو إلى موقع Discourse الذي كنت أنضم إليه، بينما كنت أتخبط في محاولة فهم كيفية كتابة عملية الهجرة من Google+ إلى Discourse، ولاحظت أن ما كُتب كان https://#{SiteSettings.absolute_base_url}/original/3X/b/a/ba9e06ebc2f4397f26793bb5cd4e169308dd371d.mp4

اليوم، عندما أرفع فيديو، أحصل على شيء مثل ![file_example_MP4_480_1_5MG|video](upload://caJ9ykkpshw3PFK4464VUIPWJ4l.mp4) بدلاً من ذلك.

على الأقل في أحدث اختبار لي، قام migrate_from_s3 بتشويه هذه الروابط تمامًا، مما جعلها لم تعد روابط على الإطلاق، لذا يجب إصلاح ذلك بالتأكيد. بعد ذلك، أعتقد أن هذه المهمة من غير المرجح عمليًا أن تواجه ![text](non-upload-url-to-migrate)، لذا كخطوة أولى، أود فقط إضافة تنسيق الرابط الماركداون حول بروتوكول upload السحري، بدلاً من جعل التعبير النمطي يتعامل مع الحالتين ويصبح أكثر صعوبة في القراءة نتيجة لذلك. لكن قد أغير رأيي في ذلك.

يبدو أن وسم video أو audio يُضاف بواسطة جافا سكريبت عبر مطابقة تعبير نمطي، لذا سأحتاج إلى نسخ التعبيرات النمطية من app/assets/javascripts/discourse/app/lib/uploads.js إلى المهمة لتحديدها بشكل صحيح. سأشمل مصدر التعبيرات النمطية حتى يعرف الشخص التالي الذي يعثر عليها مكان تحديثها. :stuck_out_tongue:

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

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

bin/rake uploads:batch_migrate_from_s3[1,1000]

لاحظ أن هذا لن يتجاوز أول 1000 منشور يتم إرجاعها بشكل عشوائي نوعًا ما من استعلام قاعدة البيانات؛ الحد المنخفض هو فقط من أجل السرعة عند إجراء الاستعلام أثناء هجرة منشور واحد فقط في كل مرة، ومراجعة ذلك المنشور للتأكد من السلوك الصحيح ثم البدء من جديد للعثور على منشور آخر. يعمل هذا الأمر بهذه الطريقة فقط مع طلب السحب الذي أعمل عليه حاليًا!

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

حاليًا، أستخدم الحيلة التالية لمشكلة فشل التحميل المتقطع من مساحات Discourse، والتي أدت عمليًا إلى تحسين معدل نجاحي بشكل هائل (ثلاث محاولات كانت كافية تمامًا عبر مئات المنشورات المهاجرة حتى الآن).

https://github.com/johnsonm/discourse/commit/7dfac12a2ea6ec04ba4e0616b4e0dbd1d806cff7

أيضًا، اكتشفت أننا بطريقة ما انتهى بنا الأمر إلى الحصول على فيديوهات أكبر من الحد الذي حددته عند الاستيراد من Google+ — وقد اضطررت إلى زيادة مؤقتة لكل من SiteSettings.max_image_size_kb و SiteSettings.max_attachment_size_kb أثناء عمليات الهجرة الفردية لبعض الفيديوهات الكبيرة الحجم التي لا يتضح لي كيف انتهى بها الأمر على الموقع، لكنني لا أريد كسرها الآن… لا أعرف ما إذا كان الخطأ الذي سمح برفع ملفات كبيرة الحجم كان في سكريبت الاستيراد الخاص بي، أو في Discourse، أو مجرد ذاكرتي حول التغييرات التي أجريتها على الإعدادات بمرور الوقت. :wink:

نظرًا لأن الكثير مما أهاجره كان استيرادًا من G+، فإن بعض منشوراتي فشلت في عمليات التحقق الحالية. حصلت على بعض رسائل Unhandled failure: Validation failed: Sorry, new users can only put one image in a post ولم أفهم في البداية لماذا لم تتكرر. اتضح أن الملفات تم نقلها بنجاح إلى المحلي، واستخدمت جميعها بروتوكول upload: الوهمي، لذا لم يتغير النص الخام. ومع ذلك، فشل post.save! بنفس الخطأ في عمليات التحقق، مما منع post.rebake! من التنفيذ، لذا لدي بعض المنشورات من أصل 30 ألفًا تحتوي على صور تحتاج إلى إعادة معالجة؛ للأسف، ليس لدي أي سجل عن أي منشورات هي تلك. لقد تحولت الآن إلى استخدام post.save!(validate: false) كإصلاح آخر، لذا يجب ألا تتكرر هذه المشكلة تحديدًا. أنا سعيد جدًا لأنني جعلت الهجرة تتوقف عند الأخطاء غير المعالجة، وإلا لكان ذلك قد تسبب في أضرار أكبر بكثير من مجرد بعض المنشورات.

لإبقاء موقعي قابلاً للاستخدام، بما في ذلك تسليم الإشعارات، أثناء تشغيل الهجرة، لا أريد إغراق طوابير Sidekiq. أعرف أن تسمية الأشياء هي واحدة من أصعب مشكلتين في علوم الحاسوب، إلى جانب إبطال التخزين المؤقت وأخطاء العد الزائد أو الناقص، لكنني أقترح DISCOURSE_MIGRATION_MAX_ENQUEUED كمتغير بيئة يحدد العدد الإجمالي لمقاعد الطابور (وليس مقاعد الوظائف) المسموح بملئها عند المتابعة لترحيل عنصر آخر بعد rebake أثناء الهجرة، لتجنب إغراق الطوابير، بحيث يستمر الموقع في العمل. لدي تصحيح يضيف هذا، مع افتراض القيمة صفر، لجميع عمليات إعادة المعالجة لكل منشور في lib/tasks/uploads.rake. أنا أستخدم هذا في هجرتي الإنتاجية.

https://github.com/discourse/discourse/blob/59a761851b9c8786d3a9692f8c595372b0534f77/lib/tasks/uploads.rake

4 إعجابات

@zogstrip هل تمانع مراجعة هذا الـ PR نظرًا لأن لديك سياقًا من المراجعة الأخيرة التي قمت بها في هذا المجال؟ FIX: Make migrations from S3 more robust; fix bare URL migration by johnsonm · Pull Request #10093 · discourse/discourse · GitHub

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

@RGJ أعتقد أن الـ PR الخاص بي كما هو الآن قد يتعامل مع جميع نقاطك ما عدا أول نقطتين، باستثناء أنني لست متأكدًا بشأن CDN. كان موقعي يستخدم CDN وهاجر مقاطع الفيديو التي تحتوي على عناوين URL من CDN، لكن قد يكون ذلك أثرًا جانبيًا لتسمية مساحات Discourse. إذا كانت لديك حالات إضافية، فآمل أن يمنحك الـ PR الخاص بي هيكلاً سهلًا لإضافته إلى التعبير النمطي (regex) وإضافة حالات اختبار للاختلافات الإضافية.

أعتقد أنه من الصحيح أولاً الهجرة حسب المنشور، لأنه بعد هجر المرفقات في منشور ما، يجب إعادة طبخ المنشور (re-bake) حتى يحتوي المنشور المطبوخ على عناوين URL الصحيحة. بعد الانتهاء من هجرة منشوراتي (والتي قد تستغرق أقل من أسبوعين الآن بعد أن غيّرت تحديد معدل السرعة للتحقق من طول الطابور مباشرة)، سأبحث في أي عمل متبقي لتنظيفه.

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

ربما لن أرى أي شعارات معطلة في makerforums لأننا قمنا بضبط الهوية البصرية بعد توقفنا عن وضع محتوى جديد في “s3” (بالنسبة لنا، DigitalOcean Spaces)، لكنني على الأرجح سأتعامل مع مجموعة من المرفقات التي لا تزال في S3 لصور الرموز الشخصية على الأقل. يجب بدء هجرة المرفقات غير المرتبطة بمنشور ما فقط بعد هجرة جميع المنشورات، وعلى الأرجح سأضطر إلى توثيق ذلك بعد الانتهاء من هجرة المرفقات في المنشورات.

@pfaffman أرى Bizarre Problems with migrate_from_s3 - #5 الذي يصف أخطاءً لم تتكرر. بدون إصلاحاتي في الـ PR الحالي، يتم تجاهل الأخطاء بصمت، بما في ذلك حالات فشل التحقق. أعتقد أن العمل هنا سيحل على الأقل بعض المشاكل التي واجهتها آنذاك.

@hosna المشاكل التي أثارها في https://meta.discourse.org/t/what-does-rake-uploads-migrate-from-s3-exactly-do/97285 تم حلها جزئيًا أو كليًا حتى الآن في هذا الـ PR. إذا لم تكن محلولة بالكامل، فقد أضفت اختبارات ستسهل إضافة اختبارات إضافية للتحقق من الإصلاحات الإضافية.

@sam بما أنك وضعت علامة 2.6 على الـ PR، فأنا أفترض أنه لن يتم دمجه على الأقل لبضعة أيام؛ هل يجب أن أسحب عملي على ميزة تحديد معدل السرعة إلى الـ PR جنبًا إلى جنب مع الإصلاحات؟ أم تفضل إبقاء الإصلاحات وعمل الميزات في طلبات سحب (PRs) منفصلة؟ يمكنني فعل أي من الأمرين. ميزة تحديد معدل السرعة تعمل بشكل ممتاز؛ فأنا أقوم بالهجرة بسرعة ثلاثة أضعاف تقريبًا، دون التأثير على توفر الموقع، الآن بعد أن انتظرت حتى يفرغ طابور Sidekiq، لذا يبدو من المنطقي دمجها، أعتقد، إذا كان ذلك شيئًا يُقبل عادةً في طلبات السحب. وإلا، فسأضطر إلى انتظار دمج الـ PR الذي يستند إليه العمل، لذا في كلتا الحالتين سيكون من الجيد سماع رأيك.

..

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

أعتقد أن الـ PR جاهز للمراجعة الآن؛ سأخطط لتقديم PR آخر للمراحل الأخيرة، لكن إدراج هذا سيحسن تجربة الهجرة العامة للجميع حتى قبل إكمال القطع الأخيرة.

5 إعجابات

حسنًا، كان ذلك منذ وقت طويل جدًا…

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

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

@pfaffman ربما يكون من الجيد أنني لم أكن أعرف ما اكتشفته لاحقًا عندما بدأت مشروع الهجرة. يبدو أنه لو كنت قد استخدمت عميل Minio لنسخ جميع محتويات حزمة S3 إلى مجلد التحميلات المحلي، وعدلت جميع قيم Upload.url إلى nil في وحدة تحكم Rails، ثم أعيدت بناء الموقع، لكانت الهجرة قد اكتملت في ساعات دون الحاجة إلى إعادة توليد جميع الصور. (بدلاً من ذلك، أنا مقيد بمعدل التشغيل بسبب إعادة تشغيل جميع عمليات تحويل الصور، وكأن المعالج المحلي أرخص من مجرد نسخ جميع الصور المعالجة من S3.)

ولو كان الأمر بهذه السهولة، لما قمت بأي من هذا العمل لجعل عمليات الهجرة أكثر موثوقية بشكل عام، ولما استفاد أي شخص آخر من ذلك. :smiling_face:

4 إعجابات

أوه. يبدو أن هذا هو ما أريد معرفته. ربما سأجرب هذه الطريقة.

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

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

أوه، وشيء آخر: كان هذا سيؤدي إلى فشل كامل في تحميلات الصوت والفيديو، ولن أنتبه لذلك إلا لاحقًا، وعندها سأحاول فهم المشكلة وكتابة كود مخصص. لذا إذا كانت لديك تحميلات للصوت والفيديو، فمن المؤكد أنك تريد البدء من هناك، ولن يعمل بشكل صحيح دون وجود طلب السحب المفتوح الذي لن يتم دمجه إلا بعد إصدار الإصدار 2.5، لأن @sam قد وضع عليه علامة 2.6.

إعجابَين (2)

أعتذر عن الانضمام إلى المحادثة في هذا الوقت المتأخر. لقد راجعت طلب السحب الخاص بك وأتساءل لماذا تعيد إنشاء نموذج الرفع بدلاً من مجرد تغيير عناوين URL الخاصة به؟ ولماذا لا تقوم بالمرور عبر OptimizedImages وفعل نفس الشيء؟

إعجابَين (2)

@RGJ لم أقوم بتغيير ذلك على الإطلاق؛ إعادة إنشاء Upload كانت إصلاحًا لخطأ من @zogstrip في Cannot execute the rake uploads:migrate_from_s3 - #11

أنا أحاول فقط جعل الكود الموجود مسبقًا يعمل، ولا أعرف تفاصيل داخليّة Discourse جيدًا؛ لقد كنت أترنح في الظلام كثيرًا. تجربتي الوحيدة مع Ruby هي بضع طلبات سحب (PRs) قمت بها لـ Discourse. اتباع نمط الكود الحالي يبدو أنه ليس المسار الأكثر كفاءة (انظر محادثتي مع @pfaffman أعلاه حول القفز عن الخطوات)، وأنا أتفق تمامًا معك. كما يمكنك الاستدلال من حقيقة أنني لم أدرك حتى في وقت سابق من اليوم أن OptimizedImages.url سيحتاج أيضًا إلى التعديل ليصبح مسارًا /uploads وأن يتم تعيين etag إلى nil (ولست أدري ما هو غير ذلك)، فأنا لا أزال أعمل في الظلام.

ما زال يتوجب عليّ التكرار عبر المنشورات أولاً على الأقل لإصلاح عناوين URL الحرفية القديمة في المنشورات. ما زال يتوجب تطبيق بعض الإصلاحات الأخرى، مثل عدم إعادة التحقق من صحة المنشورات وعدم ابتلاع الأخطاء بصمت. ما زلت أرغب في تحديد معدل الطلبات (rate limit)، أعتقد، لتقليل التأثير على المواقع النشطة.

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

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

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

@mcdanlj شكرًا لك على شرحك. كنت أسأل سؤالًا بصدق، ولم أقصد الإشارة إلى وجود أي مشاكل حاليًا. لا أعرف ما إذا كانت الطريقة التي اقترحتها “أفضل” على الإطلاق - ربما ستسبب الكثير من المشاكل الجديدة. أفترض أن الكود كما هو الآن - بغض النظر عن من كتبه - موجود على هذا النحو لسبب ما.

3 إعجابات

@RGJ بالمثل، أنا صادق تمامًا: إذا كان أي شخص يعرف بشكل قاطع كيفية تجنب هدر الوقت في إعادة بناء جميع الصور، فأنا مع ذلك تمامًا. ولو كنت مطورًا مخضرمًا في Discourse وكنت أعرف كيفية القيام بذلك بسهولة، لكانت هذه هي الخطوة الأولى التي كنت سأقوم بها.

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

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

@RGJ أنت محق بوضوح في أن التدمير وإعادة الإنشاء ليس أمرًا جيدًا. لقد أضفت تحققًا: raise "Error: upload url #{url} changed to #{new_upload.short_url}, should be unchanged." if url != new_upload.short_url والذي على الأقل يبلغ عن مشاكل في المصدر التالف. تسببت انقطاع Digital Ocean Spaces اليوم في إرسال بيانات تالفة لي، مما أثار هذا الخطأ في العديد من التحميلات — ولا أعرف كم منها. ولكن لأن النظام قد دمر بالفعل التحميل القديم، أصبح لدي الآن بعض الصفحات التالفة، ولم أدرك ذلك حتى فقدت سجل التمرير (scrollback) الذي يحتوي على السجلات التي تخبرني بالصفحات التالفة، لذا لا يمكنني حتى الدخول وإصلاحها يدويًا من نسخة احتياطية.

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

ما زلت أعتقد أن عملي يجب أن يُدمج كتحسين باريتو (Pareto improvement)، لأنه لا يجعل الأمور أسوأ بل يجعلها أفضل، لكن سيكون من الأفضل بكثير القيام بذلك بالطريقة الصحيحة. أعتقد أن ذلك يتطلب كتابة ملف lib/file_store/from_s3_migration.rb ليعمل بالتوازي مع lib/file_store/to_s3_migration.rb، لكنني لست مؤهلاً للقيام بذلك.

بما أن طلب السحب الخاص بي لم تتم مراجعته بعد، فقد أضفت المزيد إليه. لقد أضفت مهمة uploads:report_missing_uploads تبحث في raw عن حالات upload://... حيث لا يوجد كائن التحميل المرفق. على الأقل في حالتي، مع وجود نسخ احتياطية، سأتمكن من البحث في نسخي الاحتياطية وإيجاد الملفات اليتيمة واستعادتها إلى الموقع، ثم إعادة طباعة (rebake) تلك المنشورات لاستعادة الصور المفقودة. لقد عثرت على 678 منها للبحث عنها في النسخ الاحتياطية، وقد عثرت حتى الآن على جميعها ما عدا 10، لذا أنا سعيد لكتابة الاختبار! سأحتاج إلى التعامل مع ذلك قبل أن أنتقل إلى المرحلة التي أعيد فيها طباعة المنشورات المتبقية.

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

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

اكتشاف تالي: شكرًا لك على قيود المفاتيح الخارجية! اكتشفت أثناء هجرة التحميلات غير المرتبطة بالمنشورات أنني بحاجة إلى هجرة الملفات الشخصية (profiles) على الأقل قبل هجرة التحميلات غير المرتبطة بالمنشورات بشكل عام.

ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR:  update or delete on table "uploads" violates foreign key constraint "fk_rails_1d362f2e97" on table "user_profiles"

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

لقد هجرت جميع التحميلات غير المرتبطة بالمنشورات وغير المرتبطة بالملفات الشخصية. @RGJ إذا كنت ترغب في تجربة الفرع الذي نشرته، فهو محدث بعملي. كل ما فيه قد تم استخدامه الآن لهجرة موقع مكتمل.

@cvx لا أعرف متى ستتاح لك فرصة المراجعة، ولكن بدون طلب السحب الخاص بي، فإن migrate_from_s3 مليء بالتأكيد بـ أخطاء تدمير البيانات الصامتة. ما قمت به ليس مثاليًا، لكنه يحمي من العديد من الأخطاء التي واجهتها عمليًا.

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

بشأن طلب السحب، أحيانًا أحصل على فشل في الاختبارات في CI (كما هو الإصدار الحالي) يشبه هذا:

7867 examples, 0 failures, 11 pending, 1 error occurred outside of examples

##[error]Process completed with exit code 1.

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

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

5 إعجابات

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

في الوقت الحالي، إنه في الواقع فخ للاعبين الجدد.

@cvx @zogstrip ما هو تفضيلكم؟ النظر في طلب السحب أم إزالة migrate_from_s3 بالكامل والصراحة بشأن كونه طريقًا ذا اتجاه واحد؟

5 إعجابات

عذراً، الخطأ مني. سأراجع طلب السحب هذا الأسبوع.

7 إعجابات

كان جوهر المراجعة أن الطريقة الحالية خاطئة تمامًا لدرجة أنها تحتاج إلى إعادة بناء كاملة من الصفر وبطريقة مختلفة؛ وأن محاولة إصلاحها بالطريقة التي كُتبت بها سابقًا غير مقبولة. أنا غير مستعد لذلك، لذا أعتقد حقًا أنه يجب إزالة migrate_from_s3 تمامًا، وأن يُشار إلى migrate_to_s3 بأنه طريق ذو اتجاه واحد لا مفر منه، وأنك تود حقًا الالتزام به إلى الأبد. حاليًا، وجود migrate_from_s3 في الكود المصدري يمثل خللًا في سلامة البيانات في Discourse.

لم أحصل على مراجعة في الوقت المناسب أثناء عملي على عملية الهجرة، والآن بعد أن أكملت الهجرة منذ فترة طويلة (مع بعض النتائج المعطلة، مثل بعض الصور الرمزية المعطلة)، لم يعد لدي بيئة اختبار ذات معنى. لا أملك أي ثقة في أنني سأقوم بذلك بشكل صحيح، لذا انسحبت من هذا الصراع. الأمر متروك للشخص التالي الذي اعتقد أنه فكرة جيدة وضع الصور في خدمة تخزين كائنية شبيهة بـ S3 لحل المشكلة. عذرًا!

إعجابَين (2)

@CxV بما أنك رفضت عملية الهجرة السابقة لأنها أُجريت بشكل خاطئ تماماً وتتطلب البدء من جديد، يرجى مراجعة ودمج هذا الإزالة لخطأ تلف البيانات:

إعجابَين (2)

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

إليك المشكلات المعروفة التي واجهتها:

  • على الأقل، لم يظهر أيقونة discobot؛ فكل مشاركة لـ discobot أظهرت أيقونة الشخص العامة (رأس وكتفين رمادي فاتح على خلفية بيضاء).
  • لم يتم ترحيل أيقونات بعض الأشخاص الآخرين بشكل صحيح. تم إصلاح العديد منها يدويًا.
  • أثناء إعداد الموقع، قام المدير الأصلي بتجربة تغييرات في إعدادات “S3” (في حالتنا، مساحات Digital Ocean، مع وبدون CDN)، مما أدى إلى بعض الصور المحسنة المعزولة التي لم يتم إصلاحها في عملية الترحيل.

بالنسبة لأي شخص حاول استخدام فرعي (branch) الخاص بي وواجه اختفاء بعض الصور مثل هذا، قمت بتشغيل خدعة في وحدة تحكم Rails وأصلحت بعض الأشياء. هذه ليست الطريقة الصحيحة للقيام بذلك، أنا ببساطة لا أعرف النموذج (model) بما يكفي للقيام بذلك بشكل صحيح. مهاراتي في Ruby ضعيفة جدًا؛ لا أتعامل مع Ruby خارج مساهماتي الصغيرة في Discourse.

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

ما لا يظهر هنا هو كل ما فعلته بين الخطوات، مع النظر في كل مجموعة أثناء تقدمي. كان هذا جزءًا من جلسة “استكشف ما هو موجود في وحدة تحكم Rails” وليس في الواقع سكريبت كتبته وقمت بتشغيله. لا يحتوي هذا على معالجة للأخطاء، وقمت بنسخ موقع كامل احتياطيًا قبل البدء في أي من هذا العمل.

لا أعرف كيف أقول بقوة أكبر أن هذا الكود ليس الطريقة المعيارية (idiomatic) في Ruby on Rails لإجراء هذا الإصلاح. أردت فقط مشاركة كيف أصلحت على الأقل بعض الأضرار التي سببتها لنفسي في محاولتي السابقة لترحيل موقعي من مساحات Digital Ocean.

require 'set'

uploadids = Set.new
optimizedimages = Set.new
OptimizedImage.where("url like '%UNIQUEPARTOFS3URL%'").each do |oi|
  uploadids.add(oi.upload_id)
  optimizedimages.add(oi)
end

postids = Set.new
uploadids.each do |u|
  PostUpload.where(upload_id: u).each do |pu|
    postids.add(pu.post_id)
  end
end

optimizedimages.each do |oi|
  oi.delete
end

postids.each do |pid|
  Post.where(id: pid).each do |p|
    p.rebake!
  end
end
إعجابَين (2)