Esempio n. 1
0
        /// <summary>
        /// Generates a Polly <see cref="FallbackPolicy{HttpResponseMessage}"/> from the configuration.
        /// </summary>
        /// <param name="logger">The <see cref="ILogger"/> instance to use for logging.</param>
        /// <returns>A <see cref="FallbackPolicy{HttpResponseMessage}"/> instance.</returns>
        public IAsyncPolicy <HttpResponseMessage> AsTypeModel(ILogger logger)
        {
            _ = logger ?? throw new ArgumentNullException(nameof(logger));

            if (Status < 0)
            {
                logger.LogCritical("{PolicyConfig} : {Property} is negative", nameof(FallbackConfig), "statusCode");
                throw new InvalidOperationException("statusCode cannot be negative");
            }

            var message = new HttpResponseMessage
            {
                StatusCode   = (HttpStatusCode)Status,
                ReasonPhrase = Reason,
                Content      = new StringContent(Content ?? string.Empty, Encoding.UTF8, "application/json")
            };

            logger.LogDebug("Created fallback mesage {StatusCode} - {ReasonPhrase} - {Content}",
                            message.StatusCode, message.ReasonPhrase, message.Content);

            return(Policy.HandleHttpRequests()
                   .FallbackAsync(message, onFallbackAsync: async(result, context) =>
            {
                logger.LogWarning(result.Exception, "{PolicyKey} at {OperationKey}: fallback value substituted",
                                  context.PolicyKey, context.OperationKey);
                await Task.CompletedTask;
            }));
        }
Esempio n. 2
0
        /// <summary>
        /// Generates a Polly <see cref="CircuitBreakerPolicy{HttpResponseMessage}"/> from the configuration.
        /// </summary>
        /// <param name="logger">The <see cref="ILogger"/> instance to use for logging.</param>
        /// <returns>A <see cref="CircuitBreakerPolicy{HttpResponseMessage}"/> instance.</returns>
        public IAsyncPolicy <HttpResponseMessage> AsTypeModel(ILogger logger)
        {
            _ = logger ?? throw new ArgumentNullException(nameof(logger));

            if (BreakDuration < 0.02d)
            {
                logger.LogCritical("{PolicyConfig} : {Property} must be greater than 20ms", nameof(AdvancedCircuitBreakerConfig), "breakDuration");
                throw new InvalidOperationException("breakDuration must be greater than 20ms");
            }

            if (FailureThreshold < 0.0d || FailureThreshold > 1.0d)
            {
                logger.LogCritical("{PolicyConfig} : {Property} must be between 0 and 1", nameof(AdvancedCircuitBreakerConfig), "threshold");
                throw new InvalidOperationException("threshold must be between 0 and 1");
            }

            if (SamplingDuration < 0.02d)
            {
                logger.LogCritical("{PolicyConfig} : {Property} must be greater than 20ms", nameof(AdvancedCircuitBreakerConfig), "samplingDuration");
                throw new InvalidOperationException("samplingDuration must be greater than 20ms");
            }

            if (MinimumThroughput < 0)
            {
                logger.LogCritical("{PolicyConfig} : {Property} is negative", nameof(AdvancedCircuitBreakerConfig), "throughput");
                throw new InvalidOperationException("throughput cannot be negative");
            }

            // Create delegates
            void OnBreak(DelegateResult <HttpResponseMessage> result, TimeSpan timespan, Context context)
            {
                logger.LogError(result.Exception, "{PolicyKey} at {OperationKey}: {CircuitState} triggered for {CircuitDelay} seconds due to {StatusCode}",
                                context.PolicyKey, context.OperationKey, CircuitState.Open, timespan.TotalSeconds, result.Result?.StatusCode);
            }

            void OnReset(Context context)
            {
                logger.LogInformation("{PolicyKey} at {OperationKey}: {CircuitState} triggered",
                                      context.PolicyKey, context.OperationKey, CircuitState.Closed);
            }

            void OnHalfOpen() => logger.LogDebug("{CircuitState} triggered", CircuitState.HalfOpen);

            // Create policy
            var breaker = Policy
                          .HandleHttpRequests()
                          .AdvancedCircuitBreakerAsync(
                failureThreshold: FailureThreshold,
                samplingDuration: TimeSpan.FromSeconds(SamplingDuration),
                minimumThroughput: MinimumThroughput,
                durationOfBreak: TimeSpan.FromSeconds(BreakDuration),
                onBreak: OnBreak,
                onReset: OnReset,
                onHalfOpen: OnHalfOpen);

            return(breaker);
        }
