背景:単一の "フロント エンド" ユーザーを複数のバック エンド プロバイダーに登録する必要がある Azure .NET アプリケーションがあります。この登録には時間がかかるため、worker ロールにオフロードし、複数の worker ロールがあります。すべてのデータは Azure SQL に保存され、ORM として Entity Framework 5.0 を使用しています。現在のセットアップ方法では、SQL dB から読み取る=> ワーカー ロール コードのプロセス => SQL dB に書き込み/ 更新して、完了のフラグを立てます。基本的に、従来の「マルチスレッド + 共有データ書き込み」の問題を解決する必要がありますが、OS スケールではなく、クラウド スケールです。
懸念: 最初のワーカーが可視性タイムアウトよりも長くかかる場合、複数のワーカーと競合状態になります。たとえば、2 つの worker ロールを想定して、両方が SQL から読み取る方法を以下に示しました。処理がまだ保留中であり、両方が続行すると考えてください。これにより、last-writer-wins 競合状態が発生し、孤立した余分なアカウントが外部サービス プロバイダーに作成されます。
質問: これを変更して、この状況をエレガントに処理するにはどうすればよいですか? データ フローを変更するか、Mutex のユーザーごとの「クラウド」ロックを使用できます。誰の考えにも縛られずに、過去に私はSQL ベースのクラウド ロックを持っていると推測しましたが、EF5.0 で実際に動作させることはできませんでした。ここでは、SQL ベースのロックであるかどうかにかかわらず、答えを調べようとしています。
// Read message off Service Bus Queue
// message invisible for 1 min now, worker must finish in 1 min
BrokeredMessage qMsg = queueClient.Receive();
// Extract UserID Guid from message
Guid userProfileId = DeserializeUserIdFromQMsg(qMsg);
// READ PROFILE FROM SQL
UserProfile up = (from x in myAppDbContext.UserProfiles select x).SingleOrDefault(p => p.UserProfileId == userProfileId);
if (up != null)
{
List<Task> allUserRegTasks = new List<Task>();
string firstName = up.FirstName; // <== WORKER ROLE #2 HERE
string lastName = up.LastName;
string emailAddress = up.Email;
// Step 1: Async register User with provider #1, update db
if (String.IsNullOrEmpty(up.Svc1CustId))
{
// <== WORKER ROLE #1 HERE
Svc1RegHelper svc1RegHelper = new Svc1RegHelper();
Task svc1UserRegTask = svc1RegHelper.GetRegisterTask(userProfileId, firstName, lastName, emailAddress);
svc1UserRegTask.Start(); // <== SQL WRITE INSIDE THIS (marks "up.Svc1CustId")
allUserRegTasks.Add(svc1UserRegTask);
}
// Step 2: Async register User with provider #2, update db
if (String.IsNullOrEmpty(up.Svc2CustId))
{
Svc2RegHelper svc2RegHelper = new Svc2RegHelper();
Task svc2UserRegTask = svc2RegHelper.GetRegisterTask(userProfileId, firstName, lastName, emailAddress);
svc2UserRegTask.Start(); // <== SQL WRITE INSIDE THIS (marks "up.Svc2CustId")
allUserRegTasks.Add(svc2UserRegTask);
}
Task.WaitAll(allUserRegTasks.ToArray());
// Step 3: Send confirmation email to user we're ready for them!
// ...
}