1. はじめに
- DBの関連処理などリトライするケースが発生したので、処理を共通化したい
- メソッドの戻り値の有無があるので、どちらにも対応したい
- リトライ回数、リトライ間隔を設定できるようにしたい
2. 開発環境
- C#
- .Net 6
- Visual Studio 2022
- Windows 11
3. ソースコード
*Staticなユーティリティクラスを準備する
RetryExecteUtil.cs
/// <summary>
/// リトライ処理を行うユーティリティクラス
/// </summary>
public class RetryExecteUtil
{
/// <summary>
/// 処理を実行する
/// 例外が発生した場合は指定秒数間隔でリトライする
/// </summary>
/// <typeparam name="T">リトライ対象メソッドの戻り値(型)</typeparam>
/// <param name="retryMaxCount">最大リトライ回数</param>
/// <param name="retryInterval">リトライ間隔(ミリ秒)</param>
/// <param name="action">リトライ対象メソッド(戻り値あり)</param>
/// <returns>処理結果</returns>
public static T Execute<T>(int retryMaxCount, int retryInterval, Func<T> action)
{
// パラメータチェック
if (retryMaxCount < 0)
{
// 最大リトライ回数
throw new ArgumentOutOfRangeException("retryMaxCount");
}
if (retryInterval < 0)
{
// リトライ間隔
throw new ArgumentOutOfRangeException("retryInterval");
}
if (action == null)
{
// 処理
throw new ArgumentNullException("action");
}
/// <summary>
/// リトライ回数をカウントします
/// </summary>
int retryCount = 0;
while (true)
{
try
{
// メソッド
return action();
}
catch (Exception)
{
// リトライが必要な処理で例外が発生した場合
// 指定回数リトライ
if (retryCount++ < retryMaxCount)
{
// 最大リトライ回数に達していない場合
Thread.Sleep(retryInterval);
}
else
{
// 最大リトライ回数に達した場合
throw;
}
}
}
}
/// <summary>
/// 処理を実行する
/// 例外が発生した場合は指定秒数間隔でリトライする
/// </summary>
/// <param name="retryMaxCount">最大リトライ回数</param>
/// <param name="retryInterval">リトライ間隔(ミリ秒)</param>
/// <param name="action">リトライ対象メソッド(戻り値なし)</param>
public static void Execute(int retryMaxCount, int retryInterval, Action action)
{
// パラメータチェック
if (retryMaxCount < 0)
{
// 最大リトライ回数
throw new ArgumentOutOfRangeException("retryMaxCount");
}
if (retryInterval < 0)
{
// リトライ間隔
throw new ArgumentOutOfRangeException("retryInterval");
}
if (action == null)
{
// 処理
throw new ArgumentNullException("action");
}
/// <summary>
/// リトライ回数をカウントします
/// </summary>
int retryCount = 0;
while (true)
{
try
{
action();
break;
}
catch (Exception)
{
// リトライが必要な処理で例外が発生した場合
// 指定回数リトライ
if (retryCount++ < retryMaxCount)
{
// 最大リトライ回数に達していない場合
Thread.Sleep(retryInterval);
}
else
{
// 最大リトライ回数に達した場合
throw;
}
}
}
}
}
4. 使用方法
4.1. リトライ処理メソッド
var class1 = new Class1();
// 戻り値なしの場合
RetryExecteUtil.Execute(5,1000,()=> class1.RetryVoidMethod());
// 戻り値ありの場合
Debug.Print(RetryExecteUtil.Execute(5,1000,()=> class1.RetryReturnMethod("OK")));
4.2. リトライ対象クラス、メソッド
Class1.cs
public class Class1
{
int _count1 = 0;
int _count2 = 0;
public void RetryVoidMethod()
{
_count1++;
if (_count1 < 5)
{
Debug.Print($"Exception {_count1}");
throw new Exception();
}
}
public string RetryReturnMethod(string s)
{
_count2++;
if (_count2 < 5)
{
Debug.Print($"Exception {_count2}");
throw new Exception();
}
return s;
}
}
4.3 動作確認
デバッグ出力で動作を確認した
Exception 1
例外がスローされました: 'System.Exception'
Exception 2
例外がスローされました: 'System.Exception'
Exception 3
例外がスローされました: 'System.Exception'
Exception 4
例外がスローされました: 'System.Exception'
Exception 1
例外がスローされました: 'System.Exception'
Exception 2
例外がスローされました: 'System.Exception'
Exception 3
例外がスローされました: 'System.Exception'
Exception 4
例外がスローされました: 'System.Exception'
OK
5. 参考文献