【C#】エラーのリトライ処理(Polly)

C#

Pollyとは

Pollyを利用することでエラー処理をリトライすることができます。
エラーによって書き分けられるので応用力が抜群で、こけやすそうな処理に入れるとプログラムの質が格段に上がります。(個人的にC#で一番好きなライブラリです。)

入手方法

名称バージョン
入手場所Nuget
ライセンスBSD 3-Clauseライセンス

実装例

実装例としてログの書き込みで失敗した場合にリトライさせる処理を記載します。
並列で処理を実行した場合、書き込みでエラーが発生する場合があります。
エラーが発生(System.IO.IOException)した場合、エラーを検知して3秒×リトライ回数分のリトライを繰り返します。
最終的にエラーが発生している場合はMainWindowに通知します。

事前作業

Nugetからダウンロードしてプロジェクトにインポートする。

環境

名称バージョン
フレームワークWPF
.NetFrameworkv4.7.2
Pollyv7.2.0

実装コード

using System;
using System.Windows;
using System.IO;
using System.Text;
using Polly;

namespace WpfApp2
{
	public partial class MainWindow : System.Windows.Window
	{
		public MainWindow()
		{
			try{
				RetrySendAsync_WriteText("テスト書き込み", WriteMessage.WriteText);
			}
			catch (System.Exception ex)
			{
				Console.WriteLine(ex.Message);
			}
		}

		/// <summary>
		/// 外部ライブラリのPollyを使用して、テキスト書き出しをリトライする
		/// リトライ処理の失敗時はエラーを返し上位メソッドに通知
		/// </summary>
		/// <param name="Param1">コールバックファンクションに渡すパラメータ</param>
		/// <param name="callbackFunc">コールバック関数</param>
		public static async Task RetrySendAsync_WriteText(string Param1, Func<string,Task> callbackFunc)
		{
			try
			{
				// 失敗した場合には 3 秒 * リトライ回数ずつ待ち時間を増やして実行
				var policyResult = await Policy.Handle<System.IO.IOException>()
				.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(retryAttempt * 3))
				.ExecuteAndCaptureAsync(async () =>
				{
					await callbackFunc(Param1);
				});
				// Policy が成功したかは Outcome で判断する
				if (policyResult.Outcome == OutcomeType.Failure)
				{
					throw policyResult.FinalException;
				}
				return;
			}
			catch(System.Exception e)
			{
				if(e is System.IO.IOException)
				{
					throw new System.IO.IOException("リトライ処理に失敗しました。");
				}
				else
				{
					throw;
				}
			}
		}
	}

	/// <summary>
	/// StreamWriterでログを書き出します。
	/// </summary>
	/// <param name="strMessage">ログに書き出すメッセージ</param>
	public class WriteMessage
	{
		public static async Task WriteText(string strMessage)
		{
			try{
				Encoding sjisEnc = Encoding.GetEncoding("Shift_JIS");
				using(StreamWriter writer = new StreamWriter("D:\\test.txt", true, sjisEnc))
				{
					await writer.WriteLineAsync(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss ") + strMessage);
				}
				return;
			}
			catch
			{
				throw;
			}
		}
	}
}

最後に

最近はKubernetes漬けになっていたので、一番好きな言語のC#について記事にしてみました。
それとプログラム作るたびに思うけどLinqが優秀すぎるのでそのうち記事にしたいな。

参考サイト