/// <summary>
        /// Ok time to call whatever it is we are trying to do
        /// </summary>
        private static void ExecuteWithRetryInternal(Action redisAction, IRedisRetryPolicy retryPolicy)
        {
            IRedisRetryPolicy callPolicy = null == retryPolicy ? _DefaultRetryPolicy : retryPolicy;
            int      retryCount          = callPolicy.MaxRetry;
            TimeSpan?delay = null;

            while (true)
            {
                try
                {
                    redisAction();
                    return;
                }
                catch (Exception callError)
                {
                    if (retryCount > 0 && callPolicy.ShouldRetry(callError))
                    {
                        retryCount--;
                        delay = callPolicy.CalculateDelay(retryCount);
                    }
                    else
                    {
                        throw;
                    }
                }
                if (delay.HasValue)
                {
                    //borrowed from Entity Framework execution strategy
                    using (var waitEvent = new ManualResetEventSlim(false))
                    {
                        waitEvent.WaitHandle.WaitOne(delay.Value);
                    }
                }
            }
        }
        /// <summary>
        /// execute the function and return a result using the retry policy
        /// </summary>
        public static T ExecuteWithRetry <T>(this IRedisRetryPolicy retryPolicy, Func <T> redisFunction)
        {
            var returnValue = default(T);

            ExecuteWithRetryInternal(() => returnValue = redisFunction(), retryPolicy);
            return(returnValue);
        }
        /// <summary>
        /// In order for us to return the task, we need to create a new task
        /// that wraps the async action task so that it can be retried withen
        /// an external await
        /// </summary>
        private static Task <T> ExecuteWithRetryInternalAsync <T>(Func <Task <T> > asyncFunction, IRedisRetryPolicy retryPolicy)
        {
            IRedisRetryPolicy callPolicy = null == retryPolicy ? _DefaultRetryPolicy : retryPolicy;
            int      retryCount          = callPolicy.MaxRetry;
            Task <T> returnValue         = Task.Run <T>(async() =>
            {
                TimeSpan?delay = null;
                while (true)
                {
                    try
                    {
                        T taskResult = await asyncFunction();
                        return(taskResult);
                    }
                    catch (Exception callError)
                    {
                        if (retryCount > 0 && callPolicy.ShouldRetry(callError))
                        {
                            retryCount--;
                            delay = callPolicy.CalculateDelay(retryCount);
                        }
                        else
                        {
                            throw;
                        }
                    }
                    if (delay.HasValue)
                    {
                        await Task.Delay(delay.Value);
                    }
                }
            });

            return(returnValue);
        }
        public RedisIntegrationTest()
        {
            _testObject           = new CachingTestClass();
            _serializedTestObject = KrakenSerializer.Serialize(_testObject);

            _redisRetryPolicy = new RedisRetryPolicy(50, 100, 150);
            _connection       = new RedisConnection(RedisConnectionString, _redisRetryPolicy);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="RedisConnection"/> class.
        /// </summary>
        /// <param name="connectionString">Connection string to Redis</param>
        /// <param name="redisRetryPolicy">Retry policy</param>
        public RedisConnection(string connectionString, IRedisRetryPolicy redisRetryPolicy)
        {
            _setKeyChannel = "~SetKey~:" + _instanceId;

            _baseRetryPolicy = Policy.Handle<TimeoutException>()
                                     .Or<TimeoutException>()
                                     .Or<SocketException>()
                                     .Or<IOException>();  // for async
            _retryPolicy = GetBaseRetryPolicyBuilder().WaitAndRetry(redisRetryPolicy.SleepDurations);
            _retryPolicyAsync = GetBaseRetryPolicyBuilder().WaitAndRetryAsync(redisRetryPolicy.SleepDurations);

            var options = ConfigurationOptions.Parse(connectionString);
            ConfigureIfMissing(options, "abortConnect", connectionString, o => { o.AbortOnConnectFail = false; });
            ConfigureIfMissing(options, "allowAdmin", connectionString, o => { o.AllowAdmin = true; });

            _multiplexer = ConnectionMultiplexer.Connect(options);
            _multiplexer.PreserveAsyncOrder = false;

            SubscribeToEvents();
        }
 /// <summary>
 /// execute the function and return an async task result using the retry policy
 /// </summary>
 public static Task <T> ExecuteWithRetryAsync <T>(this IRedisRetryPolicy retryPolicy, Func <Task <T> > asyncFunction)
 {
     return(ExecuteWithRetryInternalAsync(() => asyncFunction(), retryPolicy));
 }
 /// <summary>
 /// execute the action using the retry policy with async operations
 /// </summary>
 public static Task ExecuteWithRetryAsync(this IRedisRetryPolicy retryPolicy, Func <Task> redisAction)
 {
     return(ExecuteWithRetryInternalAsync(redisAction, retryPolicy));
 }
 /// <summary>
 /// execute the action using the retry policy
 /// </summary>
 public static void ExecuteWithRetry(this IRedisRetryPolicy retryPolicy, Action redisAction)
 {
     ExecuteWithRetryInternal(redisAction, retryPolicy);
 }