Esempio n. 3
0
        /// <summary>
        /// Generates a Polly <see cref="CircuitBreakerPolicy{HttpResponseMessage}"/> from the configuration.
        /// </summary>
        /// <param name="logger">The <see cref="ILogger"/> instance to use for logging.</param>
        /// <returns>A <see cref="CircuitBreakerPolicy{HttpResponseMessage}"/> instance.</returns>
        public IAsyncPolicy <HttpResponseMessage> AsTypeModel(ILogger logger)
        {
            _ = logger ?? throw new ArgumentNullException(nameof(logger));

            if (BreakDuration < 0.02d)
            {
                logger.LogCritical("{PolicyConfig} : {Property} must be greater than 20ms", nameof(CircuitBreakerConfig), "duration");
                throw new InvalidOperationException("duration must be greater than 20ms");
            }

            if (FaultTolerance < 1)
            {
                logger.LogCritical("{PolicyConfig} : {Property} must be greater than 0", nameof(CircuitBreakerConfig), "tolerance");
                throw new InvalidOperationException("tolerance must be greater than 0");
            }

            // Create delegates
            void OnBreak(DelegateResult <HttpResponseMessage> result, TimeSpan timespan, Context context)
            {
                logger.LogError(result.Exception, "{PolicyKey} at {OperationKey}: {CircuitState} triggered for {CircuitDelay} seconds due to {StatusCode}",
                                context.PolicyKey, context.OperationKey, CircuitState.Open, timespan.TotalSeconds, result.Result?.StatusCode);
            }

            void OnReset(Context context)
            {
                logger.LogInformation("{PolicyKey} at {OperationKey}: {CircuitState} triggered",
                                      context.PolicyKey, context.OperationKey, CircuitState.Closed);
            }

            void OnHalfOpen() => logger.LogDebug("{CircuitState} triggered", CircuitState.HalfOpen);

            // Create policy
            var breaker = Policy
                          .HandleHttpRequests()
                          .CircuitBreakerAsync(
                handledEventsAllowedBeforeBreaking: FaultTolerance,
                durationOfBreak: TimeSpan.FromSeconds(BreakDuration),
                onBreak: OnBreak,
                onReset: OnReset,
                onHalfOpen: OnHalfOpen
                );

            return(breaker);
        }
        /// <summary>
        /// Generates a Polly <see cref="RetryPolicy{HttpResponseMessage}"/> from the configuration.
        /// </summary>
        /// <param name="logger">The <see cref="ILogger"/> instance to use for logging.</param>
        /// <returns>A <see cref="RetryPolicy{HttpResponseMessage}"/> instance.</returns>
        public IAsyncPolicy <HttpResponseMessage> AsTypeModel(ILogger logger)
        {
            _ = logger ?? throw new ArgumentNullException(nameof(logger));

            if (DelaysInSeconds is null)
            {
                logger.LogCritical("{PolicyConfig} : {Property} is not initialized", nameof(RetryConfig), "delays");
                throw new InvalidOperationException("delays cannot be null");
            }

            if (JitterMilliseconds < 0)
            {
                logger.LogCritical("{PolicyConfig} : {Property} is negative", nameof(RetryConfig), "jitter");
                throw new InvalidOperationException("jitter cannot be negative");
            }

            var builder = Policy.HandleHttpRequests();

            List <double> delays  = DelaysInSeconds.ToList();
            bool          forever = Retries < 1;

            bool immediate = !delays.Any();

            if (immediate)
            {
                if (forever)
                {
                    return(builder.RetryForeverAsync(onRetry: result =>
                                                     logger.LogError(result.Exception, "{RetryPolicy} failed with {StatusCode}",
                                                                     "RetryForeverAsync", result.Result?.StatusCode)));
                }
                else
                {
                    return(builder.RetryAsync(Retries, onRetry: (result, count) =>
                                              logger.LogError(result.Exception, "{RetryPolicy} failed with {StatusCode} on attempt {RetryCount}", "RetryAsync",
                                                              result.Result?.StatusCode, count)));
                }
            }

            bool exponential = delays.Count == 1 && delays.First() == -1.0d;

            // Defined delays rely on the list being initialized with positive delay values
            if (!exponential && delays.Any(d => d < 0))
            {
                throw new InvalidOperationException($"delay values cannot be negative");
            }

            if (forever)
            {
                return(builder.WaitAndRetryForeverAsync(
                           sleepDurationProvider: count => Delay(count, exponential),
                           onRetry: (result, timespan) => logger.LogError(result.Exception,
                                                                          "{RetryPolicy} failed with {StatusCode} after {RetryTime} seconds",
                                                                          "WaitAndRetryForeverAsync", result.Result?.StatusCode, timespan.TotalSeconds)));
            }
            else
            {
                return(builder.WaitAndRetryAsync(
                           Retries,
                           sleepDurationProvider: count => Delay(count, exponential),
                           onRetry: (result, timespan, count, context) => logger.LogError(result.Exception,
                                                                                          "{RetryPolicy} failed with {StatusCode} on attempt {RetryCount} after {RetryTime} seconds",
                                                                                          "WaitAndRetryAsync", result.Result?.StatusCode, count, timespan.TotalSeconds)));
            }
        }