6

अनुप्रयोगों को अक्सर अन्य सेवाओं (डेटाबेस, एक कैश, एक एपीआई, आदि) से कनेक्ट करने की आवश्यकता होती है। स्वच्छता और डीआरवाई के लिए, हम इन सभी कनेक्शनों को एक मॉड्यूल में रखना चाहते हैं ताकि हमारे शेष कोड बेस कनेक्शन साझा कर सकें।पायथन में कनेक्शन निर्माण का प्रबंधन?

बॉयलरप्लेट कम करने के लिए नीचे की ओर उपयोग आसान होना चाहिए:

# app/do_stuff.py 
from .connections import AwesomeDB 

db = AwesomeDB() 

def get_stuff(): 
    return db.get('stuff') 

और कनेक्शन की स्थापना भी आसान होना चाहिए:

Django और बोतल की तरह
# app/cli.py or some other main entry point 
from .connections import AwesomeDB 

db = AwesomeDB() 
db.init(username='stuff admin') # Or os.environ['DB_USER'] 

वेब चौखटे कुछ इस तरह करते हैं, लेकिन यह थोड़ा उलझन में महसूस करता है:

Connect to a Database in Flask, Which Approach is better? http://flask.pocoo.org/docs/0.10/tutorial/dbcon/

इसके साथ एक बड़ा मुद्दा यह है कि हम प्रॉक्सी के बजाय वास्तविक कनेक्शन ऑब्जेक्ट का संदर्भ चाहते हैं, क्योंकि हम iPython और अन्य देव वातावरण में टैब-पूर्णता को बनाए रखना चाहते हैं।

तो ऐसा करने का सही तरीका (टीएम) क्या है? कोई नहीं के बजाय एक सामान्य ConnectionProxy है, जो सभी विशेषता पहुँच फैल जाती है और एक अपवाद फेंकता है पर सेट करें प्रारंभिक __connection: सुधार के लिए

#app/connections.py 
from awesome_database import AwesomeDB as RealAwesomeDB 
from horrible_database import HorribleDB as RealHorribleDB 


class ConnectionMixin(object): 
    __connection = None 

    def __new__(cls): 
     cls.__connection = cls.__connection or object.__new__(cls) 
     return cls.__connection 

    def __init__(self, real=False, **kwargs): 
     if real: 
      super().__init__(**kwargs) 

    def init(self, **kwargs): 
     kwargs['real'] = True 
     self.__init__(**kwargs) 


class AwesomeDB(ConnectionMixin, RealAwesomeDB): 
    pass 


class HorribleDB(ConnectionMixin, RealHorribleDB): 
    pass 

कक्ष: कुछ पुनरावृत्तियों के बाद, यहाँ मेरा विचार है।

मैंने एसओ और विभिन्न ओएसएस परियोजनाओं में यहां चारों ओर घूमते हुए काफी कुछ किया है और इस तरह कुछ भी नहीं देखा है। यह बहुत ठोस लगता है, हालांकि इसका मतलब है कि मॉड्यूल का एक समूह आयात वस्तुओं पर साइड इफेक्ट के रूप में कनेक्शन ऑब्जेक्ट्स को तुरंत चालू करेगा। क्या यह मेरे चेहरे पर उड़ाएगा? क्या इस दृष्टिकोण के लिए कोई अन्य नकारात्मक परिणाम हैं?

उत्तर

0

, सबसे पहले डिजाइन के लिहाज से, मैं कुछ याद आ रही हो सकता है, लेकिन मैं नहीं देख पा रहे हैं कारण है कि आप भारी mixin + सिंगलटन मशीनरी के बजाय जरूरत बस इतनी तरह एक सहायक को परिभाषित: इसके अलावा

_awesome_db = None 
def awesome_db(**overrides): 
    global _awesome_db 
    if _awesome_db is None: 
     # Read config/set defaults. 
     # overrides.setdefault(...) 
     _awesome_db = RealAwesomeDB(**overrides) 
    return _awesome_db 

वहाँ, एक बग जो किसी समर्थित यूज-केस की तरह नहीं है, लेकिन वैसे भी है: यदि आप एक पंक्ति में निम्नलिखित 2 कॉल करने के लिए, आप गलत तरीके से दो बार एक ही कनेक्शन वस्तु मिलेगा भले ही आप विभिन्न मापदंडों के पारित कर दिया:

db = AwesomeDB() 
db.init(username='stuff admin') 

db = AwesomeDB() 
db.init(username='not-admin') # You'll get admin connection here. 

उस के लिए एक आसान फिक्स कनेक्शन के एक निर्देश का उपयोग करना होगा इनपुट पैरामीटर।

