![](/img/trans.png)
[英]How to read the Azure App Configuration in Service Fabric ASP.NET Core Stateless Web API?
[英]Named semaphore not working on ASP .Net Core 5 Web API hosted on Azure App Service
我有一個運行在 Azure App Service 上的 ASP.Net Core 5 Web API。 它每天運行一次 Hosted BackgroundService。 因為我只希望此服務每天運行一次(凌晨 2 點),並且因為我的 App Service 已打開自動擴展(當 CPU 或 Memory > 70% 時將實例增加 1,最多 3 個實例) ,我實現了一個命名信號量,以防止多個實例同時運行。
這是托管后台服務的代碼。 我對其進行了一些簡化以顯示要點。
public class MyBackgroundService : BackgroundService
{
private Timer _timer;
private readonly ILogger<MyBackgroundService> _logger;
public MyBackgroundService(ILogger<MyBackgroundService> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
TimeSpan timeTillNextRun = CalculateTimeTillNextRun();
_timer = new Timer(DoWork, null, timeTillNextRun, new TimeSpan(1, 0, 0, 0));
}
private async void DoWork(object state)
{
try
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
await RunAsync();
}
finally
{
TimeSpan timeTillNextRun = CalculateTimeTillNextRun();
_timer.Change(timeTillNextRun, new TimeSpan(1, 0, 0, 0));
}
}
private async Task RunAsync()
{
using (Semaphore semaphore = new Semaphore(1, 1, "MyBackgroundService"))
{
if (!semaphore.WaitOne(1))
{
return;
}
try
{
_logger.LogInformation(null, "Started.");
// Do stuff
}
finally
{
semaphore.Release();
}
}
}
}
所以我有一個定時器,每天凌晨 2 點觸發。 當計時器觸發時,我暫停它,然后調用 RunAsync()。 在 RunAsunc() 中,我設置了一個命名的(系統)信號量。 我只等待 1 毫秒,因為如果信號量正在使用中,我什至不想等待它完成,因為這個后台服務應該每天只運行一次。
但是,當我檢查日志時,我看到它最多同時運行 6 次(好吧,在大約 3 秒內),每個服務運行兩次。
id, machine_name, status, time_stamp
'9577', 'RD2818786D33F4', 'Started.', '2021-08-16 02:00:06'
'9578', 'RD2818786D33F4', 'Started.', '2021-08-16 02:00:08'
'9579', 'RD2818786D0367', 'Started.', '2021-08-16 02:00:08'
'9580', 'RD2818786D1D19', 'Started.', '2021-08-16 02:00:09'
'9581', 'RD2818786D0367', 'Started.', '2021-08-16 02:00:09'
'9582', 'RD2818786D1D19', 'Started.', '2021-08-16 02:00:10'
正如您在上面看到的,它首先在 01:00:06 運行,然后 2 秒后在同一台機器上再次運行,然后立即在另一台機器上再次運行,然后一秒后又運行兩次,最后一秒又運行一次。
現在,查看“machine_name”列,應用服務的每個實例似乎都在不同的 VM 上運行。 我想,因為所有實例都在同一個服務計划中,所以它應該是同一個虛擬機,但我想我錯了。 所以,我想這就是信號量不工作的原因——它不能在不同的機器上工作。 奇怪的是它似乎也不在同一台機器上工作。 正如您在上面的日志中看到的,RunAsync() 在每個實例上運行了兩次。 現在它並不總是那樣。 例如,這是前一天的日志:
id, machine_name, status, time_stamp
'9569', 'RD2818786D2D5E', 'Started.', '2021-08-15 02:00:05'
'9570', 'RD2818786D2D5E', 'Started.', '2021-08-15 02:00:06'
在這里它只運行了兩次,一次。 同樣,它應該只運行一次——尤其是在同一台機器上。
我使用信號量錯了嗎? 我知道它可能無法跨 VM 使用,但即使在同一台 VM 上似乎也無法使用。
任何建議將不勝感激。 謝謝。
Ps 我知道我最好從 API 中刪除此托管服務並將其粘貼在 Azure Function 或 Azure WebJob 中。 事實上,我會盡快這樣做。 但我仍然很想知道為什么我的信號量不工作。
信號量似乎每次都在創建一個新的信號量。 我不知道為什么。 這發生在不同的進程上,甚至發生在單個進程上。 按照 Steeeve 的建議,我在信號量名稱中添加了“Global//”前綴,但沒有任何區別。 我什至在信號量構造函數中記錄了第四個參數(布爾參數)的值,再次按照 Steeeve 的建議,看看它是否真的每次都在創建一個新的信號量,它真的是。 我嘗試了多種方法,甚至從 Using() 塊中刪除了信號量(因為我認為這可能以不應該的方式破壞了信號量),但沒有任何區別。
最終我像最初一樣回到了 SemaphoreSlim。 這並沒有給我創建命名/系統信號量的選項,就像 Semaphore 所做的那樣,但至少它適用於單個進程。
看起來 Semaphore 根本無法在 Azure App Service 上托管的應用程序上運行,至少有一個像我的一樣設置為 Auto Scale Out。 我可以理解這一點,因為看起來 Azure 在擴展時為應用程序的每個實例創建了一個新的 VM(至少有時 - 我不能保證總是這樣)但奇怪的是它似乎沒有甚至在同一個虛擬機上工作。 根據我的理解,命名/系統信號量在操作系統級別工作——即它應該在機器內跨進程工作。
謝謝大家的幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.