簡體   English   中英

Singleton Lock for Azure Webjob's TimerTrigger across multiple regions

[英]Singleton Lock for Azure Webjob's TimerTrigger accross multiple regions

我有一個跨多個區域部署的計時器觸發的 web 作業,它在給定的預定時間從所有區域同時觸發,我如何確保一次只運行一個作業實例。 我嘗試應用Singleton屬性和"is_singleton": true但它仍然從所有區域觸發。

有沒有其他方法可以實現這一目標。 鏈接表示 Singleton 屬性不再用於此目的,而且我也沒有看到在 azure blob 存儲中創建任何鎖定文件。 如果它是真的,我們如何實現它以確保從多個區域只觸發一個區域。 或者如果有任何其他內置方法可以通過 webjob sdk 實現這一點,那對我來說真的很有幫助

我的程序.cs

var builder = new HostBuilder();
builder
    .ConfigureWebJobs((context, b) =>
    {
        b.AddAzureStorageCoreServices();
    });
var host = builder.Build();
using (host)
{
    var jobHost = host.Services.GetService(typeof(IJobHost)) as JobHost;
    await host.StartAsync().ConfigureAwait(false);
    await jobHost.CallAsync("Run").ConfigureAwait(false);
    await host.StopAsync().ConfigureAwait(false);
}

Function.cs

[Singleton]
[NoAutomaticTrigger]
public async Task Run()
{
}

設置.job

{
  "schedule": "0 */5 * * * *",
  "is_singleton": true
}

nuget package

<PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="4.0.1" />

所以聽起來您希望每個區域都運行,但不是同時運行。

一個簡單的解決方案是將它們錯開,這樣它們就不會同時運行,但是您可以為每個時間分配一個稍微不同的 cron 時間,例如彼此相距 10m。

但是假設你無法預測它們將運行多長時間,或者你本質上希望它們運行得比最小 10m 快得多,並且假設它們都可以訪問一個數據庫,例如 Azure Cosmos Mongo,那么你可以添加一個表和一些簡單的邏輯,本質上是 model 一個“鎖定”模式。

在 mongodb 中,您可以使用findOneAndUpdate function 對眾所周知的文檔進行原子更新,這樣一次只允許一個進程“鎖定”一個文檔。

本例中的數據庫包含一個集合(又名表)和一個文檔(又名行),如下所示:

interface ILock {
  state: 'UNLOCKED' | 'LOCKED';
  lockedBy: null | string;
  lockedAt: null | Date;
}

偽代碼

while (true)
{
  // todo: add some kind of timeout here so it doesn't run forever.

  // `findOneAndUpdate` is atomic, if multiple processes
  // attempt to do this modification simultaneously
  // only one will succeed, the others will get an `undefined`
  // result to indicate the document was not found.
  var lock = await this.db.locks.findOneAndUpdate(
    { state: 'UNLOCKED' },
    {
      $set: {
        state: 'LOCKED',
        lockedBy: this.jobId,
        lockedAt: new Date()
      }
    }
  )

  if (lock) {
    try {
      // you have the lock, do your thing...
      await DoWork();
      // you are done, exit the loop.
      return;
    } finally {
      // don't forget to unlock!
      await this.db.locks.findOneAndUpdate(
        { state: 'LOCKED' },
        {
          $set: {
            state: 'UNLOCKED',
          }
        }
      )
    }
  } else {
    // you are not the one neo, take the blue pill...
    await sleep(3000)
  }
  
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM