সর্বাধিক সংখ্যক বার চেষ্টা করার কোনও অজগর উপায় আছে? [নকল]


86

আমার কাছে পাইথন স্ক্রিপ্ট রয়েছে যা একটি ভাগ করা লিনাক্স হোস্টে মাইএসকিউএল সার্ভারটি অনুসন্ধান করছে। কোনও কারণে, মাইএসকিউএল-এ অনুসন্ধানগুলি প্রায়শই একটি "সার্ভার চলে গেছে" ত্রুটিটি ফিরিয়ে দেয়:

_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')

আপনি যদি ততক্ষণে আবার কোয়েরিটি চেষ্টা করেন তবে এটি সাধারণত সফল হয়। সুতরাং, আমি জানতে চাই যে অজগরটিতে কোনও ক্যুরি চালানোর চেষ্টা করার মতো কোনও সঠিক উপায় আছে এবং যদি এটি ব্যর্থ হয় তবে একটি নির্দিষ্ট সংখ্যক চেষ্টা করে আবার চেষ্টা করুন। সম্ভবত আমি পুরোপুরি ছেড়ে দেওয়ার আগে এটি 5 বার চেষ্টা করে দেখতে চাই।

এখানে আমার ধরণের কোড রয়েছে:

conn = MySQLdb.connect(host, user, password, database)
cursor = conn.cursor()

try:
    cursor.execute(query)
    rows = cursor.fetchall()
    for row in rows:
        # do something with the data
except MySQLdb.Error, e:
    print "MySQL Error %d: %s" % (e.args[0], e.args[1])

স্পষ্টতই আমি বাদে আর একটি প্রচেষ্টা বাদ দিয়ে তা করতে পারি, তবে এটি অবিশ্বাস্যভাবে কুৎসিত, এবং আমার মনে হয় এটি অর্জনের জন্য অবশ্যই একটি শালীন উপায় থাকতে হবে।


4
এটা একটা ভাল দিক. আমি সম্ভবত কয়েক সেকেন্ডের জন্য ঘুমিয়ে ফেলতাম। আমি জানিনা সার্ভারে মাইএসকিউএল ইনস্টলেশনটির সাথে কী হয়েছে, তবে মনে হচ্ছে এটি এক সেকেন্ড ব্যর্থ হয়েছে এবং পরেরটি এটি কাজ করে।
বেন

4
@ ইউভাল এ: এটি একটি সাধারণ কাজ। আমার সন্দেহ হয় এটি এয়ারল্যাঙেও নির্মিত in
jfs

4
কেবল কিছু উল্লেখ করা যায় না যে ভুল কিছু নয়, মাইএসকিএলে নিষ্ক্রিয় সংযোগগুলি ফেলে দেওয়ার জন্য মাইএসকিএল কনফিগার করার জন্য একটি ওয়েট টাইমআউটআউট ভেরিয়েবল রয়েছে।
অ্যান্ডি

উত্তর:


98

কেমন:

conn = MySQLdb.connect(host, user, password, database)
cursor = conn.cursor()
attempts = 0

while attempts < 3:
    try:
        cursor.execute(query)
        rows = cursor.fetchall()
        for row in rows:
            # do something with the data
        break
    except MySQLdb.Error, e:
        attempts += 1
        print "MySQL Error %d: %s" % (e.args[0], e.args[1])

20
বাfor attempt_number in range(3)
সিডলারি

8
ঠিক আছে, আমি আমার পছন্দ করি কারণ এটি স্পষ্ট করে তোলে যে ব্যতিক্রম ঘটলে প্রচেষ্টা কেবল বেড়ে যায়।
ডানা

4
হ্যাঁ, আমি অনুমান করি যে আমি whileবেশিরভাগ মানুষের তুলনায় অসীম লুপগুলি ক্রিমিংয়ের বিষয়ে আরও বেহাল ।
সিডলারি

4
-1: বিরতি পছন্দ করবেন না। "না করা অবস্থায় <3:" ভাল করার মতো পছন্দ করুন।
এস .লট

4
আমি বিরতি পছন্দ করি, তবে কিছুক্ষণের মতো নয়। এটি পাইথোনিকের চেয়ে সি-ইশের মতো বেশি। আমি পরিসীমা জন্য ভাল imho।
হ্যাসেন

78

ডানার উত্তরের উপর ভিত্তি করে, আপনি এটি ডেকরেটার হিসাবে এটি করতে চাইতে পারেন:

