簡體   English   中英

命名信號量在 Azure App Service 上托管的 ASP.Net Core 5 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.

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