अब, प्रश्न के सार पर।

मुझे लगता है कि उत्तर इस बात पर निर्भर करता है कि आपके "कनेक्शन" वर्ग वास्तव में कैसे कार्यान्वित किए जाते हैं।

अपने दृष्टिकोण मैं देख रहा हूँ के साथ संभावित कमियां हैं: एक बहु-क्रम वातावरण में

  • आप एक से अधिक थ्रेड से वैश्विक कनेक्शन वस्तु को unsychronized समवर्ती उपयोग के साथ समस्याओं मिल सकता है, जब तक कि यह पहले से ही धागा सुरक्षित है। यदि आप इसके बारे में परवाह करते हैं, तो आप अपना कोड बदल सकते हैं और थोड़ा सा इंटरफ़ेस बदल सकते हैं और थ्रेड-स्थानीय चर का उपयोग कर सकते हैं।

  • कनेक्शन बनाने के बाद एक प्रक्रिया कांटा क्या होगा? वेब अनुप्रयोग सर्वर ऐसा करते हैं और यह अंतर्निहित कनेक्शन के आधार पर फिर से सुरक्षित नहीं हो सकता है।

  • क्या कनेक्शन ऑब्जेक्ट में राज्य है? क्या होता है यदि कनेक्शन ऑब्जेक्ट अमान्य हो जाता है (यानी कनेक्शन त्रुटि/समय के कारण)? किसी कनेक्शन से अनुरोध होने पर अगली बार लौटने के लिए आपको टूटे हुए कनेक्शन को नए से बदलना पड़ सकता है।

कनेक्शन प्रबंधन अक्सर पहले से ही कुशलता से और सुरक्षित रूप से क्लाइंट लाइब्रेरी में एक connection pool के माध्यम से कार्यान्वित है। कनेक्शन पूल से

इसलिए चूंकि रेडिस क्लाइंट हुड के नीचे उन सभी को संभालता है, इसलिए आप सुरक्षित रूप से जो भी चाहते हैं उसे सुरक्षित कर सकते हैं। कनेक्शन पूल पूरी तरह से पहुंचने तक कनेक्शन को आलसी बनाया जाएगा।

# app/connections.py 
def redis_client(**kwargs): 
    # Maybe read configuration/set default arguments 
    # kwargs.setdefault() 
    return redis.Redis(**kwargs) 

इसी तरह, एसक्लाक्लेमी connection pooling as well का उपयोग कर सकते हैं।

संक्षेप में, मैं समझता हूँ कि है: अपने क्लाइंट लाइब्रेरी कनेक्शन पूलिंग का समर्थन करता है

  • हैं, तो आप कुछ भी विशेष मॉड्यूल और यहां तक ​​कि धागे के बीच कनेक्शन साझा करने के लिए क्या करने की जरूरत नहीं है। आप केवल redis_client() के समान एक सहायक को परिभाषित कर सकते हैं जो कॉन्फ़िगरेशन पढ़ता है, या डिफ़ॉल्ट पैरामीटर निर्दिष्ट करता है।

  • यदि आपकी क्लाइंट लाइब्रेरी केवल निम्न-स्तरीय कनेक्शन ऑब्जेक्ट प्रदान करती है, तो आपको यह सुनिश्चित करना होगा कि उनके लिए पहुंच थ्रेड-सुरक्षित और कांटा-सुरक्षित है। साथ ही, आपको यह सुनिश्चित करने की ज़रूरत है कि प्रत्येक बार जब आप एक वैध कनेक्शन वापस कर लें (या एक अपवाद उठाएं यदि आप मौजूदा एक को स्थापित या पुन: उपयोग नहीं कर सकते हैं)।

+0

पूरी तरह से उत्तर के लिए धन्यवाद! मैंने वास्तव में थ्रेड और कांटा सुरक्षा नहीं माना था, मैं निश्चित रूप से इसके बारे में सोचूंगा। पुन: कनेक्शन पैरामीटर बग, अच्छी पकड़ और अच्छा फिक्स। पुन: क्लाइंट पूल, एक अच्छा बिंदु, लेकिन कनेक्शन पूल के साथ भी, आप प्रारंभिककरण को केंद्रीकृत करना चाहते हैं और गारंटी देते हैं कि आप पूरे पूल में उसी पूल का उपयोग कर रहे हैं। – knite

+0

पुन: सरल सहायक समारोह, मैंने मूल रूप से इस दृष्टिकोण को माना। Awesome_db * और * इसे कॉल करने की आवश्यकता वाले प्रत्येक मॉड्यूल के कारण यह जल्दी से परेशान हो जाता है। – knite

संबंधित मुद्दे