def retry(howmany):
    def tryIt(func):
        def f():
            attempts = 0
            while attempts < howmany:
                try:
                    return func()
                except:
                    attempts += 1
        return f
    return tryIt

তারপরে ...

@retry(5)
def the_db_func():
    # [...]

decoratorমডিউলটি ব্যবহার করে বর্ধিত সংস্করণ

import decorator, time

def retry(howmany, *exception_types, **kwargs):
    timeout = kwargs.get('timeout', 0.0) # seconds
    @decorator.decorator
    def tryIt(func, *fargs, **fkwargs):
        for _ in xrange(howmany):
            try: return func(*fargs, **fkwargs)
            except exception_types or Exception:
                if timeout is not None: time.sleep(timeout)
    return tryIt

তারপরে ...

@retry(5, MySQLdb.Error, timeout=0.5)
def the_db_func():
    # [...]

মডিউলটি ইনস্টল করতেdecorator :

$ easy_install decorator

4
সাজসজ্জারকে সম্ভবত একটি ব্যতিক্রম শ্রেণিও নেওয়া উচিত, সুতরাং আপনাকে খালি ছাড়া আর ব্যবহার করতে হবে না; অর্থাত্ @retry (5, মাইএসকিউএলডিবি। এরর)
সিডলারি

নিফটি! আমি কখনই সাজসজ্জার ব্যবহার করার কথা ভাবি না: পি
ডানা

এটি কেবল "
ফানক

বাহ! সতর্ক থাকুন জন্য ধন্যবাদ।
dwc

আপনি কি আসলে এটি চালানোর চেষ্টা করেছিলেন? এটি কাজ করে না। সমস্যাটি হ'ল ট্রাইআইটি ফাংশনে ফান () কলটি আপনি ফাংশনটি সাজানোর সাথে সাথেই কার্যকর হয়ে যায় , এবং আপনি যখন সজ্জিত ফাংশনটিকে আসলে কল করেন তখন তা নয় । আপনার আর একটি নেস্টেড ফাংশন দরকার।
স্টিভ লশ

12

আপডেট: পুনরায় চেষ্টা করা লাইব্রেরির টেনেসি নামে আরও ভাল রক্ষণাবেক্ষণযোগ্য কাঁটাচামচ রয়েছে যা আরও বেশি বৈশিষ্ট্য সমর্থন করে এবং সাধারণভাবে আরও নমনীয়।


হ্যাঁ, আবার চেষ্টা করার লাইব্রেরি রয়েছে , এতে এক সজ্জা রয়েছে যা বিভিন্ন ধরণের পুনরায় চেষ্টা করার যুক্তি প্রয়োগ করে যা আপনি একত্রিত করতে পারেন:

কিছু উদাহরণ:

@retry(stop_max_attempt_number=7)
def stop_after_7_attempts():
    print "Stopping after 7 attempts"

@retry(wait_fixed=2000)
def wait_2_s():
    print "Wait 2 second between retries"

@retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)
def wait_exponential_1000():
    print "Wait 2^x * 1000 milliseconds between each retry,"
    print "up to 10 seconds, then 10 seconds afterwards"

4
পুনরায় চেষ্টা করা লাইব্রেরিটি ত্যাগের লাইব্রেরিটি ছাড়িয়ে যায়
শেঠ

8
conn = MySQLdb.connect(host, user, password, database)
cursor = conn.cursor()

for i in range(3):
    try:
        cursor.execute(query)
        rows = cursor.fetchall()
        for row in rows:
            # do something with the data
        break
    except MySQLdb.Error, e:
        print "MySQL Error %d: %s" % (e.args[0], e.args[1])

4
আপনি নীচে একটি অন্য যোগ করতে পারেন :else: raise TooManyRetriesCustomException
বব স্টেইন

6

আমি এটির মতো রিফ্যাক্টর করতাম:

def callee(cursor):
    cursor.execute(query)
    rows = cursor.fetchall()
    for row in rows:
        # do something with the data

def caller(attempt_count=3, wait_interval=20):
    """:param wait_interval: In seconds."""
    conn = MySQLdb.connect(host, user, password, database)
    cursor = conn.cursor()
    for attempt_number in range(attempt_count):
        try:
            callee(cursor)
        except MySQLdb.Error, e:
            logging.warn("MySQL Error %d: %s", e.args[0], e.args[1])
            time.sleep(wait_interval)
        else:
            break

