An auto-retry recipe for Twisted.

You can find chinese version of this article here : Deferred應用的實例 : retry

For grabbing pages from websites with twisted, you can write this:

getPage("http://www.google.com").addCallback(printPage)

But what about the HTTP server is too busy to response? Your getPage fails. For reasons, you have to modify your program to retry once the getPage failed. So you might write a method like this:

getPageRetry(5, "http://www.google.com")

Well, it seems works fine, but how about you got some other operations to retry? connectToClient, getTime and so on. You have to write

connectToClientRetry(5, "example.com")
getTimeRetry(5, "timeserver.com")

You have to write retry-version version of every function that may fail. That’s not a good idea. Twisted provides a very beautiful ansyc callback object named Deferred. It looks like Chain-of-responsibility, but it can also handle errors well. With its beautiful design, I wrote a retry function that can warp all function return Deferred that might fail. That’s no need to modify any exists code of getPage to make it to retry automatically. Here is the recipe:

import logging  
 
from twisted.internet import defer  
 
log = logging.getLogger('retry')  
 
def retry(times, func, *args, **kwargs):
    """retry a defer function 
 
    @param times: how many times to retry
    @param func: defer function
    """
    errorList = []
    deferred = defer.Deferred()
    def run():
        log.info('Try %s(*%s, **%s)', func.__name__, args, kwargs)
        d = func(*args, **kwargs)
        d.addCallbacks(deferred.callback, error)
    def error(error):
        errorList.append(error)
        # Retry
        if len(errorList) < times:
            log.warn('Failed to try %s(*%s, **%s) %d times, retry...', func.__name__, args, kwargs, len(errorList))
            run()
        # Fail
        else:
            log.error('Failed to try %s(*%s, **%s) over %d times, stop', func.__name__, args, kwargs, len(errorList))
            deferred.errback(errorList)
    run()
    return deferred

Here you are! Now you can use it to make your operation to retry automatically!

from twisted.internet import reactor
from twisted.web.client import getPage  
 
def output(data):
    print 'output', data  
 
def error(error):
    print 'finall error', error  
 
d = retry(3, getPage, 'http://www.google2.com')
d.addCallbacks(output, error)  
 
d = retry(3, getPage, 'http://www.google.com')
d.addCallbacks(output, error)  
 
reactor.run()
This entry was posted in 分享, English Articles, Python and tagged , , , , . Bookmark the permalink.

One Response to An auto-retry recipe for Twisted.

  1. Pingback: Tweets that mention An auto-retry recipe for Twisted. » 程式設計 遇上 小提琴 -- Topsy.com

發表迴響

您的電子郵件位址並不會被公開。 必要欄位標記為 *

*

您可以使用這些 HTML 標籤與屬性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">