后台:我们有一个Azure .NET应用程序,我们需要向多个后端提供商注册一个“前端”用户。由于此注册需要更长时间,因此我们将其卸载到辅助角色,并且有多个辅助角色。所有数据都存储在Azure SQL中,我们使用Entity Framework 5.0作为我们的ORM。我们目前的设置方式是,我们读取来自SQL dB =>工人角色代码中的流程=> 写 /更新到SQL dB以标记完成。基本上我需要解决传统的“多线程+共享数据写入”问题,但不是操作系统规模,而是在云规模上。
关注:如果第一个工作人员的时间超过可见性超时,我们就会遇到多个工作人员的竞争状况。例如,假设有两个工作者角色,我在下面标记了两者如何从SQL读取,认为处理仍处于待处理状态,并且两者都将继续。它导致最后一个作者赢得竞争条件,并在外部服务提供商上创建孤立和额外的帐户。
问题:我如何修改它以优雅地处理这种情况?我可以更改数据流或使用每用户“云”锁定Mutex。在没有试图约束任何人的想法的情况下,过去我推测有一个SQL based cloud lock,但实际上并没有让它在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!
// ...
}
答案 0 :(得分:4)
您可以通过blob租约将mutex放入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);
}