ترقية Discourse إلى Rails 6

مرحبًا يا فريق،

تم إصدار Rails 6.0.0 قبل 25 يومًا، لذا أعتقد أنه حان الوقت لتحديث Discourse :slight_smile: كانت هناك بعض الخطوات التي اضطررت إلى القيام بها لجعل ذلك يعمل.

  1. إصلاح الاختبارات المعطلة (specs)
  • إضافة دالة فارغة trigger_transactional_callbacks? إلى lib/mini_sql_multisite_connection.rb
  • يقوم UrlHelper افتراضيًا بتحميل ActionView::Helpers::UrlHelper بدلاً من lib/UrlHelper. قمت بحل هذه المشكلة بإضافة :: في المقدمة، لكن ما رأيكم في تغيير اسم هذا الكلاس؟
  • في Rails 5.2.3، كان MigrationContext يقبل وسيطًا واحدًا، بينما في 6.0.0 يُطلب مخطط إضافي.
  1. إصلاح الطرق المهجورة (deprecated methods)
  • تم استبدال update_attributes! بـ update!
  • سيحتوي Content_type على مجموعة الأحرف (charset)، لذا يجب استخدام نوع الوسائط (media type) بدلاً من ذلك - rails/guides/source/upgrading_ruby_on_rails.md at main · rails/rails · GitHub
  • إصلاح تحذير الثابت المهيأ مسبقًا (TRADITIONAL_ESCAPED_CHAR, RFC_5987_ESCAPED_CHAR). قبل حذفها، تأكدت من أن القيم في ActionPack متطابقة.
  1. استخدام محمل التلقائي الكلاسيكي (classic autoloader) كخطوة أولى قبل Zeitwerk.
  2. إصلاح عمليات الترحيل (migrations) في Rails 6.0.0 - لا يسمح أحدث إصدار من Rails بالخطأ الموجود في الترحيلات القديمة (لا يمكنك تعريف عمود ‘integer’ تم تعريفه مسبقًا).

أجريت اختبارات دخانية (smoke tests) للتأكد من عمل Discourse كما هو متوقع. بالإضافة إلى ذلك، قمت بتشغيل اختبارات الأداء لضمان عدم وجود تراجع (استخدمت 500 تكرار افتراضيًا).

الاختبار Rails 5.2.3 Rails 6.0.0 النسبة المئوية
categories-50 27 24 88.89%
categories-75 31 26 83.87%
categories-90 36 37 102.78%
categories-99 52 50 96.15%
home-50 27 26 96.30%
home-75 30 28 93.33%
home-90 39 38 97.44%
home-99 53 55 103.77%
topic-50 35 27 77.14%
topic-75 36 29 80.56%
topic-90 37 39 105.41%
topic-99 56 50 89.29%
categories_admin-50 47 47 100.00%
categories_admin-75 54 59 109.26%
categories_admin-90 64 66 103.13%
categories_admin-99 132 116 87.88%
home_admin-50 47 46 97.87%
home_admin-75 51 56 109.80%
home_admin-90 63 64 101.59%
home_admin-99 110 97 88.18%
topic_admin-50 50 49 98.00%
topic_admin-75 58 59 101.72%
topic_admin-90 65 67 103.08%
topic_admin-99 113 86 76.11%
load_rails 2593 2618 100.96%
rss_kb 318800 287332 90.13%
pss_kb 306913 275378 89.73%
المتوسط 89.31%

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

PR - https://github.com/discourse/discourse/pull/8083

تحياتي،
كريس

هذا رائع :confetti_ball:

هل يمكنك وضع هذا في جدول بتنسيق Markdown مع نسبة التغير؟ الفحص السريع يُظهر أن القليل قد تغير، وهو أمر رائع.

من حيث الإضافات، لدينا مهمة Rake تقوم بتثبيت جميع الإضافات الرسمية. هل يمكنك تشغيلها والتأكد من أن مواصفات الإضافات تعمل بنجاح على Rails 6؟ (أمر rake plugin:spec يجب أن ينجز المهمة).

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

هناك رقمان هنا أجدانهما مثيرين للاهتمام للغاية:

