using System; using System.Threading.Tasks; using Microsoft.Data.SqlClient; namespace Tapeti.Flow.SQL { internal class SqlRetryHelper { public static readonly TimeSpan[] ExponentialBackoff = { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(13), TimeSpan.FromSeconds(21), TimeSpan.FromSeconds(34), TimeSpan.FromSeconds(55) }; public static async Task Execute(Func callback) { var retryAttempt = 0; while (true) { try { await callback(); break; } catch (SqlException e) { if (SqlExceptionHelper.IsTransientError(e)) { await Task.Delay(ExponentialBackoff[retryAttempt]); if (retryAttempt < ExponentialBackoff.Length - 1) retryAttempt++; } else throw; } } } public static async Task Execute(Func> callback) { var returnValue = default(T); await Execute(async () => { returnValue = await callback(); }); return returnValue!; } } }