大量の行セットを取得するために使用されるSQLサーバーCLRストアドプロシージャがあり、プロセスを実行して別のテーブルのカウントを更新します。
フローは次のとおりです。
選択 -> プロセス -> カウントの更新 -> 選択した行を処理済みとしてマーク
このプロセスの性質上、同じデータ セットを 2 回カウントすることはできません。また、SP は GUID を引数として呼び出されます。
そのため、現在処理中の GUID のリストを (SP の静的リストに) 保持し、現在処理中の GUID が終了するまで、同じ引数を使用して SP への後続の呼び出しの実行を停止します。
プロセスが最終ブロックで終了したときに GUID を削除するコードがありますが、毎回機能しているわけではありません。最終ブロックを呼び出さずに SP が終了し、リストから GUID を削除せずに SP が終了するインスタンス (ユーザーが SP の実行をキャンセルした場合など) があるため、後続の呼び出しは無期限に待機し続けます。
いつでも1つのIDのみが処理されていることを確認するための解決策や、最終ブロックが何に関係なく呼び出されるようにする解決策を教えてください。
処理ビットを削除したコードのサンプルを次に示します。
[Microsoft.SqlServer.Server.SqlProcedure]
public static void TransformSurvey(Guid PublicationId)
{
AutoResetEvent autoEvent = null;
bool existing = false;
//check if the process is already running for the given Id
//concurrency handler holds a dictionary of publicationIds and AutoresetEvents
lock (ConcurrencyHandler.PublicationIds)
{
existing = ConcurrencyHandler.PublicationIds.TryGetValue(PublicationId, out autoEvent);
if (!existing)
{
//there's no process in progress. so OK to start
autoEvent = new AutoResetEvent(false);
ConcurrencyHandler.PublicationIds.Add(PublicationId, autoEvent);
}
}
if (existing)
{
//wait on the shared object
autoEvent.WaitOne();
lock (ConcurrencyHandler.PublicationIds)
{
ConcurrencyHandler.PublicationIds.Add(PublicationId, autoEvent); //add this again as the exiting thread has removed this from the list
}
}
try
{
// ... do the processing here..........
}
catch (Exception ex)
{
//exception handling
}
finally
{
//remove the pubid
lock (ConcurrencyHandler.PublicationIds)
{
ConcurrencyHandler.PublicationIds.Remove(PublicationId);
autoEvent.Set();
}
}
}