Last active
August 28, 2021 22:20
-
-
Save dfch/ebdb945d9f561bd5b91e83b431bc5fe8 to your computer and use it in GitHub Desktop.
Transient Error Handling with automatic Retries in C# - d-fens.net -
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System; | |
using System.Diagnostics; | |
using System.Diagnostics.Contracts; | |
namespace Net.Appclusive.Core.Domain.General | |
{ | |
public class Retry | |
{ | |
public static RetryStrategyExponential ExponentialStrategy = new RetryStrategyExponential(); | |
public static RetryStrategyIncremental IncrementalStrategy = new RetryStrategyIncremental(); | |
public static RetryStrategyFixed FixedStrategy = new RetryStrategyFixed(); | |
public static TResult Invoke<TResult> | |
( | |
Func<RetryStrategyBase, TResult> func, | |
Action<RetryStrategyBase, Exception> exceptionFilter = null, | |
Func<RetryStrategyBase, TResult> defaultReturnValueFactory = null, | |
RetryStrategyExponential strategy = null | |
) | |
{ | |
Contract.Requires(null != func); | |
if (null == strategy) | |
{ | |
strategy = ExponentialStrategy; | |
} | |
var waitTime = strategy.MinWaitTimeIntervalMilliseconds; | |
var stopwatch = Stopwatch.StartNew(); | |
for (;;) | |
{ | |
try | |
{ | |
return func.Invoke(strategy); | |
} | |
catch (Exception ex) | |
{ | |
exceptionFilter?.Invoke(strategy, ex); | |
} | |
if (strategy.CurrentAttempt >= strategy.MaxAttempts) | |
{ | |
break; | |
} | |
// check if maximum time has already elapsed | |
if (stopwatch.ElapsedMilliseconds >= strategy.MaxWaitTimeMilliseconds) | |
{ | |
break; | |
} | |
// wait for next retry | |
System.Threading.Thread.Sleep(waitTime); | |
// get next wait time interval | |
waitTime = strategy.GetNextWaitTime(waitTime); | |
strategy.NextAttempt(); | |
} | |
return null != defaultReturnValueFactory | |
? defaultReturnValueFactory.Invoke(strategy) | |
: default(TResult); | |
} | |
public static TResult Invoke<TResult> | |
( | |
Func<TResult> func, | |
Action<Exception> exceptionFilter = null, | |
Func<TResult> defaultReturnValueFactory = null, | |
RetryStrategyExponential strategy = null | |
) | |
{ | |
Contract.Requires(null != func); | |
if (null == strategy) | |
{ | |
strategy = ExponentialStrategy; | |
} | |
var waitTime = strategy.MinWaitTimeIntervalMilliseconds; | |
var stopwatch = Stopwatch.StartNew(); | |
for (;;) | |
{ | |
try | |
{ | |
return func.Invoke(); | |
} | |
catch (Exception ex) | |
{ | |
exceptionFilter?.Invoke(ex); | |
} | |
if (strategy.CurrentAttempt >= strategy.MaxAttempts) | |
{ | |
break; | |
} | |
// check if maximum time has already elapsed | |
if (stopwatch.ElapsedMilliseconds >= strategy.MaxWaitTimeMilliseconds) | |
{ | |
break; | |
} | |
// wait for next retry | |
System.Threading.Thread.Sleep(waitTime); | |
// get next wait time interval | |
waitTime = strategy.GetNextWaitTime(waitTime); | |
strategy.NextAttempt(); | |
} | |
return null != defaultReturnValueFactory | |
? defaultReturnValueFactory.Invoke() | |
: default(TResult); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
namespace Net.Appclusive.Core.Domain.General | |
{ | |
public abstract class RetryStrategyBase | |
{ | |
public int MaxAttempts = int.MaxValue; | |
public int CurrentAttempt = 1; | |
public int MaxWaitTimeMilliseconds = 300 * 1000; | |
public int MinWaitTimeIntervalMilliseconds = 200; | |
public int MaxWaitTimeIntervalMilliseconds = 20 * 1000; | |
public object StateInfo; | |
public int NextAttempt() | |
{ | |
return ++CurrentAttempt; | |
} | |
public abstract int GetNextWaitTime(int currentWaitTime); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System; | |
using System.Diagnostics.Contracts; | |
namespace Net.Appclusive.Core.Domain.General | |
{ | |
public class RetryStrategyCustom : RetryStrategyBase | |
{ | |
private readonly Func<RetryStrategyCustom, int> waitTimeFactory; | |
protected RetryStrategyCustom(Func<RetryStrategyCustom, int> waitTimeFactory) | |
{ | |
Contract.Requires(null != waitTimeFactory); | |
this.waitTimeFactory = waitTimeFactory; | |
} | |
public override int GetNextWaitTime(int currentWaitTime) | |
{ | |
return waitTimeFactory(this); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System; | |
namespace Net.Appclusive.Core.Domain.General | |
{ | |
public class RetryStrategyExponential : RetryStrategyBase | |
{ | |
public double Factor = Math.Sqrt(2); | |
public override int GetNextWaitTime(int currentWaitTime) | |
{ | |
return (int) Math.Min(MaxWaitTimeIntervalMilliseconds, Math.Max(MinWaitTimeIntervalMilliseconds, currentWaitTime * Factor)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
namespace Net.Appclusive.Core.Domain.General | |
{ | |
public class RetryStrategyFixed : RetryStrategyBase | |
{ | |
public override int GetNextWaitTime(int currentWaitTime) | |
{ | |
return currentWaitTime; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2017 d-fens GmbH | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
using System; | |
namespace Net.Appclusive.Core.Domain.General | |
{ | |
public class RetryStrategyIncremental : RetryStrategyBase | |
{ | |
public override int GetNextWaitTime(int currentWaitTime) | |
{ | |
return Math.Min(MaxWaitTimeIntervalMilliseconds, Math.Max(MinWaitTimeIntervalMilliseconds, currentWaitTime)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment