python重試(指數退避算法)


本文實現了一個重試的裝飾器,並且使用了指數退避算法。指數退避算法實現還是很簡單的。先上代碼再詳細解釋。

1、指數退避算法

欠奉。http://hugnew.com/?p=814

 

2、重試裝飾器retry實現

# -*- coding:utf-8 -*-
import time
from random import randint
from struct import Result, ProcedureException


def retry(max_retries=3, max_wait_interval=10, period=1, rand=False):

    def _retry(func):

        def __retry(*args, **kwargs):
            MAX_RETRIES = max_retries
            MAX_WAIT_INTERVAL = max_wait_interval
            PERIOD = period
            RAND = rand

            retries = 0
            error = None
            while retries < MAX_RETRIES:
                try:
                    result = func(*args, **kwargs)
                    if result.code == Result.ERROR:
                        raise ProcedureException("procedure occur error")
                    if result.code == Result.TIMEOUT:
                        raise ProcedureException("procedure request time out")
                    if result.code == Result.SUCCESS:
                        return result
                except Exception, ex:
                    error = ex
                finally:
                    sleep_time = min(2 ** retries * PERIOD if not RAND else randint(0, 2 ** retries) * PERIOD, MAX_WAIT_INTERVAL)
                    time.sleep(sleep_time)
                    retries += 1
                    print "", retries, "次重試, ", "等待" , sleep_time, ""
            if retries == MAX_RETRIES:
                if error:
                    raise error
                else:
                    raise ProcedureException("unknown")
        return __retry
    return _retry

這里我們自己定義了兩個東西:

1)枚舉類Result,標識過程調用的狀態,其中有三個狀態,成功SUCCESS,失敗ERROR,超時TIMEOUT;

2)異常ProcedureException,在retry裝飾器中我們判斷了狀態,如果是失敗和超時場景,我們將會拋出這個異常。

這兩個東西的實現如下

from enum import Enum, unique

@unique
class Result(Enum):
    SUCCESS = 0
    TIMEOUT = 1
    ERROR = 2


class ProcedureException(Exception):
    def __init__(self, message):
        Exception.__init__(self, message)

retry裝飾器會重試以下兩個場景:

1)Procedure函數func出現異常:TIMEOUT和ERROR

2)未知異常:Procedure函數func可以拋出未能處理的異常,例如func函數可能是網絡讀寫,遇到網絡超時,鏈接斷開等,拋出timeout或者broken pipe。

是否隨機:

1)不隨機,將會以2**retries,作為重試時間

2)隨機,將會在(0,2**retries)之間隨機一個數,作為重試時間

其實指數退避算法就是使用隨機“抖動”的方式來解決高並發場景下信道碰撞的,但是我們的應用場景也有需要持續增加重試間隔(而不是增加幾率)的情況。

 

3、測試一下

我們測試兩個場景,重試10次和隨機,重試5次不隨機。

1)重試10次,隨機,最大間隔10s

# -*- coding:utf-8 -*-
from decorator import retry
from struct import Result

@retry(rand=True, max_retries=10, max_wait_interval=10)
def do_something():

    class result(object):
        def __init__(self, code):
            self.code = code
    print "##########  調用結果", Result.ERROR, " ############"
    return result(Result.ERROR)

do_something()

輸出結果

/Users/didi/anaconda/bin/python /Users/didi/test/pythoneer/retry/test.py
##########  調用結果 Result.ERROR  ############
第 1 次重試,  等待 0 秒
##########  調用結果 Result.ERROR  ############
第 2 次重試,  等待 1##########  調用結果 Result.ERROR  ############
第 3 次重試,  等待 2##########  調用結果 Result.ERROR  ############
第 4 次重試,  等待 0 秒
##########  調用結果 Result.ERROR  ############
第 5 次重試,  等待 10##########  調用結果 Result.ERROR  ############
第 6 次重試,  等待 10##########  調用結果 Result.ERROR  ############
第 7 次重試,  等待 10##########  調用結果 Result.ERROR  ############
第 8 次重試,  等待 10##########  調用結果 Result.ERROR  ############
第 9 次重試,  等待 10##########  調用結果 Result.ERROR  ############
Traceback (most recent call last):
第 10 次重試,  等待 10 秒
  File "/Users/didi/test/pythoneer/retry/test.py", line 14, in <module>
    do_something()
  File "/Users/didi/test/pythoneer/retry/decorator.py", line 36, in __retry
    if error:
struct.ProcedureException: procedure occur error

 

2)重試5次,不隨機,最大間隔10s

# -*- coding:utf-8 -*-
from decorator import retry
from struct import Result

@retry(rand=False, max_retries=5, max_wait_interval=10)
def do_something():

    class result(object):
        def __init__(self, code):
            self.code = code
    print "##########  調用結果", Result.ERROR, " ############"
    return result(Result.ERROR)

do_something()

輸出結果

/Users/didi/anaconda/bin/python /Users/didi/test/pythoneer/retry/test.py
##########  調用結果 Result.ERROR  ############
第 1 次重試,  等待 1##########  調用結果 Result.ERROR  ############
第 2 次重試,  等待 2##########  調用結果 Result.ERROR  ############
第 3 次重試,  等待 4##########  調用結果 Result.ERROR  ############
第 4 次重試,  等待 8##########  調用結果 Result.ERROR  ############
第 5 次重試,  等待 10 秒
Traceback (most recent call last):
  File "/Users/didi/test/pythoneer/retry/test.py", line 14, in <module>
    do_something()
  File "/Users/didi/test/pythoneer/retry/decorator.py", line 37, in __retry
    raise error
struct.ProcedureException: procedure occur error

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM