Search code examples
pythonpython-decorators

Python decorator


from random import randint
import  time
state = 0 #close

open_time = 0
failure_count = 0
count = 0
status = {0 : "closed" , 2 : " open" , 1 : "half closed"}
def circuitbreaker(func):
    global count
    global open_time , state
    print("circuit status "+ status.get(state))
    if state ==0: #close state
        try:
            func()
        except Exception as ex:
            print(ex)
            count+=1
            if count>2:
                print("opening circuit breaker")
                state = 2
                open_time = int(time.time())
    elif (state == 2): #open state
        if( time.time() - open_time > 5) :
            state = 1
        else:
            print("circuit opened")
    else:
        try:
            func()
            count = 0
            open_time = 0
            print("closing circuit breaker")
            state = 0
        except Exception as ex:
            state = 2
            open_time = int(time.time())
            print("opening circuit breaker")

@circuitbreaker
def generic_func():
    a = randint(0,9)
    print("hello")
    print("random number = "+str(a))
    if a>4:
        return a
    else:
        raise Exception('Yalla!')

if __name__=="__main__":

    # while(True):
    #     generic_func()
        time.sleep(1)

I have this code . I have a couple of question:- 1)why does generic function is being called even if I comment it in main.

2)when I uncomment the commented part in main function . I get following error .How do I properly call this generic function . My motive is to implement a circuit breaker who closed when there is some kind of error or exception in a calling function . I can directly use :- circuitbreaker(calling function) but I wanted to use decorators

Traceback (most recent call last):
circuit status closed
hello
  File "/Users/abhishekkumar/PycharmProjects/RateLimiter/circuitbreaker.py", line 53, in <module>
random number = 1
Yalla!
    generic_func()
TypeError: 'NoneType' object is not callable

Process finished with exit code 1

The issue was the decorator should be returning a function object and should have relevant logic inside a function and then return that function otherwise it returns none object


Solution

  • the answer to question #1: it's because of circuitbreaker decorator, as its logic is executed during module import and it calls the decorated function. Check out the following lines

    ...
    try:
        func() # <-- here
    except Exception as ex:
        print(ex)
        ...
    

    The way of implementing decorators is to return a wrapper function, which contains the business logic:

    from functools import wraps
    
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            ... your logic here ...
        return wrapper
    

    The answer to question #2 derives from the previous one.