Search code examples
pythondecoratorttl

Writing a TTL decorator in Python


I'm trying to write a TTL decorator in python. Basically I give it raise an exception if the function doesn't answer in the selected time.

You can find the thead2 snippets on http://sebulba.wikispaces.com/recipe+thread2

from thread2 import Thread

"""  A TTL decorator. """
class Worker(Thread):
    def __init__(self, q, f, args, kvargs):
        Thread.__init__(self)

        self.q = q
        self.f = f
        self.args = args
        self.kvargs = kvargs

    def run(self,):
        try:
            res = (True, self.f(*self.args, **self.kvargs))
            self.q.put(res)
        except Exception, e:
            self.q.put((False, e))

class Referee(Thread):
    def __init__(self,q, ttl,exception_factory):
        Thread.__init__(self)

        self.exception_factory=exception_factory    
        self.q=q
        self.ttl=ttl

    def run(self):
        time.sleep(self.ttl)
        res = (False, self.exception_factory())
        self.q.put(res)

def raise_if_too_long(ttl, exception_factory=lambda :RuntimeError("Timeout")):
    def raise_if_too_long_aux(f):
        def ritl(*args,**kvargs):
            q = Queue.Queue(2)

            referee = Referee(q, ttl, exception_factory)
            worker = Worker(q,f,args,kvargs)

            worker.start()
            referee.start()

            (valid, res)= q.get(1)

            q.task_done()

            referee.terminate()
            worker.terminate()

            if valid:
                return res
            else:
                raise res

        return ritl

    return raise_if_too_long_aux

However, I get some pretty bad result. It seems like sometimes the function is returning alright yet the decorator doesn't return until the TTL is reached and the error raises.

Do you see something wrong in this code? Is there a common way/library to write function with a TTL in python?


Solution

  • The code provided is a bit tough to follow -- how is it going to raise an exception in the right place at the right time in the right thread?

    Consider this rough flow:

    Decorator function called with target function. Return a function which:

    1. Starts thread, calling target function
    2. Joins to thread using thread.join([timeout])
    3. If you get a timeout, raise an exception, and ignore the result of the thread.
    4. If you don't get a timeout, capture the result of the thread and return it.

    (You would need to devise a way to capture the output of the thread...)

    See http://docs.python.org/library/threading.html for info on the threading timeout...

    (Or just start using erlang :)