いくつかの実験を行ったところ、これにより、以前から使用していた古い「接続の管理」の状況に戻ることがわかりました。今回は、接続が少し抽象化され、今は「管理」する必要があります。コンテキスト」も同様です。
OnContextCreated
次の実装があるとしましょう。
private void OnContextCreated()
{
const int maxRetries = 4;
const int initialDelayInMilliseconds = 100;
const int maxDelayInMilliseconds = 5000;
const int deltaBackoffInMilliseconds = initialDelayInMilliseconds;
var policy = new RetryPolicy<SqlAzureTransientErrorDetectionStrategy>(maxRetries,
TimeSpan.FromMilliseconds(initialDelayInMilliseconds),
TimeSpan.FromMilliseconds(maxDelayInMilliseconds),
TimeSpan.FromMilliseconds(deltaBackoffInMilliseconds));
policy.ExecuteAction(() =>
{
try
{
Connection.Open();
var storeConnection = (SqlConnection) ((EntityConnection) Connection).StoreConnection;
new SqlCommand("declare @i int", storeConnection).ExecuteNonQuery();
//Connection.Close();
// throw new ApplicationException("Test only");
}
catch (Exception e)
{
Connection.Close();
Trace.TraceWarning("Attempted to open connection but failed: " + e.Message);
throw;
}
}
);
}
このシナリオでは、接続を強制的に開きます(これがここでの目標でした)。このため、コンテキストは多くの呼び出しにわたってそれを開いたままにします。そのため、接続を閉じるタイミングをコンテキストに通知する必要があります。そのための主要なメカニズムは、コンテキストでDisposeメソッドを呼び出すことです。したがって、ガベージコレクションでコンテキストをクリーンアップするだけの場合は、接続を開いたままにしておくことができます。
Connection.Close()
ブロック内のコメントを切り替えて、try
データベースに対して一連の単体テストを実行することで、これをテストしました。を呼び出さずClose
に、(SQL Serverの観点から)最大275〜300のアクティブな接続にジャンプしました。を呼び出すことによりClose
、その番号は〜12でホバリングしました。次に、コンテキストのブロックがある場合とない場合の両方で少数の単体テストを使用してusing
再現し、同じ結果を再現しました(異なる数値-それらが何であったかを忘れています)。
次のクエリを使用して接続をカウントしていました。
SELECT s.session_id, s.login_name, e.connection_id,
s.last_request_end_time, s.cpu_time,
e.connect_time
FROM sys.dm_exec_sessions AS s
INNER JOIN sys.dm_exec_connections AS e
ON s.session_id = e.session_id
WHERE login_name='myuser'
ORDER BY s.login_name
結論:Connection.Open()
この回避策を呼び出して一時的な障害処理ブロックを有効にする場合は、使用するすべてのコンテキストにusing
ブロックを使用する必要があります。そうしないと、問題が発生します(SQL Azureでは、データベースが「スロットル」される原因になります)。そして最終的には何時間もオフラインになります!)。