القضبان: "مستوى المكدس عميق جدًا" عند استدعاء طريقة مفتاح "المعرف" الأساسي

StackOverflow https://stackoverflow.com/questions/4136245

سؤال

هذا هو إعادة النشر على امر اخر, ، معزولة بشكل أفضل هذه المرة. في ملف البيئة. RB قمت بتغيير هذا السطر:

config.time_zone = 'UTC'

إلى هذا الخط:

config.active_record.default_timezone = :utc

منذ ذلك الحين ، هذه الدعوة:

Category.find(1).subcategories.map(&:id)

يفشل على خطأ "مستوى المكدس عميقًا جدًا" بعد المرة الثانية التي يتم فيها تشغيله في بيئة التطوير عند config.cache_classes = false. إذا كان config.cache_classes = صحيح ، فإن المشكلة لا تحدث. الخطأ هو نتيجة للرمز التالي في Active_record/Attribute_methods.rb حول السطر 252:

def method_missing(method_id, *args, &block)
...

    if self.class.primary_key.to_s == method_name
        id
    ....

تعيد الاتصال إلى دالة "ID" Method_missing ولا يوجد شيء يمنع المعرف الذي يتم استدعاؤه مرارًا وتكرارًا ، مما يؤدي إلى مستوى المكدس عميقًا جدًا.

أنا أستخدم Rails 2.3.8. نموذج الفئة HAS_MANY: الفئات الفرعية. تفشل المكالمة على متغيرات هذا السطر أعلاه (على سبيل المثال الفئة.

أي أفكار ستكون موضع تقدير كبير.

شكرًا! أميت

هل كانت مفيدة؟

المحلول 2

- يتم نسخ هذه الإجابة من مشاركتي الأصلية هنا.

أخيرا حل! بعد النشر سؤال ثالث وبمساعدة من trptcolin, ، يمكنني تأكيد حل العمل.

المشكلة: كنت أستخدم require لتضمين نماذج من داخل النماذج أقل من الجدول (فئات موجودة في التطبيق/النماذج ولكن لا تمدد ActivereCord :: Base). على سبيل المثال ، كان لدي فصل FilterCategory التي أدت require 'category'. هذا أفسد مع التخزين المؤقت للفئة. كان علي استخدام require في المقام الأول منذ خطوط مثل Category.find :all باءت بالفشل.

الحل (يذهب الائتمان إلى trptcolin): استبدال Category.find :all مع ::Category.find :all. يعمل هذا دون الحاجة إلى طلب أي نموذج بشكل صريح ، وبالتالي لا يتسبب في أي مشاكل في التخزين المؤقت للفئة.

كما تختفي مشكلة "المكدس العميق" عند استخدامها config.active_record.default_timezone = :utc

نصائح أخرى

على الرغم من أن هذا تم حله ، إلا أنني أردت فقط أن أتناغم في هذا الأمر ، وأبلغ عن كيفية إصلاح هذه المشكلة. كان لدي نفس الأعراض مثل OP ، والطلب الأولي .ID () عملت بشكل جيد ، والطلبات اللاحقة .id () سوف ترمي رسالة الخطأ "المكدس العميق". إنه خطأ غريب ، لأنه يعني عمومًا أن لديك حلقة لا حصر لها في مكان ما. لقد أصلحت هذا عن طريق التغيير:

config.action_controller.perform_caching = true
config.cache_classes                     = false

إلى

config.action_controller.perform_caching = true
config.cache_classes                     = true

في البيئات/الإنتاج.

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

config.cache_store = :file_store

تحديث رقم 2: C. Bedard نشر هذا التحليل للقضية. يبدو أن يلخصها بشكل جيد.

بعد أن واجهت هذه المشكلة بنفسي (والتعليق عليها بشكل متكرر) لقد بحثت في الخطأ (ونأمل أن أجد حلًا جيدًا). إليك ما أعرفه حول هذا الموضوع: يحدث ذلك عندما يتم استدعاء ActivereCord :: Base#Reset_SubClasses بواسطة المرسل بين الطلبات (في وضع DEV فقط).

ACTIVERECORD :: base #reset_subclasses يمنح التجزئة الوراثية _attributes (حيث يتم تخزين #skip_time_zone_conversion_for_attributes). لن يحدث ذلك فقط على الكائنات المستمرة من خلال الطلبات ، حيث يظهر "تطبيق اختبار القرد" من #1290 ، ولكن أيضًا عند محاولة الوصول إلى أساليب الارتباط التي تم إنشاؤها على AR ، حتى بالنسبة للكائنات التي تعيش فقط في الطلب الحالي.

تم تقديم هذا الخطأ بواسطة هذا الالتزام حيث تم تغيير إعلان #skip_time_zone_conversion_for_attributes من base.cattr_accessor إلى base.class_inherable_accessor. ولكن مرة أخرى ، فإن هذا الالتزام نفسه ثابت أيضا شيء آخر. تم تقديم التصحيح في البداية هنا والذي يتجنب ببساطة مسح extal_variables و eChate_methods في Reset_subclasses ، تقدم تسربًا هائلاً ، ويبدو أن المبالغ التي يتم تسربها تتناسب بشكل مباشر مع تعقيد التطبيق (أي عدد النماذج والجمعيات والسمات على كل واحد منها). لديّ تطبيق معقد جدًا يتسرب ما يقرب من 1 ميغابايت في كل طلب في وضع DEV عند تطبيق التصحيح. لذلك ليس قابلاً للتطبيق (بالنسبة لي على أي حال).

أثناء تجربة طرق مختلفة لحل هذا ، قمت بتصحيح الخطأ الأولي (skip_time_zone_conversion_for_attributes يجري لا شيء على الطلب الثاني) ، لكنها كشفت عن خطأ آخر (وهو ما لم يحدث فقط لأن الاستثناء الأول سيثير قبل الوصول إليه). يبدو أن هذا الخطأ هو الخطأ الذي تم الإبلاغ عنه في #774 (مكدس Overflow في method_missing لطريقة "المعرف").

الآن ، بالنسبة للحل ، يقوم التصحيح (المرفق) بما يلي: يضيف طرق التفاف لطرق #skip_time_zone_conversion_for_attributes ، مع التأكد من أنه يقرأ/يكتب دائمًا القيمة باعتباره class_inheritable_attribute. بهذه الطريقة ، لم تعد لا تعود بعد الآن.

إنه يضمن عدم القضاء على طريقة "المعرف" عند استدعاء Reset_SubClasses. AR غريب نوعًا ما على ذلك ، لأنه يحدده أولاً مباشرة في المصدر ، لكنه يعيد تعريف نفسه بـ #Define_Read_Method عندما يتم استدعاؤه لأول مرة. وهذا هو بالضبط ما يجعلها تفشل بعد إعادة التحميل (منذ إعادة stet_subclasses ثم تمحوها).

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

آسف على اللصق الطويل ، فإنه يمتص أن مشروع Lighthouse Rails خاص. التصحيح المذكور أعلاه خاص.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top