2

背景:単一の "フロント エンド" ユーザーを複数のバック エンド プロバイダーに登録する必要がある 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!
    // ...

}
4

1 に答える 1

4

BLOB リースを使用して、ミューテックスを BLOB ストレージに配置できます。ミューテックスが他の誰かによって使用されている場合、AcquireLease() は失敗するため、全体に try/catch を配置します。

                var lockBlobContainer = cloudClient.GetContainerReference("mutex-container");
                var lockBlob = lockBlobContainer.GetBlobReference("SOME_KNOWN_KEY.lck");
                lockBlob.UploadText(DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)); //creates the mutex file
                var leaseId = lockBlob.AcquireLease();

                try
                {
                    // Do stuff
                }
                finally
                {
                    lockBlob.ReleaseLease(leaseId);
                }
于 2013-01-08T20:44:24.180 に答える