def task_decorator(method):
 @wraps(method)
 def _wrapper(self, *args, **kwds):
  rnd_id = random.randint(1, MAX_RAND)
  function_id = ('%s_%s' % (method.__name__, rnd_id))
  self._add_task(function_id)
  try:
   result = method(self, function_id, *args, **kwds)
  except:
   self._task_done(function_id)
   raise
  else:
   self._task_done(function_id)
   return result
 return _wrapper

def task_decorator ( method ) : @ wraps ( method ) def _wrapper ( self , * args , ** kwds ) : rnd_id = random . randint ( 1 , MAX_RAND ) function_id = ( '%s_%s' % ( method . __name__ , rnd_id ) ) self . _add_task ( function_id ) try : result = method ( self , function_id , * args , ** kwds ) except : self . _task_done ( function_id ) raise else : self . _task_done ( function_id ) return result return _wrapper
makes sure that for each task we call _add_task() and _task_done() which will avoid some ugly race conditions .