أداء RSS على الإصدار 6.0 أفضل بنسبة 10% تقريبًا.

الوقت المتوسط للصفحة (Topic) — وهو المسار الأكثر شيوعًا لدينا — أسرع بنسبة 22%.

هذا تحسن ملحوظ في الأداء، هل يمكنك قياس تحسن 22% بشكل متسق على topic-50؟ هل يمكنك تأكيد أن الصفحة الفعلية تُعرض بشكل صحيح؟

شغلت اختبار الأداء ثلاث مرات، وهذه المرة كانت النتائج أقل إبهارًا. تدفقي هو كتابة ruby script/bench.rb في الفرع الصحيح master أو rails6، ثم الضغط على Enter دون لمس لوحة المفاتيح حتى لا تؤثر على النتائج.

topic-50 RSS
5.2.3 50 322852
5.2.3 50 309684
5.2.3 50 346376
المتوسط 50 326304
6.0.0 49 328844
6.0.0 49 321824
6.0.0 49 283584
المتوسط 49 311417

كما قمت بربط خادم التطوير الخاص بي بقاعدة بيانات الأداء للتأكد من أن صفحة الموضوع تبدو صحيحة. تبدو الصورة المرفقة أدناه جيدة من وجهة نظري

أود الحصول على رأيك بخصوص إصلاح واحد.
لقد قمت بتحميل جميع الإضافات، ومع ذلك يفشل أحد المواصفات الجديدة مقارنة بفرع master (./plugins/discourse-data-explorer/spec/controllers/queries_controller_spec.rb:32)

  1) DataExplorer::QueryController when disabled denies every request
     Failure/Error: render 'default/empty'

     ActionView::Template::Error:
       wrong number of arguments (given 2, expected 1)

تم إصلاح هذه المشكلة في فرع master rspec-rails https://github.com/rspec/rspec-rails/blob/4-0-dev/lib/rspec/rails/view_rendering.rb
عن طريق تغيير
def self.call(_template) إلى def self.call(_template, _source = nil)

يمكنني تطبيق حشوة (monkey patch) على rspec-rails بإنشاء ملف جديد في lib/freedom_patched/rspec-rails.rb، لكنني أريد التأكد من أن هذا هو أفضل نهج.

أعتقد أن هذا هو التغيير الأخير الذي يعيق دمج Rails 6.

بالإضافة إلى ذلك، لاحظت أن هذا الاختبار معطّل، وهو معطّل أيضًا في فرع master. يمكنني محاولة إصلاحه (./plugins/discourse-calendar/spec/jobs/update_holiday_usernames_spec.rb:14)

 Failure/Error: expect(DiscourseCalendar.users_on_holiday).to eq([post.user.username])
       expected: ["bruce1"]
            got: []

أخيرًا، هناك دوال قديمة في الإضافات يمكنني إصلاحها بسهولة غدًا.

ما هو رأيك بخصوص rspec-rails؟

يا إلهي، أعتقد أننا سنقوم بتعديل (monkey patch) حتى يتم إصدار rspec-rails 4، ولا يمكنني التفكير في إصلاح أنظف من ذلك هنا.

أو… ربما… نستخدم النسخة التجريبية (beta gem) مؤقتًا إذا كان كل شيء يعمل بشكل صحيح؟

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

لقد قمت بإجراء بعض الإصلاحات الإضافية.

أولاً، اكتشفت السبب وراء فشل اختبار واحد بالنسبة لي في كل من فرع master و فرع rails6 - FIX: Freezed time used in update_holiday_usernames_spec.rb should be UTC by KrisKotlarek · Pull Request #3 · discourse/discourse-calendar · GitHub

كما قمت بإنشاء طلبات دمج (pull requests) لطرق قديمة في إضافات مختلفة:

أعدت تجميع أحدث نسخة من master في فرع rails6.

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

تم الدمج الآن :confetti_ball: :confetti_ball: :confetti_ball:

سأتابع الأمر عن كثب اليوم، شكرًا جزيلاً على هذا العمل.

وشكرًا كبيرًا لفريق Rails على جعل هذه الترقية ممتعة للغاية!!

سأعود للإبلاغ في هذا الموضوع مع بعض الرسوم البيانية الجميلة.

