/// <summary>
        /// Helper method to execute given function with given user FabricClientRetryErrors and given Operation Timeout
        /// </summary>
        /// <param name="function">Action to be performed</param>
        /// <param name="errors">Fabric Client Errors that can be retired</param>
        /// <param name="operationTimeout">Timeout for the operation</param>
        /// <param name="cancellationToken">Cancellation token for Async operation</param>
        /// <returns>Task object</returns>
        public static async Task <T> ExecuteFabricActionWithRetryAsync <T>(
            Func <Task <T> > function,
            FabricClientRetryErrors errors,
            TimeSpan operationTimeout,
            CancellationToken cancellationToken)
        {
            bool      needToWait = false;
            Stopwatch watch      = new Stopwatch();

            watch.Start();
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (needToWait)
                {
                    await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken).ConfigureAwait(false);

                    needToWait = false;
                }

                try
                {
                    return(await function().ConfigureAwait(false));
                }
                catch (Exception e)
                {
                    bool retryElseSuccess;
                    if (HandleException(e, errors, out retryElseSuccess))
                    {
                        if (retryElseSuccess)
                        {
                            Logger.LogMessage("ExecuteFabricActionWithRetryAsync:; Retrying due to Exp: {0}", e);
                            if (watch.Elapsed > operationTimeout)
                            {
                                Logger.LogMessage(
                                    "ExecuteFabricActionWithRetryAsync:; Done Retrying. Time Elapsed: {0}, Timeout: {1}. Throwing Exception: {2}",
                                    watch.Elapsed.TotalSeconds,
                                    operationTimeout.TotalSeconds,
                                    e);
                                throw;
                            }

                            needToWait = true;
                            continue;
                        }

                        Logger.LogMessage("ExecuteFabricActionWithRetryAsync:; Exception {0} Handled but No Retry", e);
                        return(default(T));
                    }

                    throw;
                }
            }
        }
        private static bool HandleException(Exception e, FabricClientRetryErrors errors, out bool retryElseSuccess)
        {
            FabricException fabricException = e as FabricException;

            if (errors.RetryableExceptions.Contains(e.GetType()))
            {
                retryElseSuccess = true /*retry*/;
                return(true);
            }

            if (fabricException != null && errors.RetryableFabricErrorCodes.Contains(fabricException.ErrorCode))
            {
                retryElseSuccess = true /*retry*/;
                return(true);
            }

            if (errors.RetrySuccessExceptions.Contains(e.GetType()))
            {
                retryElseSuccess = false /*success*/;
                return(true);
            }

            if (fabricException != null && errors.RetrySuccessFabricErrorCodes.Contains(fabricException.ErrorCode))
            {
                retryElseSuccess = false /*success*/;
                return(true);
            }

            if (e.GetType() == typeof(FabricTransientException))
            {
                retryElseSuccess = true /*retry*/;
                return(true);
            }

            if (fabricException != null && fabricException.InnerException != null)
            {
                var ex = fabricException.InnerException as COMException;
                if (ex != null && errors.InternalRetrySuccessFabricErrorCodes.Contains((uint)ex.ErrorCode))
                {
                    retryElseSuccess = false /*success*/;
                    return(true);
                }
            }

            retryElseSuccess = false;
            return(false);
        }