/// <summary>
        /// Builds a <see cref="SqlStrategy"/> with policies that will function
        /// like a Circuit Breaker.
        /// </summary>
        /// <param name="sqlStrategyBuilder">The SQL strategy.</param>
        /// <param name="sqlStrategyConfiguration">
        /// An <see cref="SqlStrategyOptions"/> containing configuration parameters.
        /// </param>
        /// <returns>The strategy instance.</returns>
        public static SqlStrategyBuilder WithCircuitBreakers(this SqlStrategyBuilder sqlStrategyBuilder, SqlStrategyOptions sqlStrategyConfiguration)
        {
            var exceptionsAllowedBeforeBreaking = sqlStrategyConfiguration.ExceptionsAllowedBeforeBreaking();
            var durationOfBreak = sqlStrategyConfiguration.DurationOfBreak();

            //DatabaseNotCurrentlyAvailable
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40613).CircuitBreaker(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F1.{SqlServerPolicyKeys.CircuitBreakerPolicy}"));
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40613).CircuitBreakerAsync(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F1.{SqlServerPolicyKeys.CircuitBreakerPolicyAsync}"));

            //ErrorProcessingRequest
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40197).CircuitBreaker(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F2.{SqlServerPolicyKeys.CircuitBreakerPolicy}"));
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40197).CircuitBreakerAsync(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F2.{SqlServerPolicyKeys.CircuitBreakerPolicyAsync}"));

            //ServiceCurrentlyBusy
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40501).CircuitBreaker(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F3.{SqlServerPolicyKeys.CircuitBreakerPolicy}"));
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40501).CircuitBreakerAsync(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F3.{SqlServerPolicyKeys.CircuitBreakerPolicyAsync}"));

            //SessionTerminatedLongTransaction
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40549).CircuitBreaker(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F4.{SqlServerPolicyKeys.CircuitBreakerPolicy}"));
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40549).CircuitBreakerAsync(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F4.{SqlServerPolicyKeys.CircuitBreakerPolicyAsync}"));

            //NotEnoughResources
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 49918).CircuitBreaker(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F5.{SqlServerPolicyKeys.CircuitBreakerPolicy}"));
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 49918).CircuitBreakerAsync(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F5.{SqlServerPolicyKeys.CircuitBreakerPolicyAsync}"));

            //SessionTerminatedToManyLocks
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40550).CircuitBreaker(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F6.{SqlServerPolicyKeys.CircuitBreakerPolicy}"));
            sqlStrategyBuilder.Policies.Add(Policy.Handle <SqlException>(e => e.Number == 40550).CircuitBreakerAsync(exceptionsAllowedBeforeBreaking, durationOfBreak, SqlStrategyLoggingDelegates.OnCircuitBreak, SqlStrategyLoggingDelegates.OnCircuitReset).WithPolicyKey($"F6.{SqlServerPolicyKeys.CircuitBreakerPolicyAsync}"));

            return(sqlStrategyBuilder);
        }
        /// <summary>
        /// Builds a <see cref="SqlStrategy"/> with a policy for retrying
        /// actions on transaction failures.
        /// </summary>
        /// <param name="sqlStrategy">The SQL strategy.</param>
        /// <param name="exceptionHandlingStrategy">
        /// The exception handling strategy used to determine which exceptions
        /// should be retried.
        /// </param>
        /// <param name="sqlStrategyConfiguration">
        /// An <see cref="SqlStrategyOptions"/> containing configuration parameters.
        /// </param>
        /// <returns>The strategy instance.</returns>
        public static SqlStrategyBuilder Retry(this SqlStrategyBuilder sqlStrategy, IExceptionHandlingStrategy exceptionHandlingStrategy, SqlStrategyOptions sqlStrategyConfiguration)
        {
            var backoff = Backoff.ExponentialBackoff(TimeSpan.FromSeconds(2), sqlStrategyConfiguration.RetryCount());

            sqlStrategy.Policies.Add(Policy.Handle <SqlException>(exceptionHandlingStrategy.ShouldHandle).WaitAndRetry(backoff, SqlStrategyLoggingDelegates.OnRetry).WithPolicyKey(SqlServerPolicyKeys.TransactionPolicy));
            sqlStrategy.Policies.Add(Policy.Handle <SqlException>(exceptionHandlingStrategy.ShouldHandle).WaitAndRetryAsync(backoff, SqlStrategyLoggingDelegates.OnRetryAsync).WithPolicyKey(SqlServerPolicyKeys.TransactionPolicyAsync));
            return(sqlStrategy);
        }
        /// <summary>
        /// Builds a <see cref="SqlStrategy"/> with a policy for an overall timeout.
        /// </summary>
        /// <param name="sqlStrategy">The SQL strategy.</param>
        /// <param name="sqlStrategyConfiguration">
        /// An <see cref="SqlStrategyOptions"/> containing configuration parameters.
        /// </param>
        /// <returns>The strategy instance.</returns>
        /// <remarks>
        /// This is equivalent to calling
        /// <see cref="WithOverallTimeout(SqlStrategyBuilder, SqlStrategyOptions)"/>, <see cref="WithTimeoutPerRetry(SqlStrategyBuilder, SqlStrategyOptions)"/>.
        /// </remarks>
        public static SqlStrategyBuilder WithOverallTimeout(this SqlStrategyBuilder sqlStrategy, SqlStrategyOptions sqlStrategyConfiguration)
        {
            var overallTimeout = sqlStrategyConfiguration.OverallTimeout();

            sqlStrategy.Policies.Add(Policy.Timeout(overallTimeout, TimeoutStrategy.Pessimistic, SqlStrategyLoggingDelegates.OnTimeout).WithPolicyKey(SqlServerPolicyKeys.OverallTimeoutPolicy));
            sqlStrategy.Policies.Add(Policy.TimeoutAsync(overallTimeout, TimeoutStrategy.Pessimistic, SqlStrategyLoggingDelegates.OnTimeoutAsync).WithPolicyKey(SqlServerPolicyKeys.OverallTimeoutPolicyAsync));
            return(sqlStrategy);
        }
        /// <summary>
        /// Builds a <see cref="SqlStrategy"/> with a policy for a per retry timeout.
        /// </summary>
        /// <param name="sqlStrategy">The SQL strategy.</param>
        /// <param name="sqlStrategyConfiguration">
        /// An <see cref="SqlStrategyOptions"/> containing configuration parameters.
        /// </param>
        /// <returns>The strategy instance.</returns>
        /// <remarks>
        /// This is equivalent to calling
        /// <see cref="WithOverallTimeout(SqlStrategyBuilder, SqlStrategyOptions)"/>, <see cref="WithTimeoutPerRetry(SqlStrategyBuilder, SqlStrategyOptions)"/>.
        /// </remarks>
        public static SqlStrategyBuilder WithTimeoutPerRetry(this SqlStrategyBuilder sqlStrategy, SqlStrategyOptions sqlStrategyConfiguration)
        {
            var timeoutPerRetry = sqlStrategyConfiguration.TimeoutPerRetry();

            sqlStrategy.Policies.Add(Policy.Timeout(timeoutPerRetry, TimeoutStrategy.Pessimistic, SqlStrategyLoggingDelegates.OnTimeout).WithPolicyKey(SqlServerPolicyKeys.TimeoutPerRetryPolicy));
            sqlStrategy.Policies.Add(Policy.TimeoutAsync(timeoutPerRetry, TimeoutStrategy.Pessimistic, SqlStrategyLoggingDelegates.OnTimeoutAsync).WithPolicyKey(SqlServerPolicyKeys.TimeoutPerRetryPolicyAsync));
            return(sqlStrategy);
        }
 /// <summary>
 /// Builds a <see cref="SqlStrategy"/> with policies for both an overall
 /// timeout and a per retry timeout.
 /// </summary>
 /// <param name="sqlStrategy">The SQL strategy.</param>
 /// <param name="sqlStrategyConfiguration">
 /// An <see cref="SqlStrategyOptions"/> containing configuration parameters.
 /// </param>
 /// <returns>The strategy instance.</returns>
 /// <remarks>
 /// This is equivalent to calling
 /// <see cref="WithOverallTimeout(SqlStrategyBuilder, SqlStrategyOptions)"/>, <see cref="WithTimeoutPerRetry(SqlStrategyBuilder, SqlStrategyOptions)"/>.
 /// </remarks>
 public static SqlStrategyBuilder WithOverallAndTimeoutPerRetry(this SqlStrategyBuilder sqlStrategy, SqlStrategyOptions sqlStrategyConfiguration)
 {
     sqlStrategy.WithOverallTimeout(sqlStrategyConfiguration);
     sqlStrategy.WithTimeoutPerRetry(sqlStrategyConfiguration);
     return(sqlStrategy);
 }