calleeফাংশনটি ফ্যাক্টরিং করার ফলে কার্যকারিতাটি বিচ্ছিন্ন হয়ে পড়েছে যাতে পুনরায় চেষ্টা কোডটিতে জড়িত না হয়ে ব্যবসায়ের যুক্তি দেখতে সহজ হয়।


-1: অন্যথায় এবং বিরতি ... আইকি। বিরতির তুলনায় "কাজ না করে এবং গণনা করুন! = চেষ্টা_কাউন্ট" কে আরও পরিষ্কার করুন।
এসলট

4
সত্যি? আমি ভেবেছিলাম এটি এভাবে আরও বোধগম্য হয়েছে - যদি ব্যতিক্রম না ঘটে তবে লুপটি ভেঙে ফেলুন। লুপগুলি চলাকালীন আমি সীমাহীনভাবে অতিরিক্ত ভয় পেতে পারি।
সিডলারি

4
+1: ভাষাটি কোড কোড স্ট্রাকচারের জন্য এটি করার জন্য অন্তর্ভুক্ত করলে আমি পতাকাটির পরিবর্তনশীলগুলি ঘৃণা করি। বোনাস পয়েন্টগুলির জন্য, সমস্ত প্রচেষ্টা ব্যর্থ হওয়ার সাথে মোকাবিলা করার জন্য অন্য কোনও বিষয় রাখুন।
xorsyst

6

এস.লোটের মতো আমিও একটি পতাকা পছন্দ করি যা শেষ হয়ে গেছে কিনা তা যাচাই করতে:

conn = MySQLdb.connect(host, user, password, database)
cursor = conn.cursor()

success = False
attempts = 0

while attempts < 3 and not success:
    try:
        cursor.execute(query)
        rows = cursor.fetchall()
        for row in rows:
            # do something with the data
        success = True 
    except MySQLdb.Error, e:
        print "MySQL Error %d: %s" % (e.args[0], e.args[1])
        attempts += 1

1
def successful_transaction(transaction):
    try:
        transaction()
        return True
    except SQL...:
        return False

succeeded = any(successful_transaction(transaction)
                for transaction in repeat(transaction, 3))

1

1. সংজ্ঞা:

def try_three_times(express):
    att = 0
    while att < 3:
        try: return express()
        except: att += 1
    else: return u"FAILED"

2. ব্যবহার:

try_three_times(lambda: do_some_function_or_express())

আমি এটি পার্স এইচটিএমএল প্রসঙ্গে ব্যবহার করি।


0

এটি আমার জেনেরিক সমাধান:

class TryTimes(object):
    ''' A context-managed coroutine that returns True until a number of tries have been reached. '''

    def __init__(self, times):
        ''' times: Number of retries before failing. '''
        self.times = times
        self.count = 0

    def __next__(self):
        ''' A generator expression that counts up to times. '''
        while self.count < self.times:
            self.count += 1
        yield False

    def __call__(self, *args, **kwargs):
        ''' This allows "o() calls for "o = TryTimes(3)". '''
        return self.__next__().next()

    def __enter__(self):
        ''' Context manager entry, bound to t in "with TryTimes(3) as t" '''
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        ''' Context manager exit. '''
        return False # don't suppress exception

এটি নিম্নলিখিতগুলির মতো কোডের অনুমতি দেয়:

with TryTimes(3) as t:
    while t():
        print "Your code to try several times"

এছাড়াও সম্ভব:

t = TryTimes(3)
while t():
    print "Your code to try several times"

এটি আরও স্বজ্ঞাত উপায়ে ব্যতিক্রমগুলি পরিচালনা করে উন্নত হতে পারে, আমি আশা করি। পরামর্শ খুলুন।


0

সর্বাধিক প্রভাবের জন্য আপনি forএকটি elseধারা সহ একটি লুপ ব্যবহার করতে পারেন :

conn = MySQLdb.connect(host, user, password, database)
cursor = conn.cursor()

for n in range(3):
    try:
        cursor.execute(query)
    except MySQLdb.Error, e:
        print "MySQL Error %d: %s" % (e.args[0], e.args[1])
    else:
        rows = cursor.fetchall()
        for row in rows:
            # do something with the data
        break
else:
    # All attempts failed, raise a real error or whatever

কীটিটি সাফল্যের সাথে সাথে লুপটি ভেঙে ফেলা হবে। elseলুপ একটি ছাড়া সমাপ্ত যদি দফা শুধুমাত্র ট্রিগার করা হবে না break

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.