يبدو الترقية هادئًا جدًا، وهو أمر رائع. الأداء متسق ويبقى متشابهًا بشكل مذهل.

يبدو الذاكرة ووحدة المعالجة المركزية متشابهين بشكل ملحوظ.

مخاوفي الوحيدة (وشيء أود معرفة سببه) هو أنه يبدو أننا نحصل على “خيوط هاربة” لبضع ثوانٍ بانتظام في عمال الويب.

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

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

نظرًا لأن كل شيء آخر يبدو رائعًا حقًا، فلن أقوم بإلغاء الترقية.

يجب إصلاح ذلك وفقًا لـ:

هذا نتيجة لوجود كود جديد في Rails 6 يحمي الوصول إلى المتغير المرتبط بالخيوط لتحديد ما إذا كان بإمكانك استخدام عبارات مُعدّة أم لا.

في Discourse، لا نستخدم العبارات المُعدّة على الإطلاق، لذا فإن هذه التصحيحة ليست شيئًا نحتاجه.

راجع المزيد في:

و … تم التأكيد … إصلاحي يزيل العدد الكبير من طفرات الخيوط

جدير بالذكر أيضًا … هذا هو كيفية تصحيحها:

  1. كتبت هذا الكلاس الصغير
# frozen_string_literal: true

class Thread
  attr_accessor :origin
end

class ThreadDetective
  def self.test_thread
    Thread.new { sleep 1 }
  end
  def self.start(max_threads)
    @thread ||= Thread.new do
      self.new.monitor(max_threads)
    end

    @trace = TracePoint.new(:thread_begin) do |tp|
      Thread.current.origin = Thread.current.inspect
    end
    @trace.enable
  end

  def self.stop
    @thread&.kill
    @thread = nil
    @trace&.disable
    @trace.stop
  end

  def monitor(max_threads)
    STDERR.puts "Monitoring threads in #{Process.pid}"

    while true
      threads = Thread.list

      if threads.length > max_threads
        str = +("-" * 60)
        str << "#{threads.length} found in Process #{Process.pid}!\n"

        threads.each do |thread|
          str << "\n"
          if thread.origin
            str << thread.origin
          else
            str << thread.inspect
          end
          str << "\n"
        end
        str << ("-" * 60)

        STDERR.puts str
      end
      sleep 1
    end
  end

end
  1. بعد ذلك قمت بربط unicorn في after_fork مع استدعاء هذا الكلاس وشغلت ThreadDetective.start(14)

  2. راقب الكلاس بكل دقة كل مرة يتم فيها إنشاء خيط باستخدام TracePoint ووضع إطارًا صغيرًا على الخيط يسمى origin لمساعدتي في تتبع مصدره. بمجرد ملاحظة عدد كبير من الخيوط، قام بوضع البيانات في STDERR. يمكن تتبع ذلك في /var/www/discourse/logs/unicorn.stderr.log

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

لاحظت أنني لم أعد أستطيع استخدام dev.local كاسم مضيف في وضع التطوير في Rails 6، لذا أضفت متغير بيئة (ENV) لتكوين القائمة البيضاء:

لا ينبغي أن نحتفظ بهذا التصحيح المؤقت على المدى الطويل، حيث تم بالفعل دمج إصلاح في Rails.

مرحبًا،

شكرًا لك على جهودك في جلب Rails 6 إلى Discourse! هل يمكنني أن أسأل بلباقة متى يُتوقع أن يتم دمجها في Discourse؟ أم أنها موجودة بالفعل في الإصدار 2.4.0.beta؟ أنا أسأل فقط حول إمكانية ما إذا كان ذلك قد يكسر أي إضافة قام الأشخاص بتثبيتها على مثيلاتهم.

مع خالص التحية،
أندرياس.

هذا متاح منذ سبتمبر لجميع المستخدمين الذين يستخدمون قناة الإصدار الافتراضية. وقد تم عرضه لأول مرة في الإصدار 2.4.0.beta5.

حسناً، شكرًا جزيلاً لك. أتمنى لك كل التوفيق في عام 2020، وشكرًا على كل ما تقومون به هنا.