रेलिंग की सुरक्षा। रेल [] रेल में उपयोग


81

मैं Thread.currentहैश में जानकारी संग्रहीत करने के अभ्यास (जैसे, current_user, वर्तमान उपडोमेन, आदि) पर परस्पर विरोधी राय प्राप्त करता रहता हूं । तकनीक को मॉडल परत (क्वेरी स्कूपिंग, ऑडिटिंग, आदि) के भीतर बाद के प्रसंस्करण को सरल बनाने के तरीके के रूप में प्रस्तावित किया गया है।

कई लोग इस अभ्यास को अस्वीकार्य मानते हैं क्योंकि यह एमवीसी पैटर्न को तोड़ता है। अन्य लोग दृष्टिकोण की विश्वसनीयता / सुरक्षा के बारे में चिंता व्यक्त करते हैं, और मेरा 2-भाग प्रश्न बाद के पहलू पर केंद्रित है।

  1. क्या Thread.currentहैश उपलब्ध होने की गारंटी देता है और निजी और केवल एक प्रतिक्रिया के लिए, अपने पूरे चक्र में?

  2. मैं समझता हूं कि एक प्रतिक्रिया के अंत में, एक धागा, अन्य आवक अनुरोधों को सौंप दिया जा सकता है, जिससे किसी भी जानकारी को संग्रहीत किया जा सकता है Thread.current। प्रतिक्रिया समाप्त होने से पहले इस तरह की जानकारी को साफ़ करना (जैसे Thread.current[:user] = nilएक नियंत्रक से निष्पादित after_filter) इस तरह के सुरक्षा उल्लंघन को रोकने के लिए पर्याप्त है?

धन्यवाद! ग्यूसेप


9
यहां "थ्रेडक्रेड्रेट के साथ गंदा हो रहा है" अनुभाग देखें। m.onkey.org/thread-safety-for-your-rails । यह एक जुबी लेखक द्वारा लिखा गया था। # 1 ROR कोड I18N और time_zone के लिए स्वयं Thread.current का उपयोग करता है। क्या वह इसकी गारंटी के बारे में बोलता है? # २। अगर # 1 सच है तो यह पर्याप्त है।
so_mv

धन्यवाद, मैंने संदर्भ जोड़ा।
Giuseppe

3
आपके द्वारा लिंक किए गए पोस्ट में, उदाहरण विशेष रूप से नियंत्रक परत के साथ सौदा करते हैं, और प्रस्तावित समाधान स्पष्ट रूप से उपयुक्त है। मुझे संदेह है, हालांकि, कि ज्यादातर लोगों को क्या दिलचस्पी होगी, मॉडल को प्रत्येक कॉल में अतिरिक्त मापदंडों को जोड़ने के बिना, सामान्य रूप से उन तक पहुंची जानकारी के 1-2 टुकड़ों में मॉडल तक पहुंच देने का एक साफ तरीका है। इस संबंध में, उन सभी बड़े डरावने "थ्रेड.ट्रैक से दूर रहें" विशिष्ट कारणों के बिना चेतावनी के संकेत हैं कि अब तक मुझे अनिश्चित क्यों छोड़ दिया है। साभार
Giuseppe

जवाबों:


48

थ्रेड-लोकल वैरिएबल से दूर रहने का कोई विशेष कारण नहीं है, मुख्य मुद्दे हैं:

  • जब आप इसका उपयोग करने वाले कोड का परीक्षण कर रहे हों, तो उन्हें थ्रेड-लोकल वैरिएबल सेट करना याद रखना कठिन होगा, क्योंकि उनका परीक्षण करना कठिन है
  • थ्रेड लोकल का उपयोग करने वाली कक्षाओं को ज्ञान की आवश्यकता होगी कि ये ऑब्जेक्ट उनके लिए उपलब्ध नहीं हैं, लेकिन थ्रेड-लोकल वैरिएबल के अंदर और इस तरह के अप्रत्यक्ष रूप से आमतौर पर लोकतंत्र का कानून टूट जाता है
  • थ्रेड-लोकल की सफाई नहीं करना एक मुद्दा हो सकता है यदि आपका फ्रेम थ्रेड्स का पुन: उपयोग करता है (थ्रेड-लोकल वैरिएबल पहले से ही शुरू हो जाएगा और कोड जो कि पर निर्भर करता है = = वैरिएबल को शुरू करने के लिए कॉल विफल हो सकता है)

