#stdlib
import os
from atexit import register

#local
from semaphore import RedisSemaphore

def rate_limited(*args, **kwargs):
    '''
    Semaphore decorator.
    
    @rate_limited
    def foo():
        pass
        
    Will only allow one instance of foo to operate at one time - across all servers
    running your code.
    
    You can increase the limit easily:
    
    @rate_limited(5)
    def five_foo():
        pass
        
    Maintains locks on redis-db0/1 unless host/db are overwritten in kwargs
    '''
    
    if 'host' not in kwargs:
        kwargs['host'] = os.environ.get('REDIS_HOST', 'localhost')
    if 'db' not in kwargs:
        kwargs['db'] = os.environ.get('REDIS_DB', 0)

    def _rate_limited(f):
        name = '.'.join((f.__module__, f.__name__))
        s = RedisSemaphore(name, limit, acquire=False, **kwargs)
        
        @register
        def exit():
            s._close_gracefully()
        
        def fx(*args, **fkwargs):
            s.acquire()
 
            try:
                ret = f(*args, **fkwargs)
            finally:
                s.release()

            return ret
    
        return fx
        
    if callable(args[0]):
        f = args[0]
        limit = 1
        return _rate_limited(f)
    else:
        limit = args[0]
        return _rate_limited
   
@@ -38,16 +38,84 @@
 register
+%0Afrom random import triangular%0A%0A#3rd party%0Afrom gevent import sleep 
 %0A%0A#local
@@ -151,16 +151,42 @@
 emaphore
+%0Afrom logger import Logger
 %0A%0Adef ra
@@ -1395,24 +1395,940 @@
 return _rate_limited%0A   
+%0A   %0Adef retry(*args, **kwargs):%0A    def _retry(f):%0A        def _fx(*args, **fkwargs):%0A            success = False%0A            i = 0%0A            while not success:%0A                %0A                sleep(i*triangular(*interval))%0A                %0A                if i %3E limit:%0A                    raise Exception('Retry Limit Exceeded: %25s.%25s - %25s %25s'%25(f.__module__, f.__Name__,%0A                                                                           args, fkwargs))%0A                try:%0A                    success = f(*args, **fkwargs)%0A                except:%0A                    import traceback%0A                    traceback.print_exc()%0A                finally:%0A                    i += 1%0A                    %0A                    %0A        return _fx%0A%0A    %0A    limit = kwargs.get('limit', 15)%0A    interval = kwargs.get('interval', (3, 5))%0A    %0A    return _retry%0A                    %0A                %0A        %0A    

Add retry decorator