예제 #1
0
        public static async Task <T> Retry <T>(this IRetryPolicy retryPolicy, Func <Task <T> > retryMethod,
                                               CancellationToken cancellationToken = default(CancellationToken))
        {
            var inlinePipeContext = new InlinePipeContext(cancellationToken);

            using (RetryPolicyContext <InlinePipeContext> policyContext = retryPolicy.CreatePolicyContext(inlinePipeContext))
            {
                try
                {
                    return(await retryMethod().ConfigureAwait(false));
                }
                catch (Exception exception)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        if (exception is OperationCanceledException canceledException &&
                            canceledException.CancellationToken == cancellationToken)
                        {
                            throw;
                        }

                        cancellationToken.ThrowIfCancellationRequested();
                    }

                    if (!policyContext.CanRetry(exception, out RetryContext <InlinePipeContext> retryContext))
                    {
                        throw;
                    }

                    return(await Attempt(inlinePipeContext, retryContext, retryMethod).ConfigureAwait(false));
                }
            }
        }
예제 #2
0
        public static async Task Retry(this IRetryPolicy retryPolicy, Func <Task> retryMethod, CancellationToken cancellationToken = default(CancellationToken))
        {
            RetryPolicyContext <InlinePipeContext> policyContext = retryPolicy.CreatePolicyContext(new InlinePipeContext(cancellationToken));

            try
            {
                await retryMethod().ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    var canceledException = exception as OperationCanceledException;
                    if (canceledException != null && canceledException.CancellationToken == cancellationToken)
                    {
                        throw;
                    }

                    cancellationToken.ThrowIfCancellationRequested();
                }

                RetryContext <InlinePipeContext> retryContext;
                if (!policyContext.CanRetry(exception, out retryContext))
                {
                    throw;
                }

                await Attempt(retryContext, retryMethod).ConfigureAwait(false);
            }
        }
예제 #3
0
        public Task Send(ConsumeContext <TData> context)
        {
            using (RetryPolicyContext <ConsumeContext <TData> > policyContext = _retryPolicy.CreatePolicyContext(context))
            {
                var exception = new SagaException("An existing saga instance was not found", typeof(TInstance), typeof(TData), context.CorrelationId ?? Guid
                                                  .Empty);

                if (!policyContext.CanRetry(exception, out RetryContext <ConsumeContext <TData> > retryContext))
                {
                    return(_finalPipe.Send(context));
                }

                int previousDeliveryCount = context.GetRedeliveryCount();
                for (int retryIndex = 0; retryIndex < previousDeliveryCount; retryIndex++)
                {
                    if (!retryContext.CanRetry(exception, out retryContext))
                    {
                        return(_finalPipe.Send(context));
                    }
                }

                var schedulerContext = context.GetPayload <MessageSchedulerContext>();

                MessageRedeliveryContext redeliveryContext = new ScheduleMessageRedeliveryContext <TData>(context, schedulerContext);

                var delay = retryContext.Delay ?? TimeSpan.Zero;

                return(redeliveryContext.ScheduleRedelivery(delay));
            }
        }
예제 #4
0
        public static async Task Retry <T>(this IRetryPolicy retryPolicy, ConsumeContext <T> context,
                                           Func <ConsumeContext <T>, Task> retryMethod)
            where T : class
        {
            using (RetryPolicyContext <ConsumeContext <T> > policyContext = retryPolicy.CreatePolicyContext(context))
            {
                try
                {
                    await retryMethod(policyContext.Context).ConfigureAwait(false);
                }
                catch (Exception exception)
                {
                    if (context.TryGetPayload(out RetryContext <ConsumeContext <T> > retryContext))
                    {
                        throw;
                    }

                    if (!policyContext.CanRetry(exception, out retryContext))
                    {
                        context.GetOrAddPayload(() => retryContext);
                        throw;
                    }

                    await Attempt(retryContext, retryMethod).ConfigureAwait(false);
                }
            }
        }
        public static async Task Retry(this IRetryPolicy retryPolicy, Func <Task> retryMethod, CancellationToken cancellationToken = default)
        {
            var inlinePipeContext = new InlinePipeContext(cancellationToken);

            using (RetryPolicyContext <InlinePipeContext> policyContext = retryPolicy.CreatePolicyContext(inlinePipeContext))
            {
                try
                {
                    await retryMethod().ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception exception)
                {
                    if (!policyContext.CanRetry(exception, out RetryContext <InlinePipeContext> retryContext))
                    {
                        throw;
                    }

                    try
                    {
                        await Attempt(inlinePipeContext, retryContext, retryMethod).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException ex) when(ex.CancellationToken == cancellationToken)
                    {
                    }

                    throw;
                }
            }
        }
