Just built a simple retry engine in C#.

    /// <summary>
    /// Retry engine.
    /// </summary>
    public class RetryEngine
    {
        private static Random rnd = new Random();
        private readonly ILogger<RetryEngine> logger;

        /// <summary>
        /// Creates new retry engine.
        /// </summary>
        /// <param name="logger">Logger</param>
        public RetryEngine(ILogger<RetryEngine> logger)
        {
            this.logger = logger;
        }

        /// <summary>
        /// Run a task with retry.
        /// </summary>
        /// <typeparam name="T">Response type.</typeparam>
        /// <param name="taskFactory">Task factory.</param>
        /// <param name="attempts">Retry times.</param>
        /// <param name="when">On error event.</param>
        /// <returns>Response</returns>
        public async Task<T> RunWithTry<T>(
            Func<int, Task<T>> taskFactory,
            int attempts = 3,
            Predicate<Exception> when = null)
        {
            for (var i = 1; i <= attempts; i++)
            {
                try
                {
                    this.logger.LogInformation($"Starting a job with retry. Attempt: {i}. (Starts from 1)");
                    var response = await taskFactory(i);
                    return response;
                }
                catch (Exception e)
                {
                    if (when != null)
                    {
                        var shouldRetry = when.Invoke(e);
                        if (!shouldRetry)
                        {
                            this.logger.LogInformation($"A task that was asked to retry failed. But from the given condition is false, we gave up retry.");
                            throw;
                        }
                        else
                        {
                            this.logger.LogInformation($"A task that was asked to retry failed. With given condition is true.");
                        }
                    }

                    if (i >= attempts)
                    {
                        this.logger.LogInformation($"A task that was asked to retry failed. Maximum attempts {attempts} already reached. We have to crash it.");
                        throw;
                    }

                    this.logger.LogInformation($"A task that was asked to retry failed. Current attempt is {i}. maximum attempts is {attempts}. Will retry soon...");

                    await Task.Delay(ExponentialBackoffTimeSlot(i) * 1000);
                }
            }

            throw new InvalidOperationException("Code shall not reach here.");
        }

        /// <summary>
        /// Please see <see href="https://en.wikipedia.org/wiki/Exponential_backoff">Exponetial backoff </see> time slot. 
        /// </summary>
        /// <param name="time">the time of trial</param>
        /// <returns>Time slot to wait.</returns>
        private static int ExponentialBackoffTimeSlot(int time)
        {
            var max = (int)Math.Pow(2, time);
            return rnd.Next(0, max);
        }
    }

 

When you have this, you can do in your business code:

this.retryEngine.RunWithTry(attempt =>
{
    return dmsClient.ExecuteManagementCmdlet(cmdletName, parameters);
}, when: e => e is WebException, attempts: 3);