我正在尝试构建一个发送电子邮件的重试机制。我希望它是可配置的,以便管理员可以指定两者;
进一步的要求是每次重试之间等待的秒数以指数方式(或遵循其他几何序列)增加到最大值。
另一种描述问题的方法是:如何将最大秒数划分为X个间隔,其间每个间隔比其前一个间隔指数大?
我不确定这是否可以使用纯粹的数学表示来表达,如果不是C#中的例子会受到欢迎。但是,我真的只是在寻找这里的逻辑,所以如果它得到了很好的解释,我确信任何语言都可以轻松翻译。
答案 0 :(得分:3)
一些数学:让变量T
(总时间),N
(重试次数),t
(第一次尝试的时间)和e
(指数) 。每次尝试都需要:t*1
,t*e
,t*e*e
,t*e*e*e
等。
所以总时间可写为T = t*e^0 + t*e^1 + t*e^2 +.. + t*e^N
重写:T = t*(e^0+e^1+e^2 .. + e^N)
。我们可以将sum of powers计算为:sum = (e^N-1)/(e-1)
。
由于T
,N
和e
,我们可以将t
计算为:t = T/((e^N-1)/(e-1))
要计算i
次迭代使用的时间:ti = t*e^i
例如,给定T = 124(s),N = 5(尝试)并且e = 2,第一个间隔将是124/((2^5-1)/(2-1)) = 4s
。以下间隔将是:
等待124秒的总时间。
抱歉格式化。对于Mathematics,这个问题可能会更好。
计算所有间隔的代码是:
public static void TestFunction(int max, int numIntervals) {
List<double> intervals = new List<double>();
double exponent = 2;
double n = Math.Pow(exponent, numIntervals) - 1;
double d = exponent - 1;
double t = max / (n / d);
for (int x = 0; x < numIntervals; x++) {
double interval = t * Math.Pow(exponent, x);
intervals.Add(interval);
}
}
答案 1 :(得分:1)
我不确定这个答案有多有用,但创作肯定很有趣。这个答案有些不同的原因是它计算了用于指数计算时间间隔的基础。
因此输入是总时间以及将时间跨度划分为多个时间间隔。指定第一个间隔的长度,挑战是计算剩余的间隔,以确保它们呈指数增长并总和为总时间。
这可以表示为数学方程式:
t∙x 0 + t∙x 1 + ... + t∙ x n = T
t 是第一个间隔的长度, T 是总时间。 n 是间隔数, x 是未知基数。
假设 x 不是1,则可以将此等式重写为多项式方程的标准形式:
x n - r∙x + r - 1 = 0
其中 r = T / t 是总时间与第一个间隔长度之间的比率。
据我所知,这个方程没有通用的解决方案,但可以使用数值分析库中的算法来解决。我从Math.Net Numerics上的NuGet库中选择了Newton-Raphson算法。对于该算法,需要多项式的一阶导数,这是
n∙x n - 1 - r
将所有这些组合起来创建一系列指数增长的时间跨度等待:
IEnumerable<TimeSpan> ExponentialTimeSpans(TimeSpan firstTimeSpan, TimeSpan totalTimeSpan, Int32 count) {
var ratio = totalTimeSpan.TotalSeconds/firstTimeSpan.TotalSeconds;
var @base = RobustNewtonRaphson.FindRoot(
x => Math.Pow(x, count) - ratio*x + ratio - 1,
x => count*Math.Pow(x, count - 1) - ratio,
1d + 1E-8, // Assume that base is > 1
100d // Arbitrary (but BIG) upper limit on base
);
for (var i = 0; i < count; i += 1)
yield return TimeSpan.FromSeconds(firstTimeSpan.TotalSeconds*Math.Pow(@base, i));
}
请注意,您可以轻松地提供没有解决方案的输入,这将导致抛出异常。但是,任何基于原始问题陈述的合理输入都应按预期工作。
答案 2 :(得分:0)
可能会出现以下情况?
var time_in_seconds = 10000; // usually done in milliseconds, so lets say 10 sec.
// if email fails:
time_in_seconds *= 10;
// So, next will be 100, 1000, etc. & you get your exponential increment.
答案 3 :(得分:0)
第一步 - 一个简单的解决方案 - 反向工作! (减少率为50%)
我需要在10秒内完成128秒。
Interval : Time (Of occurrence)
1 : 128
2 : 64
3 : 32
4 : 16
5 : 8
6 : 4
7 : 2
8 : 1
9 : 1/2
10 : 1/4
注意:以上工作正常(保持在X下,只是从X / 2开始)。下面,没有那么多。这种技术可以迭代地应用于找到一个好的&#39;解决方案虽然现在。
很好,但如果我们需要最低限度会怎么样?可能不需要在开始时重试之间的1/128秒。所以我们需要做的是改变指数。
现在,上述内容可以写成result = 1/4 * 2^9
或更一般result = startingInterval * 2^(n-1)
。但是我们知道我们想要的结果,所以我们需要重新安排这个公式。
(result/startingInterval)^(1/(n-1)) = base
具有以上价值:
(128/(1/4))^(1/(10-1)) = base = 2
或换句话说,要获得128秒的总时间,以1/4秒的间隔开始并使用10次尝试(包括第一次),那么我们需要每次尝试将间隔之间的长度增加2倍。
答案 4 :(得分:-1)
声明最大阈值以及为每次重试添加的偏移量。
int maxRetryCount = 5;
int offSet = 10000;
int currRetryCount = 0;
int waitTime = 1000; //default value
while(currRetryCount < maxRetryCount)
{
try
{
//Send Email
// break out once the email is send
break;
}
catch
{
//Wait for a while
Thread.Sleep(waitTime);
//increase the wait time for next time
waitTime += offSet;
currRetryCount++;
}
}
此处代码最多会尝试5次发送电子邮件,每次等待时间将增加10秒。