예제 #6
0
        async Task IFilter <TContext> .Send(TContext context, IPipe <TContext> next)
        {
            RetryPolicyContext <TContext> policyContext = _retryPolicy.CreatePolicyContext(context);

            try
            {
                await next.Send(policyContext.Context).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                RetryContext <TContext> payloadRetryContext;
                if (context.TryGetPayload(out payloadRetryContext) && !payloadRetryContext.CanRetry(exception, out payloadRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    throw;
                }

                RetryContext <TContext> retryContext;
                if (!policyContext.CanRetry(exception, out retryContext))
                {
                    await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                    context.GetOrAddPayload(() => retryContext);
                    throw;
                }

                await Attempt(retryContext, next).ConfigureAwait(false);
            }
        }
예제 #7
0
        async Task IFilter <TContext> .Send(TContext context, IPipe <TContext> next)
        {
            RetryPolicyContext <TContext> policyContext = _retryPolicy.CreatePolicyContext(context);

            await _observers.PostCreate(policyContext).ConfigureAwait(false);

            try
            {
                await next.Send(policyContext.Context).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                RetryContext <TContext> payloadRetryContext;
                if (context.TryGetPayload(out payloadRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(payloadRetryContext).ConfigureAwait(false);

                    throw;
                }

                RetryContext genericRetryContext;
                if (context.TryGetPayload(out genericRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(genericRetryContext).ConfigureAwait(false);

                    throw;
                }

                RetryContext <TContext> retryContext;
                if (!policyContext.CanRetry(exception, out retryContext))
                {
                    await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(retryContext).ConfigureAwait(false);

                    context.GetOrAddPayload(() => retryContext);
                    throw;
                }

                await _observers.PostFault(retryContext).ConfigureAwait(false);

                if (retryContext.Delay.HasValue)
                {
                    await Task.Delay(retryContext.Delay.Value).ConfigureAwait(false);
                }

                await Attempt(retryContext, next).ConfigureAwait(false);
            }
        }
        RetryPolicyContext <T> IRetryPolicy.CreatePolicyContext <T>(T context)
        {
            if (context is ConsumeContext consumeContext)
            {
                RetryPolicyContext <ConsumeContext> retryPolicyContext = _retryPolicy.CreatePolicyContext(consumeContext);

                var retryConsumeContext = new RetryConsumeContext(consumeContext);

                return(new ConsumeContextRetryPolicyContext(retryPolicyContext, retryConsumeContext) as RetryPolicyContext <T>);
            }

            throw new ArgumentException("The argument must be a ConsumeContext", nameof(context));
        }
예제 #9
0
        RetryPolicyContext <T> IRetryPolicy.CreatePolicyContext <T>(T context)
        {
            var filterContext = context as TFilter;

            if (filterContext == null)
            {
                throw new ArgumentException($"The argument must be a {typeof(TFilter).Name}", nameof(context));
            }

            RetryPolicyContext <TFilter> retryPolicyContext = _retryPolicy.CreatePolicyContext(filterContext);

            var retryConsumeContext = _contextFactory(filterContext);

            return(new CommandContextRetryPolicyContext <TFilter, TContext>(retryPolicyContext, retryConsumeContext) as RetryPolicyContext <T>);
        }
예제 #10
0
        RetryPolicyContext <T> IRetryPolicy.CreatePolicyContext <T>(T context)
        {
            if (context is CommandContext consumeContext)
            {
                RetryPolicyContext <CommandContext> retryPolicyContext = _retryPolicy.CreatePolicyContext(consumeContext);

                var innerType = context.GetType().GetClosingArguments(typeof(CommandContext <>)).Single();

                var retryConsumeContext = (RetryCommandContext)Activator.CreateInstance(typeof(RetryCommandContext <>).MakeGenericType(innerType), context);

                return(new CommandContextRetryPolicyContext(retryPolicyContext, retryConsumeContext) as RetryPolicyContext <T>);
            }

            throw new ArgumentException("The argument must be a ConsumeContext", nameof(context));
        }
예제 #11
0
        public static async Task Retry(this IRetryPolicy retryPolicy, Func <Task> retryMethod, CancellationToken cancellationToken = default(CancellationToken))
        {
            RetryPolicyContext <InlinePipeContext> policyContext = retryPolicy.CreatePolicyContext(new InlinePipeContext());

            try
            {
                await retryMethod().ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                RetryContext <InlinePipeContext> retryContext;
                if (!policyContext.CanRetry(exception, out retryContext))
                {
                    throw;
                }

                await Attempt(retryContext, retryMethod, cancellationToken).ConfigureAwait(false);
            }
        }
예제 #12
0
        async Task IFilter <TContext> .Send(TContext context, IPipe <TContext> next)
        {
            using (RetryPolicyContext <TContext> policyContext = _retryPolicy.CreatePolicyContext(context))
            {
                await _observers.PostCreate(policyContext).ConfigureAwait(false);

                try
                {
                    await next.Send(policyContext.Context).ConfigureAwait(false);
                }
                catch (OperationCanceledException exception)
                    when(exception.CancellationToken == policyContext.Context.CancellationToken || exception.CancellationToken == context.CancellationToken)
                    {
                        throw;
                    }
                catch (Exception exception)
                {
                    if (policyContext.Context.CancellationToken.IsCancellationRequested)
                    {
                        policyContext.Context.CancellationToken.ThrowIfCancellationRequested();
                    }

                    if (policyContext.Context.TryGetPayload(out RetryContext <TContext> payloadRetryContext))
                    {
                        if (_retryPolicy.IsHandled(exception))
                        {
                            await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                            await _observers.RetryFault(payloadRetryContext).ConfigureAwait(false);
                        }

                        context.GetOrAddPayload(() => payloadRetryContext);

                        throw;
                    }

                    if (policyContext.Context.TryGetPayload(out RetryContext genericRetryContext))
                    {
                        if (_retryPolicy.IsHandled(exception))
                        {
                            await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                            await _observers.RetryFault(genericRetryContext).ConfigureAwait(false);
                        }

                        context.GetOrAddPayload(() => genericRetryContext);

                        throw;
                    }

                    if (!policyContext.CanRetry(exception, out RetryContext <TContext> retryContext))
                    {
                        if (_retryPolicy.IsHandled(exception))
                        {
                            await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                            await _observers.RetryFault(retryContext).ConfigureAwait(false);

                            context.GetOrAddPayload(() => retryContext);
                        }

                        throw;
                    }

                    await _observers.PostFault(retryContext).ConfigureAwait(false);

                    await Attempt(context, retryContext, next).ConfigureAwait(false);
                }
            }
        }
예제 #13
0
        public async Task Send(ConsumeContext <T> context, IPipe <ConsumeContext <T> > next)
        {
            RetryPolicyContext <ConsumeContext <T> > policyContext = _retryPolicy.CreatePolicyContext(context);

            await _observers.PostCreate(policyContext).ConfigureAwait(false);

            try
            {
                await next.Send(policyContext.Context).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                if (context.CancellationToken.IsCancellationRequested)
                {
                    if (exception is OperationCanceledException canceledException && canceledException.CancellationToken == context.CancellationToken)
                    {
                        throw;
                    }

                    context.CancellationToken.ThrowIfCancellationRequested();
                }

                if (policyContext.Context.TryGetPayload(out RetryContext <ConsumeContext <T> > payloadRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(payloadRetryContext).ConfigureAwait(false);

                    context.GetOrAddPayload(() => payloadRetryContext);

                    throw;
                }

                if (policyContext.Context.TryGetPayload(out RetryContext genericRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(genericRetryContext).ConfigureAwait(false);

                    context.GetOrAddPayload(() => genericRetryContext);

                    throw;
                }

                if (!policyContext.CanRetry(exception, out RetryContext <ConsumeContext <T> > retryContext))
                {
                    await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(retryContext).ConfigureAwait(false);

                    if (_retryPolicy.IsHandled(exception))
                    {
                        context.GetOrAddPayload(() => retryContext);
                    }

                    throw;
                }

                int previousDeliveryCount = context.Headers.Get(MessageHeaders.RedeliveryCount, default(int?)) ?? 0;
                for (int retryIndex = 0; retryIndex < previousDeliveryCount; retryIndex++)
                {
                    if (!retryContext.CanRetry(exception, out retryContext))
                    {
                        await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                        await _observers.RetryFault(retryContext).ConfigureAwait(false);

                        if (_retryPolicy.IsHandled(exception))
                        {
                            context.GetOrAddPayload(() => retryContext);
                        }

                        throw;
                    }
                }

                await _observers.PostFault(retryContext).ConfigureAwait(false);

                try
                {
                    if (!context.TryGetPayload(out MessageRedeliveryContext redeliveryContext))
                    {
                        throw new ContextException("The message redelivery context was not available to delay the message", exception);
                    }

                    var delay = retryContext.Delay ?? TimeSpan.Zero;

                    await redeliveryContext.ScheduleRedelivery(delay).ConfigureAwait(false);

                    await context.NotifyConsumed(context, context.ReceiveContext.ElapsedTime, TypeMetadataCache <RedeliveryRetryFilter <T> > .ShortName).ConfigureAwait(false);
                }
                catch (Exception redeliveryException)
                {
                    throw new ContextException("The message delivery could not be rescheduled", new AggregateException(redeliveryException, exception));
                }
            }
        }
        public async Task Send(TContext context, IPipe <TContext> next)
        {
            using (RetryPolicyContext <TContext> policyContext = _retryPolicy.CreatePolicyContext(context))
            {
                if (_observers.Count > 0)
                {
                    await _observers.PostCreate(policyContext).ConfigureAwait(false);
                }

                try
                {
                    await next.Send(policyContext.Context).ConfigureAwait(false);
                }
                catch (OperationCanceledException exception)
                    when(exception.CancellationToken == context.CancellationToken || exception.CancellationToken == policyContext.Context.CancellationToken)
                    {
                        throw;
                    }
                catch (Exception exception)
                {
                    if (policyContext.Context.CancellationToken.IsCancellationRequested)
                    {
                        policyContext.Context.CancellationToken.ThrowIfCancellationRequested();
                    }

                    if (!policyContext.CanRetry(exception, out RetryContext <TContext> retryContext))
                    {
                        if (_retryPolicy.IsHandled(exception))
                        {
                            context.GetOrAddPayload(() => retryContext);

                            await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                            if (_observers.Count > 0)
                            {
                                await _observers.RetryFault(retryContext).ConfigureAwait(false);
                            }
                        }

                        throw;
                    }

                    var previousDeliveryCount = context.GetRedeliveryCount();
                    for (var retryIndex = 0; retryIndex < previousDeliveryCount; retryIndex++)
                    {
                        if (!retryContext.CanRetry(exception, out retryContext))
                        {
                            if (_retryPolicy.IsHandled(exception))
                            {
                                context.GetOrAddPayload(() => retryContext);

                                await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                                if (_observers.Count > 0)
                                {
                                    await _observers.RetryFault(retryContext).ConfigureAwait(false);
                                }
                            }

                            throw;
                        }
                    }

                    if (_observers.Count > 0)
                    {
                        await _observers.PostFault(retryContext).ConfigureAwait(false);
                    }

                    try
                    {
                        var redeliveryContext = context.GetPayload <MessageRedeliveryContext>();

                        var delay = retryContext.Delay ?? TimeSpan.Zero;

                        await redeliveryContext.ScheduleRedelivery(delay).ConfigureAwait(false);

                        await context.NotifyConsumed(context, context.ReceiveContext.ElapsedTime,
                                                     TypeMetadataCache <RedeliveryRetryFilter <TContext, TMessage> > .ShortName).ConfigureAwait(false);
                    }
                    catch (Exception redeliveryException)
                    {
                        throw new TransportException(context.ReceiveContext.InputAddress, "The message delivery could not be rescheduled",
                                                     new AggregateException(redeliveryException, exception));
                    }
                }
            }
        }
        async Task RunJob(PipeContext context, IJobConsumer <TJob> jobConsumer)
        {
            var jobContext = context.GetPayload <JobContext <TJob> >();

            RetryPolicyContext <JobContext <TJob> > policyContext = _retryPolicy.CreatePolicyContext(jobContext);

            try
            {
                await jobContext.NotifyStarted().ConfigureAwait(false);

                await jobConsumer.Run(jobContext).ConfigureAwait(false);

                await jobContext.NotifyCompleted().ConfigureAwait(false);
            }
            catch (OperationCanceledException exception)
            {
                if (jobContext.CancellationToken == exception.CancellationToken)
                {
                    await jobContext.NotifyCanceled("Operation canceled").ConfigureAwait(false);
                }
            }
            catch (Exception exception)
            {
                if (!policyContext.CanRetry(exception, out RetryContext <JobContext <TJob> > retryContext))
                {
                    if (_retryPolicy.IsHandled(exception))
                    {
                        context.GetOrAddPayload(() => retryContext);

                        await retryContext.RetryFaulted(exception).ConfigureAwait(false);
                    }

                    await jobContext.NotifyFaulted(exception).ConfigureAwait(false);

                    return;
                }

                var currentRetryAttempt = jobContext.RetryAttempt;
                for (var retryIndex = 0; retryIndex < currentRetryAttempt; retryIndex++)
                {
                    if (!retryContext.CanRetry(exception, out retryContext))
                    {
                        if (_retryPolicy.IsHandled(exception))
                        {
                            context.GetOrAddPayload(() => retryContext);

                            await retryContext.RetryFaulted(exception).ConfigureAwait(false);
                        }

                        await jobContext.NotifyFaulted(exception).ConfigureAwait(false);

                        return;
                    }
                }

                var delay = retryContext.Delay ?? TimeSpan.Zero;

                await jobContext.NotifyFaulted(exception, delay).ConfigureAwait(false);
            }
            finally
            {
                policyContext.Dispose();
            }
        }
예제 #16
0
        public async Task Send(ConsumeContext <T> context, IPipe <ConsumeContext <T> > next)
        {
            RetryPolicyContext <ConsumeContext <T> > policyContext = _retryPolicy.CreatePolicyContext(context);

            await _observers.PostCreate(policyContext).ConfigureAwait(false);

            try
            {
                await next.Send(policyContext.Context).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                RetryContext <ConsumeContext <T> > payloadRetryContext;
                if (context.TryGetPayload(out payloadRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(payloadRetryContext).ConfigureAwait(false);

                    throw;
                }

                RetryContext genericRetryContext;
                if (context.TryGetPayload(out genericRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(genericRetryContext).ConfigureAwait(false);

                    throw;
                }

                RetryContext <ConsumeContext <T> > retryContext;
                if (!policyContext.CanRetry(exception, out retryContext))
                {
                    await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(retryContext).ConfigureAwait(false);

                    context.GetOrAddPayload(() => retryContext);
                    throw;
                }

                int previousDeliveryCount = context.Headers.Get(MessageHeaders.RedeliveryCount, default(int?)) ?? 0;
                for (int retryIndex = 0; retryIndex < previousDeliveryCount; retryIndex++)
                {
                    if (!retryContext.CanRetry(exception, out retryContext))
                    {
                        await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                        await _observers.RetryFault(retryContext).ConfigureAwait(false);

                        context.GetOrAddPayload(() => retryContext);
                        throw;
                    }
                }

                await _observers.PostFault(retryContext).ConfigureAwait(false);

                try
                {
                    MessageRedeliveryContext redeliveryContext;
                    if (!context.TryGetPayload(out redeliveryContext))
                    {
                        throw new ContextException("The message redelivery context was not available to delay the message", exception);
                    }

                    var delay = retryContext.Delay ?? TimeSpan.Zero;

                    await redeliveryContext.ScheduleRedelivery(delay).ConfigureAwait(false);
                }
                catch (Exception redeliveryException)
                {
                    throw new ContextException("The message delivery could not be rescheduled", new AggregateException(redeliveryException, exception));
                }
            }
        }