简体   繁体   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

I have an ASP.Net Core 5 Web API running on Azure App Service.我有一个运行在 Azure App Service 上的 ASP.Net Core 5 Web API。 Once a day, it runs a Hosted BackgroundService.它每天运行一次 Hosted BackgroundService。 Because I only want this service to run once a day (at 2 AM), and because my App Service has auto scale-out turned on (increase instance by 1 when CPU or Memory > 70%, up to a maximum of 3 instances), I implemented a named semaphore, to prevent more than one instance running simultaneously.因为我只希望此服务每天运行一次(凌晨 2 点),并且因为我的 App Service 已打开自动扩展(当 CPU 或 Memory > 70% 时将实例增加 1,最多 3 个实例) ,我实现了一个命名信号量,以防止多个实例同时运行。

Here is the code for the Hosted BackgroundService.这是托管后台服务的代码。 I have simplified it a bit to show the essentials.我对其进行了一些简化以显示要点。

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();
            }
        }
    }
}

So I have a timer which will fire at 2AM each day.所以我有一个定时器,每天凌晨 2 点触发。 When the timer fires, I pause it, and I call RunAsync().当计时器触发时,我暂停它,然后调用 RunAsync()。 In RunAsunc(), I set a named (system) semaphore.在 RunAsunc() 中,我设置了一个命名的(系统)信号量。 I only wait 1 millisecond because, if the semaphore is in use, I don't even want to wait for it to finish because this background service should run once a day only.我只等待 1 毫秒,因为如果信号量正在使用中,我什至不想等待它完成,因为这个后台服务应该每天只运行一次。

However, when I check the logs, I see it runs up to 6 times simultaneously (well, within about 3 seconds), twice on each service.但是,当我检查日志时,我看到它最多同时运行 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'

As you can see above, it first ran at 01:00:06, then again 2 seconds later on the same machine, then instantly again on a different machine, then twice more a second later, and finally once more a second after that.正如您在上面看到的,它首先在 01:00:06 运行,然后 2 秒后在同一台机器上再次运行,然后立即在另一台机器上再次运行,然后一秒后又运行两次,最后一秒又运行一次。

Now, looking at the "machine_name" column, it would appear that each instance of the App Service is running on a different VM.现在,查看“machine_name”列,应用服务的每个实例似乎都在不同的 VM 上运行。 I thought, since all instances are on the same service plan, that it would be the same VM, but I guess I was wrong.我想,因为所有实例都在同一个服务计划中,所以它应该是同一个虚拟机,但我想我错了。 So, I guess that's why the semaphore isn't working - it does not work across different machines.所以,我想这就是信号量不工作的原因——它不能在不同的机器上工作。 The strange thing is that it appears to not be working within the same machine either.奇怪的是它似乎也不在同一台机器上工作。 As you can see int he log above, RunAsync() ran on each instance twice.正如您在上面的日志中看到的,RunAsync() 在每个实例上运行了两次。 Now it's not always exactly like that.现在它并不总是那样。 For example, this is the log for the previous day:例如,这是前一天的日志:

id, machine_name, status, time_stamp
'9569', 'RD2818786D2D5E', 'Started.', '2021-08-15 02:00:05'
'9570', 'RD2818786D2D5E', 'Started.', '2021-08-15 02:00:06'

Here it only ran twice, on one instance.在这里它只运行了两次,一次。 Again, it should only have run once - especially seeing as it was on the same machine.同样,它应该只运行一次——尤其是在同一台机器上。

Am I using Semaphore wrong?我使用信号量错了吗? I understand that it probably won't work across VM's, but it doesn't seem to be working even on the same VM.我知道它可能无法跨 VM 使用,但即使在同一台 VM 上似乎也无法使用。

Any advice would be greatly appreciated.任何建议将不胜感激。 Thanks.谢谢。

Ps I understand that it would be better for me to remove this hosted service from the API and stick it in an Azure Function or Azure WebJob. Ps 我知道我最好从 API 中删除此托管服务并将其粘贴在 Azure Function 或 Azure WebJob 中。 And indeed, I will do that ASAP.事实上,我会尽快这样做。 But I'm still curious to know why my Semaphore is not working.但我仍然很想知道为什么我的信号量不工作。

