现在我正在使用 Azure Functions 创建一个 HTTP 无服务器函数,因此我需要在访问我的存储帐户上的单个 Blob 存储项时使我的传入请求同步。
我想要发生的事情如下:
// Incoming Request 1
// .. Get blob
await myBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1), leaseId);
// .. 10 seconds later
await myblob.ReleaseLeaseAsync(AccessCondition.GenerateEmptyCondition());
//
// MEANWHILE
//
// Incoming Request 2 (Happens 1-2 seconds after Request 1)
// .. Get blob
// .. -- Wait until Lease is released from Request 1 --
await myBlob.AcquireLeaseAsync(TimeSpan.FromMinutes(1), leaseId);
// Repeat...
但是我注意到,当我尝试在请求 2 上获取 Blob 时,它不会同步等待 Blob 租约从请求 1 中释放,它只是返回一个错误,表明此 blob 上已经有一个事件租约,然后继续。
是否可以在 Azure Function 中拥有上述同步系统?
请您参考如下方法:
当您获得租约 blob 时,您收到的错误(可能是代码=409)是正确的。这是无服务器分布式模型的完美行为,在该模型中,更多功能(作业、工作人员等)希望对租用 blob 具有独占访问权限。
只有他们中的一个可以成为赢家,其他人必须定期再次要求获得租约。 建议在此获取期间使用随机等待时间。
以下代码片段显示了 azure 函数中此“循环逻辑”的示例:
// Acquireing a Lease blob
public async static Task<string> LockingEntity(dynamic entity, int leaseTimeInSec = 60, string leaseId = null)
{
while (true)
{
try
{
string lid = await entity.AcquireLeaseAsync(TimeSpan.FromSeconds(leaseTimeInSec), leaseId);
if (string.IsNullOrEmpty(lid))
await Task.Delay(TimeSpan.FromMilliseconds(new Random(Guid.NewGuid().GetHashCode()).Next(250, 1000)));
else
return lid;
}
catch (StorageException ex)
{
if (ex.RequestInformation.HttpStatusCode != 409)
throw;
}
}
}
上述方法在azure函数中的用法:
string leaseId = await LockingEntity(blockBlob);
if (string.IsNullOrEmpty(leaseId) == false)
{
try
{
string esp = await blockBlob.DownloadTextAsync(Encoding.UTF8, AccessCondition.GenerateLeaseCondition(leaseId), null, null);
state = JsonConvert.DeserializeObject<State>(esp);
// …
}
finally
{
await blockBlob.ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(leaseId));
}
}
另外,看看我的文章Using Azure Lease Blob无服务器事件驱动分布式架构中的更多模式等。