इसलिए, जब यह उपयोग करने के लिए सवाल से पूरी तरह से बाहर नहीं है, तो सबसे अच्छा तरीका उनका उपयोग नहीं करना है, लेकिन समय-समय पर आप एक दीवार पर टकराते हैं जहां एक धागा स्थानीय काफी कोड बदलने के बिना सबसे सरल संभव समाधान होने जा रहा है और आपको समझौता करना होगा, थ्रेड लोकल के साथ एक सही ऑब्जेक्ट ओरिएंटेड मॉडल से कम या ऐसा करने के लिए काफी कोड बदलना होगा।

तो, यह ज्यादातर सोचने का विषय है जो आपके मामले के लिए सबसे अच्छा समाधान होने जा रहा है और यदि आप वास्तव में थ्रेड-लोकल पाथ नीचे जा रहे हैं, तो मैं निश्चित रूप से आपको इसे उन ब्लॉकों के साथ करने की सलाह दूंगा जो बाद में साफ करना याद रखें। वे निम्नलिखित की तरह किए जाते हैं:

around_filter :do_with_current_user

def do_with_current_user
    Thread.current[:current_user] = self.current_user
    begin
        yield
    ensure
        Thread.current[:current_user] = nil
    end      
end

यह सुनिश्चित करता है कि यदि थ्रेड को पुनर्नवीनीकरण किया जाता है, तो उपयोग किए जाने से पहले थ्रेड स्थानीय चर को साफ कर दिया जाता है।


1
यदि आप बहुत सावधान नहीं हैं तो एक सुनिश्चित ब्लॉक के साथ एक फिल्टर का उपयोग करना अपवाद हैंडलिंग / लॉगिंग के साथ गड़बड़ करेगा। एक मिडलवेयर-आधारित, क्लीनर समाधान के लिए डीजन के उत्तर में RequestStore की जाँच करें।
Irongaze.com

इस समस्या के लिए मेरा दृष्टिकोण हो सकता है कि मैं पहले अपवाद को छोड़ रहा था (केवल ऊपर के रूप में सुनिश्चित करने के बजाय)। अपवाद की कॉल स्टैक को उस स्थान पर रीसेट किया जा रहा था जहां मैंने पुन: उठाया, रेल्स त्रुटि लॉग और कहीं और गड़बड़ कर रहा था। मैंने स्वयं को संरक्षित करने के लिए लॉग फ़ाइल में कैप्चर किए गए अपवाद को मैन्युअल रूप से डंप किया, लेकिन यह बदसूरत था। एक मिडलवेयर-आधारित दृष्टिकोण का उपयोग करना बहुत क्लीनर IMHO है।
Irongaze.com 14

1
इसलिए उस कोड के ऊपर केवल एक ensureब्लॉक है और अपवाद को पकड़ने की कोशिश नहीं करता है।
मॉरीशो लिन्हार्स 15

सरल जब आप इसे देखते हैं :)
244an


15

स्वीकृत उत्तर प्रश्न को कवर करता है लेकिन रेल 5 के रूप में अब एक "सार सुपर क्लास" ActiveSupport :: CurrentAttributes प्रदान करता है जो Thread.current का उपयोग करता है।

मैंने सोचा कि मैं एक संभव ( अलोकप्रिय ) समाधान के रूप में एक लिंक प्रदान करूंगा ।

https://github.com/rails/rails/blob/master/activesupport/lib/active_support/current_attributes.rb


4

स्वीकृत उत्तर तकनीकी रूप से सटीक है, लेकिन जैसा कि उत्तर में धीरे से बताया गया है, और http://m.onkey.org/thread-safety-for-your-rails में इतना धीरे नहीं:

Thread.currentयदि आप बिल्कुल नहीं हैं तो थ्रेड लोकल स्टोरेज का उपयोग न करें

के लिए मणि request_storeएक और समाधान (बेहतर) है, लेकिन सिर्फ थ्रेड स्थानीय भंडारण से दूर रहने के लिए और अधिक कारणों से रीडमी पढ़ें।

लगभग हमेशा बेहतर तरीका होता है।


3
मैं गेंडा मल्टी-टेनेंट ऐप के साथ यूनिकॉर्न का उपयोग कर रहा हूं। क्या आप "बेहतर तरीके" का एक उदाहरण सुझा सकते हैं? लिंक आप पोस्ट त्रुटि अनुप्रयोग फेंकता है। धन्यवाद।
लैकोस्टेनकोडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.