#NEWLINE# def serial_task( unique_key , default_retry_delay = 30 , timeout = ( 5 * 60 ) , max_retries = 3 , queue = 'background_queue' ) : #NEWLINE# #INDENT# '\n    Define a task to be executed one at a time.  If another serial_task with\n    the same unique_key is currently in process, this will retry after a delay.\n\n    :param unique_key: string used to lock the task.  There will be one lock\n        per unique value.  You may use any arguments that will be passed to the\n        function.  See example.\n    :param default_retry_delay: seconds to wait before retrying if a lock is\n        encountered\n    :param timeout: timeout on the lock (in seconds).  Normally the lock should\n        be released when the task completes, but you should also define a\n        timeout in case something goes wrong.  This must be greater than the\n        maximum length of the task.\n\n    Usage:\n        @serial_task("{user.username}-{from}", default_retry_delay=2)\n        def greet(user, from="Dimagi"):\n            ...\n\n        greet.delay(joeshmoe)\n        # Locking key used would be "greet-joeshmoe@test.commcarehq.org-Dimagi"\n    ' #NEWLINE# def decorator( fn ) : #NEWLINE# #INDENT# @ task ( bind = True , queue = queue , ignore_result = True , default_retry_delay = default_retry_delay , max_retries = max_retries ) #NEWLINE# @ wraps ( fn ) #NEWLINE# def _inner( self , * args , **kwargs ) : #NEWLINE# #INDENT# if settings . UNIT_TESTING : #NEWLINE# #INDENT# fn ( * args , ** kwargs ) #NEWLINE# return #NEWLINE# #UNINDENT# client = get_redis_client ( ) #NEWLINE# key = _get_unique_key ( unique_key , fn , * args , ** kwargs ) #NEWLINE# lock = client . lock ( key , timeout = timeout ) #NEWLINE# if lock . acquire ( blocking = False ) : #NEWLINE# #INDENT# try : #NEWLINE# #INDENT# fn ( * args , ** kwargs ) #NEWLINE# #UNINDENT# except Exception : #NEWLINE# #INDENT# lock . release ( ) #NEWLINE# raise #NEWLINE# #UNINDENT# lock . release ( ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# msg = "Could not aquire lock '{}' for task '{}'." . format ( key , fn . __name__ ) #NEWLINE# self . retry ( exc = CouldNotAqcuireLock ( msg ) ) #NEWLINE# #UNINDENT# #UNINDENT# return _inner #NEWLINE# #UNINDENT# return decorator