私はポリシーを作成しようとしています。実行ブロックの最大時間...リトライと中間ディレイを使用して
実行コードを最大時間(この例では10秒)実行します。 しかし、私はまたx回数(サンプルで3回)をやり直したいと思います。そして、失敗の一時停止(サンプルの2秒間)を中断します。
私は私の動作をテストするために人為的に遅延するために私のストアドプロシージャを組み立てました。
私のデータセットはコード化されているので、30秒後にデータセットが読み込まれます(fyi:30秒はストアドプロシージャのハードコード値)。だから私の実行コードは10秒後に救済されません....
理想的には、最初の2回の試行で10秒後に救済されるコードを見て、人為的に遅延する)。明らかにこれは実際のコードではありませんが、不思議なストアドプロシージャは私にその動作をテストする方法を与えます。
マイストアドプロシージャ:
USE [Northwind]
GO
/* CREATE */ ALTER PROCEDURE [dbo].[uspWaitAndReturn]
(
@InvokeDelay bit
)
AS
SET NOCOUNT ON;
if (@InvokeDelay > 0)
BEGIN
WAITFOR DELAY '00:00:30';
END
select top 1 * from dbo.Customers c order by newid()
GO
マイC#/ポリー/データベース・コード:
public DataSet GetGenericDataSet()
{
DataSet returnDs = null;
int maxRetryAttempts = 3; /* retry attempts */
TimeSpan pauseBetweenFailuresTimeSpan = TimeSpan.FromSeconds(2); /* pause in between failures */
Policy timeoutAfter10SecondsPolicy = Policy.Timeout(TimeSpan.FromSeconds(10)); /* MAGIC SETTING here, my code inside the below .Execute block below would bail out after 10 seconds */
Policy retryThreeTimesWith2SecondsInBetweenPolicy = Policy.Handle<Exception>().WaitAndRetry(maxRetryAttempts, i => pauseBetweenFailuresTimeSpan);
Policy aggregatePolicy = timeoutAfter10SecondsPolicy.Wrap(retryThreeTimesWith2SecondsInBetweenPolicy);
int attemptCounter = 0; /* used to track the attempt and conditionally set the @InvokeDelay value for the stored procedure */
aggregatePolicy.Execute(() =>
{
try
{
attemptCounter++;
/* Microsoft.Practices.EnterpriseLibrary.Data code */
////////DatabaseProviderFactory factory = new DatabaseProviderFactory();
////////Database db = factory.CreateDefault();
////////DbCommand dbc = db.GetStoredProcCommand("dbo.uspWaitAndReturn");
////////dbc.CommandTimeout = 120;
////////db.AddInParameter(dbc, "@InvokeDelay", DbType.Boolean, attemptCounter < maxRetryAttempts ? true : false); /* if i'm not on my last attempt, then pass in true to cause the artificial delay */
////////DataSet ds;
////////ds = db.ExecuteDataSet(dbc);
////////returnDs = ds;
using (SqlConnection conn = new SqlConnection(@"MyConnectionStringValueHere"))
{
SqlCommand sqlComm = new SqlCommand("[dbo].[uspWaitAndReturn]", conn);
sqlComm.Parameters.AddWithValue("@InvokeDelay", attemptCounter < maxRetryAttempts ? true : false);
sqlComm.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = sqlComm;
DataSet ds = new DataSet();
da.Fill(ds);
returnDs = ds;
}
}
catch (Exception ex)
{
string temp = ex.Message;
throw;
}
});
return returnDs;
}
用い文:
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
//// using Microsoft.Practices.EnterpriseLibrary.Data;
using Polly;
バージョン(packages.config)
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommonServiceLocator" version="1.0" targetFramework="net40" />
<package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net45" />
<package id="EnterpriseLibrary.Data" version="6.0.1304.0" targetFramework="net45" />
<package id="Polly" version="5.6.1" targetFramework="net45" />
/>
</packages>
APPEND:
@mountain旅行者からの素晴らしい答えた後、私は作業例を持っている:
追加TimeoutStrategy.Pessimistic
とされたDbCommandを追加しました:
重要なポイントでした。 Cancel()コール(エンタープライズライブラリを使用しない場合はSqlCommand.Cancel())を使用して(以前の)コマンドを強制終了します。
また、私は "ポリシーaggregatePolicy"を "逆転"しなければなりませんでした。
public DataSet GetGenericDataSet()
{
DataSet returnDs = null;
DbCommand dbc = null; /* increase scope so it can be cancelled */
int maxRetryAttempts = 3; /* retry attempts */
TimeSpan pauseBetweenFailuresTimeSpan = TimeSpan.FromSeconds(2); /* pause in between failures */
Policy timeoutAfter10SecondsPolicy = Policy.Timeout(
TimeSpan.FromSeconds(10),
TimeoutStrategy.Pessimistic,
(context, timespan, task) =>
{
string x = timespan.Seconds.ToString();
if (null != dbc)
{
dbc.Cancel();
dbc = null;
}
});
Policy retryThreeTimesWith2SecondsInBetweenPolicy = Policy.Handle<Exception>().WaitAndRetry(maxRetryAttempts, i => pauseBetweenFailuresTimeSpan);
////Policy aggregatePolicy = timeoutAfter10SecondsPolicy.Wrap(retryThreeTimesWith2SecondsInBetweenPolicy);
Policy aggregatePolicy = retryThreeTimesWith2SecondsInBetweenPolicy.Wrap(timeoutAfter10SecondsPolicy);
int attemptCounter = 0; /* used to track the attempt and conditionally set the @InvokeDelay value for the stored procedure */
aggregatePolicy.Execute(() =>
{
try
{
attemptCounter++;
/* Microsoft.Practices.EnterpriseLibrary.Data code */
DatabaseProviderFactory factory = new DatabaseProviderFactory();
Database db = factory.CreateDefault();
dbc = db.GetStoredProcCommand("dbo.uspWaitAndReturn");
dbc.CommandTimeout = 120;
db.AddInParameter(dbc, "@InvokeDelay", DbType.Boolean, attemptCounter < maxRetryAttempts ? true : false); /* if i'm not on my last attempt, then pass in true to cause the artificial delay */
DataSet ds;
ds = db.ExecuteDataSet(dbc);
returnDs = ds;
////////using (SqlConnection conn = new SqlConnection(@"YOUR_VALUE_HERE"))
////////{
//////// SqlCommand sqlComm = new SqlCommand("[dbo].[uspWaitAndReturn]", conn);
//////// sqlComm.Parameters.AddWithValue("@InvokeDelay", attemptCounter < maxRetryAttempts ? true : false);
//////// sqlComm.CommandType = CommandType.StoredProcedure;
//////// SqlDataAdapter da = new SqlDataAdapter();
//////// da.SelectCommand = sqlComm;
//////// DataSet ds = new DataSet();
//////// da.Fill(ds);
//////// returnDs = ds;
////////}
}
catch (SqlException sqlex)
{
switch (sqlex.ErrorCode)
{
case -2146232060:
/* I couldn't find a more concrete way to find this specific exception, -2146232060 seems to represent alot of things */
if (!sqlex.Message.Contains("cancelled"))
{
throw;
}
break;
default:
throw;
}
}
});
return returnDs;
}
私はDbCommand.Cancel()(具体的にはSqlCommand.Cancel()です)を作成していました。ありがとう。私は私のaggregatePolicyを "後方に"持っていると思います。 – granadaCoder
私は完全な作業コードとSQLプロファイラのスクリーンショットで私の元の質問を追加しました。再度、感謝します。 – granadaCoder