![](/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.