Exemplo n.º 1
0
        /// <summary>
        /// Executes the provided retry callback. In case the callback is successful, the returned value of type
        /// R will be returned. In case of failure (the retry callback throws an exception), the operation will be
        /// retried while the specified retry policy allows it.
        ///
        /// If some back-off policy is defined, the amount of time configured in the policy will be waited before
        /// retrying the callback execution.
        ///
        /// When the callback fails and the retry policy does not allow more retries for some exception, a
        /// RetryExhaustedException will be thrown (containing a reference to the exception that caused the
        /// failure in the retry callback).
        /// </summary>
        /// <param name="pendingRetry">Handle to an operation pending for retries as returned by SaveForRetry.</param>
        /// <param name="retryCallback">The function that will be invoked in each retry</param>
        /// <param name="recoveryCallback">An optional function that will be invoked when the retries over the operation have been exhausted according the specified RetryPolicy . If null, it be ignored.</param>
        /// <param name="cancellationToken">Cancellation token that allows to manually indicate that the retries should stop.</returns>
        public R DoExecute <T, R>(PendingRetry <T> pendingRetry, Func <T, R> retryCallback, Func <T, R> recoveryCallback, CancellationToken cancellationToken)
        {
            var collection = database.GetCollection <PendingRetry <T> >(RetryTemplate.PENDING_RETRIES_COLLECTION_NAME);

            Exception lastException = null;
            var       retryPolicy   = RetryPolicy;
            var       backOffPolicy = BackOffPolicy;

            retryPolicy.StartContext();
            backOffPolicy.StartContext();

            while (retryPolicy.CanRetry(lastException) && !cancellationToken.IsCancellationRequested)
            {
                try {
                    lastException = null;
                    R result = retryCallback.Invoke(pendingRetry.Argument);
                    if (!collection.Delete(pendingRetry.Id))
                    {
                        throw new DeleteRetryException("The pending retry document cannot be found on database");
                    }
                    return(result);
                }
                catch (DeleteRetryException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    lastException = e;

                    if (retryPolicy.CanRetry(lastException) && !cancellationToken.IsCancellationRequested)
                    {
                        retryPolicy.RegisterRetry(lastException);
                        backOffPolicy.BackOff();
                    }
                }
            }

            if (cancellationToken.IsCancellationRequested)
            {
                throw new RetryInterruptedException("The execution of retries has been explicitly cancelled.");
            }
            else
            {
                collection.Delete(pendingRetry.Id);
                return(HandleRetryExhausted(recoveryCallback, pendingRetry.Argument, lastException));
            }
        }
Exemplo n.º 2
0
        /// <summary>Saves a new operation as pending for retries.</summary>
        /// <param name="operationId">The operation identifier, that can be subsequently used to look for peding retry operations.</param>
        /// <param name="argument">The argument that must be provided to the operation when retried. It may be null.</param>
        /// <returns>A new instance of <see cref="PendingRetry"/> referring to the new created operation pending for retries.</returns>
        public PendingRetry <T> SaveForRetry <T>(string operationId, T argument)
        {
            var collection = database.GetCollection <PendingRetry <T> >(PENDING_RETRIES_COLLECTION_NAME);

            var pendingRetry = new PendingRetry <T>
            {
                Argument    = argument,
                OperationId = operationId
            };

            // Create index for the OperationId field
            collection.EnsureIndex(x => x.OperationId);

            lock (this)
            {
                collection.Insert(pendingRetry);

                BlockingCollection <PendingRetry <T> > blockingRetriesCollection = blockingOperationCollections.GetOrAdd(operationId,
                                                                                                                         new BlockingCollection <PendingRetry <T> >()) as BlockingCollection <PendingRetry <T> >;
                blockingRetriesCollection.Add(pendingRetry);
            }

            return(pendingRetry);
        }
Exemplo n.º 3
0
        private void MarkAsCompleted <T>(PendingRetry <T> pendingRetry)
        {
            var collection = database.GetCollection <PendingRetry <T> >(PENDING_RETRIES_COLLECTION_NAME);

            collection.Delete(pendingRetry.Id);
        }