Semaphore appears to be creating a new semaphore every single time.信号量似乎每次都在创建一个新的信号量。 I don't know why.我不知道为什么。 This is happening both on different processes and even on single processes.这发生在不同的进程上,甚至发生在单个进程上。 I added the "Global//" prefix to the Semaphore name, as suggested by Steeeve, but it made no difference.按照 Steeeve 的建议,我在信号量名称中添加了“Global//”前缀,但没有任何区别。 I even logged the value of the 4th parameter (boolean param) in the Semaphore constructor, again as suggested by Steeeve, to see if it was actually creating a new semaphore each time, and it truly is.我什至在信号量构造函数中记录了第四个参数(布尔参数)的值,再次按照 Steeeve 的建议,看看它是否真的每次都在创建一个新的信号量,它真的是。 I tried multiple things, even removing the Semaphore from the Using() block (because I thought maybe that was destroying the Semaphore in a way it shouldn't) but it made no difference.我尝试了多种方法,甚至从 Using() 块中删除了信号量(因为我认为这可能以不应该的方式破坏了信号量),但没有任何区别。

Eventually I moved back to a SemaphoreSlim like I had initially.最终我像最初一样回到了 SemaphoreSlim。 This doesn't give me the option of creating a named/system semaphore, like Semaphore did, but at least it works on single processes.这并没有给我创建命名/系统信号量的选项,就像 Semaphore 所做的那样,但至少它适用于单个进程。

It appears Semaphore simply doesn't work on an app hosted on Azure App Service, at least one that is set to Auto Scale Out like mine is.看起来 Semaphore 根本无法在 Azure App Service 上托管的应用程序上运行,至少有一个像我的一样设置为 Auto Scale Out。 I can understand this, as it appears that Azure creates a new VM for each instance of the app when it scales out (at least sometimes - I can't guarantee this is always the case) but the strange thing is that it appears not to be working even on the same VM.我可以理解这一点,因为看起来 Azure 在扩展时为应用程序的每个实例创建了一个新的 VM(至少有时 - 我不能保证总是这样)但奇怪的是它似乎没有甚至在同一个虚拟机上工作。 From my understanding, a named/system semaphore works at an OS level - ie it's supposed to work across processes within a machine.根据我的理解,命名/系统信号量在操作系统级别工作——即它应该在机器内跨进程工作。

Thanks, everyone for your help.谢谢大家的帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何读取Service Fabric Azure App Configuration ASP.NET Core Stateless Web API? - How to read the Azure App Configuration in Service Fabric ASP.NET Core Stateless Web API? Azure 部署ASP.Net后服务应用不可用 Web 核心应用 - Azure Service App Becomes Unavailable After Deploying ASP.Net Web Core App 从ASP.NET Core访问Azure App Service ConnectionString - Access Azure App Service ConnectionString from ASP.NET Core azure 应用服务中的谷歌应用凭证(as.net core web api) - Google application credentials in azure app service (aspnet core web api) ASP.net 核心 docker https on Azure 应用服务容器 - ASP.net core docker https on Azure App Service Containers 信号 R 将数据发送到 UI 的功能在 Angular/ASP.Net Core 中不起作用 web API 3.1 应用程序与 Azure 活动目录身份验证 - Signal R functionality to send data to UI not working in Angular/ASP.Net Core web API 3.1 application with Azure Active directory authentication 如何手动将 ASP.NET 核心应用程序的部署版本复制到 Azure web 应用程序(应用服务) - How can I manually copy a deployment build of ASP.NET Core application to Azure web application (App Service) 如何配置.NET 7 Web API部署到Azure应用服务 - How to configure .NET 7 Web API for deploying to Azure App service Azure Web 应用程序与 Linux 并将 GLIBC 2.29 与我的 ASP.NET Core 7 应用程序捆绑在一起 - Azure Web App with Linux and bundling GLIBC 2.29 with my ASP.NET Core 7 App 带有数据库的 ASP.Net Core Web 应用程序使用 Visual Studio 2019 发布到 Azure - 实体框架迁移错误 - ASP.Net Core Web App with Database publish to Azure with Visual Studio 2019 - Error with Entity Framework Migrations
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM