Пример #1
0
        static async Task <TResult> Attempt <T, TResult>(RetryContext <T> retryContext, Func <Task <TResult> > retryMethod, CancellationToken cancellationToken)
            where T : class
        {
            cancellationToken.ThrowIfCancellationRequested();

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

                if (nextRetryContext.Delay.HasValue)
                {
                    await Task.Delay(nextRetryContext.Delay.Value, cancellationToken).ConfigureAwait(false);
                }

                return(await Attempt(nextRetryContext, retryMethod, cancellationToken).ConfigureAwait(false));
            }
        }
Пример #2
0
        async Task Attempt(RetryContext <TContext> retryContext, IPipe <TContext> next)
        {
            await retryContext.PreRetry().ConfigureAwait(false);

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

                    throw;
                }

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

                    retryContext.Context.GetOrAddPayload(() => nextRetryContext);
                    throw;
                }

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

                await Attempt(nextRetryContext, next).ConfigureAwait(false);
            }
        }
Пример #3
0
        static async Task Attempt <T>(RetryContext <ConsumeContext <T> > retryContext, Func <ConsumeContext <T>, Task> retryMethod)
            where T : class
        {
            try
            {
                await retryMethod(retryContext.Context).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                if (retryContext.Context.TryGetPayload(out RetryContext <ConsumeContext <T> > nextRetryContext))
                {
                    throw;
                }

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

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

                await Attempt(nextRetryContext, retryMethod).ConfigureAwait(false);
            }
        }
Пример #4
0
        public bool CanRetry(Exception exception, out RetryContext <CommandContext> retryContext)
        {
            var canRetry = _retryContext.CanRetry(exception, out RetryContext <CommandContext> policyRetryContext);

            retryContext = new ConsumeContextRetryContext(policyRetryContext, canRetry ? _context.CreateNext() : _context);

            return(canRetry);
        }
Пример #5
0
            async Task Run()
            {
                var stoppingContext = new TransportStoppingContext(Stopping);

                RetryPolicyContext <TransportStoppingContext> policyContext = _retryPolicy.CreatePolicyContext(stoppingContext);

                try
                {
                    while (!IsStopping)
                    {
                        RetryContext <TransportStoppingContext> retryContext = null;
                        try
                        {
                            if (retryContext != null)
                            {
                                LogContext.Warning?.Log(retryContext.Exception, "Retrying {Delay}: {Message}", retryContext.Delay,
                                                        retryContext.Exception.Message);

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

                            if (!IsStopping)
                            {
                                await RunTransport().ConfigureAwait(false);
                            }
                        }
                        catch (OperationCanceledException)
                        {
                            throw;
                        }
                        catch (Exception exception)
                        {
                            if (retryContext != null)
                            {
                                retryContext = retryContext.CanRetry(exception, out RetryContext <TransportStoppingContext> nextRetryContext)
                                    ? nextRetryContext
                                    : null;
                            }

                            if (retryContext == null && !policyContext.CanRetry(exception, out retryContext))
                            {
                                break;
                            }
                        }
                    }
                }
                catch (Exception exception)
                {
                    LogContext.Debug?.Log(exception, "ReceiveTransport Run Exception: {InputAddress}", _context.InputAddress);
                }
                finally
                {
                    policyContext.Dispose();
                }
            }
Пример #6
0
        public bool CanRetry(Exception exception, out RetryContext <ConsumeContext> retryContext)
        {
            RetryContext <ConsumeContext> policyRetryContext;
            var canRetry = _retryContext.CanRetry(exception, out policyRetryContext);

            retryContext = new ConsumeContextRetryContext(policyRetryContext, _context);

            return(canRetry);
        }
Пример #7
0
        static async Task Attempt <T>(RetryContext <T> retryContext, Func <Task> retryMethod)
            where T : class
        {
            while (retryContext.CancellationToken.IsCancellationRequested == false)
            {
                if (retryContext.Delay.HasValue)
                {
                    await Task.Delay(retryContext.Delay.Value, retryContext.CancellationToken).ConfigureAwait(false);
                }

                retryContext.CancellationToken.ThrowIfCancellationRequested();

                try
                {
                    await retryMethod().ConfigureAwait(false);

                    return;
                }
                catch (Exception exception)
                {
                    if (retryContext.CancellationToken.IsCancellationRequested)
                    {
                        var canceledException = exception as OperationCanceledException;
                        if (canceledException != null && canceledException.CancellationToken == retryContext.CancellationToken)
                        {
                            throw;
                        }

                        retryContext.CancellationToken.ThrowIfCancellationRequested();
                    }

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

                    retryContext = nextRetryContext;
                }
            }

            retryContext.CancellationToken.ThrowIfCancellationRequested();
        }
        static async Task <TResult> Attempt <T, TResult>(T context, RetryContext <T> retryContext, Func <Task <TResult> > retryMethod)
            where T : class, PipeContext
        {
            while (context.CancellationToken.IsCancellationRequested == false)
            {
                if (retryContext.Delay.HasValue)
                {
                    await Task.Delay(retryContext.Delay.Value, context.CancellationToken).ConfigureAwait(false);
                }

                context.CancellationToken.ThrowIfCancellationRequested();

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

                        context.CancellationToken.ThrowIfCancellationRequested();
                    }

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

                    retryContext = nextRetryContext;
                }
            }

            context.CancellationToken.ThrowIfCancellationRequested();

            throw new OperationCanceledException("Retry was cancelled");
        }
Пример #9
0
        static async Task Attempt <T>(T context, RetryContext <T> retryContext, Func <Task> retryMethod)
            where T : class, PipeContext
        {
            while (context.CancellationToken.IsCancellationRequested == false)
            {
                if (retryContext.Delay.HasValue)
                {
                    await Task.Delay(retryContext.Delay.Value, context.CancellationToken).ConfigureAwait(false);
                }

                context.CancellationToken.ThrowIfCancellationRequested();

                try
                {
                    await retryMethod().ConfigureAwait(false);

                    return;
                }
                catch (Exception exception)
                {
                    if (context.CancellationToken.IsCancellationRequested)
                    {
                        if (exception is OperationCanceledException canceledException && canceledException.CancellationToken == context.CancellationToken)
                        {
                            throw;
                        }

                        context.CancellationToken.ThrowIfCancellationRequested();
                    }

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

                    retryContext = nextRetryContext;
                }
            }

            context.CancellationToken.ThrowIfCancellationRequested();
        }
Пример #10
0
        static async Task Attempt <T>(T context, RetryContext <T> retryContext, Func <Task> retryMethod)
            where T : class, PipeContext
        {
            while (context.CancellationToken.IsCancellationRequested == false)
            {
                LogContext.Warning?.Log(retryContext.Exception, "Retrying {Delay}: {Message}", retryContext.Delay, retryContext.Exception.Message);

                try
                {
                    if (retryContext.Delay.HasValue)
                    {
                        await Task.Delay(retryContext.Delay.Value, context.CancellationToken).ConfigureAwait(false);
                    }

                    if (!context.CancellationToken.IsCancellationRequested)
                    {
                        await retryMethod().ConfigureAwait(false);
                    }

                    return;
                }
                catch (OperationCanceledException exception) when(exception.CancellationToken == context.CancellationToken)
                {
                    retryContext.Exception?.Rethrow();
                    throw;
                }
                catch (Exception exception)
                {
                    if (!retryContext.CanRetry(exception, out RetryContext <T> nextRetryContext))
                    {
                        throw new OperationCanceledException(context.CancellationToken);
                    }

                    retryContext = nextRetryContext;
                }
            }

            throw new OperationCanceledException(context.CancellationToken);
        }
Пример #11
0
        async Task Attempt(TContext context, RetryContext <TContext> retryContext, IPipe <TContext> next)
        {
            while (retryContext.CancellationToken.IsCancellationRequested == false)
            {
                if (retryContext.Delay.HasValue)
                {
                    await Task.Delay(retryContext.Delay.Value, retryContext.CancellationToken).ConfigureAwait(false);
                }

                await retryContext.PreRetry().ConfigureAwait(false);

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

                try
                {
                    await next.Send(retryContext.Context).ConfigureAwait(false);

                    return;
                }
                catch (OperationCanceledException exception)
                    when(exception.CancellationToken == retryContext.CancellationToken || exception.CancellationToken == context.CancellationToken)
                    {
                        throw;
                    }
                catch (Exception exception)
                {
                    if (context.CancellationToken.IsCancellationRequested)
                    {
                        context.CancellationToken.ThrowIfCancellationRequested();
                    }

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

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

                        context.GetOrAddPayload(() => payloadRetryContext);

                        throw;
                    }

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

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

                        context.GetOrAddPayload(() => genericRetryContext);

                        throw;
                    }

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

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

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

                        throw;
                    }

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

                    retryContext = nextRetryContext;
                }
            }

            context.CancellationToken.ThrowIfCancellationRequested();
        }
        public static async Task Retry(this IHostConfiguration hostConfiguration, Func <Task> factory, ISupervisor supervisor,
                                       CancellationToken cancellationToken)
        {
            var description = hostConfiguration.HostAddress;

            using var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, supervisor.Stopping);

            var stoppingContext = new SupervisorStoppingContext(tokenSource.Token);

            RetryPolicyContext <SupervisorStoppingContext> policyContext = hostConfiguration.ReceiveTransportRetryPolicy.CreatePolicyContext(stoppingContext);

            try
            {
                RetryContext <SupervisorStoppingContext> retryContext = null;

                while (!tokenSource.Token.IsCancellationRequested)
                {
                    try
                    {
                        if (retryContext?.Delay != null)
                        {
                            await Task.Delay(retryContext.Delay.Value, tokenSource.Token).ConfigureAwait(false);
                        }

                        if (tokenSource.Token.IsCancellationRequested)
                        {
                            throw new ConnectionException($"The connection is stopping and cannot be used: {description}", retryContext?.Exception);
                        }

                        await factory().ConfigureAwait(false);

                        return;
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }
                    catch (Exception exception)
                    {
                        if (retryContext != null)
                        {
                            retryContext = retryContext.CanRetry(exception, out RetryContext <SupervisorStoppingContext> nextRetryContext)
                                ? nextRetryContext
                                : null;
                        }

                        if (retryContext == null && !policyContext.CanRetry(exception, out retryContext))
                        {
                            throw;
                        }
                    }

                    if (tokenSource.Token.IsCancellationRequested)
                    {
                        break;
                    }

                    try
                    {
                        await Task.Delay(TimeSpan.FromSeconds(1), tokenSource.Token).ConfigureAwait(false);
                    }
                    catch
                    {
                        // just a little breather before reconnecting the receive transport
                    }
                }

                throw new ConnectionException($"The connection is stopping and cannot be used: {description}", retryContext?.Exception);
            }
            finally
            {
                policyContext.Dispose();
            }
        }
Пример #13
0
            async Task Run()
            {
                var stoppingContext = new TransportStoppingContext(Stopping);

                RetryPolicyContext <TransportStoppingContext> policyContext = _retryPolicy.CreatePolicyContext(stoppingContext);

                try
                {
                    RetryContext <TransportStoppingContext> retryContext = null;

                    while (!IsStopping)
                    {
                        try
                        {
                            if (retryContext?.Delay != null)
                            {
                                await Task.Delay(retryContext.Delay.Value, Stopping).ConfigureAwait(false);
                            }

                            if (!IsStopping)
                            {
                                await RunTransport().ConfigureAwait(false);
                            }
                        }
                        catch (OperationCanceledException exception)
                        {
                            if (retryContext == null)
                            {
                                await NotifyFaulted(exception).ConfigureAwait(false);
                            }

                            throw;
                        }
                        catch (Exception exception)
                        {
                            if (retryContext != null)
                            {
                                retryContext = retryContext.CanRetry(exception, out RetryContext <TransportStoppingContext> nextRetryContext)
                                    ? nextRetryContext
                                    : null;
                            }

                            if (retryContext == null && !policyContext.CanRetry(exception, out retryContext))
                            {
                                break;
                            }
                        }

                        if (IsStopping)
                        {
                            break;
                        }

                        try
                        {
                            await Task.Delay(TimeSpan.FromSeconds(1), Stopping).ConfigureAwait(false);
                        }
                        catch
                        {
                            // just a little breather before reconnecting the receive transport
                        }
                    }
                }
                catch (OperationCanceledException exception)
                {
                    if (exception.CancellationToken != Stopping)
                    {
                        LogContext.Debug?.Log(exception, "ReceiveTransport Operation Cancelled: {InputAddress}", _context.InputAddress);
                    }
                }
                catch (Exception exception)
                {
                    LogContext.Debug?.Log(exception, "ReceiveTransport Run Exception: {InputAddress}", _context.InputAddress);
                }
                finally
                {
                    policyContext.Dispose();
                }
            }