Skip to main content
 首页 » 编程设计

c#之Azure Blob 存储 | AcquireLeaseAsync,同步等待直到锁被释放

2024年01月29日25lvdongjie

现在我正在使用 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无服务器事件驱动分布式架构中的更多模式等。