パイプライン
7. クラウド汎用パターン
あらゆるプロジェクトで使用推奨
クラウド汎用パターン
あらゆるプロジェクトで使用推奨
• Retry パターン
• 概要
• クラウドでは一時的な障害は珍しくない。障害発生時にその影響を最小限に抑える。
• 戦略
• 障害を示すエラーが一時的でない、または繰り返し要求しても成功する可能性が無い場合 、アプリケーションは操作を中止し、適切な例外を報告す る必要がある。(例:資格情報が無効なため、何度挑戦しても失敗する)
• 報告された例外が通常は起こりえないものや極希少なものの場合、極めて異常な事情によってその例外が引き起されている可能性がある。(例:
ネットワークパケットの破損)このような場合は同一の障害が繰り返される可能性は低いし、再要求は恐らく成功するので直ちに再試行を行う。
• 障害の原因が一般的な接続の問題や接続先がビジー状態によるものの場合、接続時の問題が解決するか、接続先のタスクがクリアされるまで短時間 の待ち時間が必要な場合がある。このような場合、アプリケーションは要求を再試行する前に適切な時間を待つ必要がある。
アプリケーション サービス
1
500
2
500
3
200
クラウド汎用パターン
あらゆるプロジェクトで使用推奨
• Retry パターン実装例
private int retryCount = 3;
public async Task OperationWithBasicRetryAsync() {
int currentRetry = 0;
for (; ;) {
try {
// 外部サービスの呼び出し.
await TransientOperationAsync();
// Return or break.
break;
}
catch (Exception ex) {
Trace.TraceError("Operation Exception");
currentRetry++;
// 一時的なエラーか判定。
if (currentRetry > this.retryCount || !IsTransient(ex)) {
// 一時的なエラーではない場合、リトライしない throw;
} }
// リトライの待機。
Await.Task.Delay();
} }
// リモートサービス非同期呼び出しメソッド. private async Task TransientOperationAsync() {
...
}
private bool IsTransient(Exception ex) {
// 例外が一時的なものか判定
// 例外のタイプのチェックだけでよい場合もあるが、時には例外のプロパティ値のチェックも必要 if (ex is OperationTransientException)
return true;
var webException = ex as WebException;
if (webException != null) {
// web exceptionのStatusが以下のStatus値のいずれかの場合、一時的なエラーとみなす return new[] { WebExceptionStatus.ConnectionClosed,
WebExceptionStatus.Timeout,
WebExceptionStatus.RequestCanceled }.
Contains(webException.Status);
}
// 追加の例外チェックはここに実装 return false;
}
クラウド汎用パターン
あらゆるプロジェクトで使用推奨
• でも Azure の SDK を使用する場合は先ほどのような実装はしません
Storage アクセスの場合の Retry 実装例
• 最初から Retry の仕組みが用意されています。
CloudStorageAccount storageAccount =new CloudStorageAccount(new StorageCredentials(Configs.StorageAccountNameSupply, Configs.StorageAccountKeySupply), true);
varclient = storageAccount.CreateCloudBlobClient();
client.RetryPolicy =newMicrosoft.WindowsAzure.Storage.RetryPolicies.ExponentialRetry(TimeSpan.FromSeconds(2), Configs.RetryMaxCount);
usingMicrosoft.Practices.EnterpriseLibrary.TransientFaultHandling;
・・・
varsqlConn = newSqlConnection(sqlConnString);
varpolicy =new RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy>(retryCount: 3, initialInterval:TimeSpan.FromSeconds(30), increment:TimeSpan.FromSeconds(30));
sqlConn.OpenWithRetry(policy);