背景:我们有一个 Azure .NET 应用程序,我们需要在其中向多个后端提供商注册一个“前端”用户。由于此注册需要更长的时间,我们将其卸载到工作角色,并且有多个工作角色。所有数据都存储在 Azure SQL 中,我们使用 Entity Framework 5.0 作为我们的 ORM。我们当前的设置方式,我们从 SQL dB读取=> 工作角色代码中的进程 =>写入/update 到 SQL dB 以标记完成。本质上,我需要解决传统的“多线程+共享数据写入”问题,但不是操作系统规模,而是云规模。
关注点:如果第一个工作人员花费的时间超过可见性超时,我们就会有多个工作人员的竞争条件。例如,假设有两个工作角色,我在下面标记了两者将如何从 SQL 中读取,认为处理仍处于未决状态并且两者都将继续进行。它会导致最后写入者获胜的竞争条件,并且还会在外部服务提供商上创建孤立帐户和额外帐户。
问题:如何修改它以优雅地处理这种情况?我可以更改数据流或为 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!
// ...
}