Fabricio Rodriguez
Fabricio Rodriguez

Reputation: 4249

Will SemaphoreSlim protect code from running twice simultaneously when Azure App Service scales out my Web API?

I have an ASP .Net Core 5 Web API running on Azure App Service. It contains a service which runs once a day, at around midnight. So i have a System.Threading.Tasks.Timer that runs once an hour. If it is between midnight and 1am, it will start the service. The service takes about a minute to complete, and is a loop that performs some database operations.

The other day, for some reason, it ran twice. So, while it was running, and before it finished, it ran a second instance simultaneously.

I couldn't figure out why it did this. And then I remembered that I recently set Azure App Service to scale out up to 3 instances when CPU or Memory utilization increases above 70%. Then I thought, could this be why it ran twice? While it was running, CPU or memory utilization went beyond 70%, so Azure App Service created a second instance of my Web API, which then fired the timer, which saw it was between midnight and 1AM, and so ran the service?

I thought, well, I guess it's possible. So, I thought the service needs protection against this. It should not allow two instances of it to run simultaneously (or really, in any given 24-hour period).

At first I thought about using Lock/Monitor. But my service is asynchronous, and uses the await keyword in a few places, so that wouldn't work with Lock/Monitor. SO I ended up using SemaphoreSlim. However, from my research, SemaphoreSlim only protects against interal threads executing the same code twice. It does not protect against external threads (the way, I believe, Semaphore or Mutex do).

So, to conlcude this rather lengthy post, I want to know if SemaphoreSlim will indeed protect my service from executing twice simultaneously, when Azure App Service increases the instance count of my Web API. Since it is essentially two separate instances of my API running (as far as I understand), would the second instance be seen as an external thread, and therefore not monitored by SemaphoreSlim?

Thanks

Upvotes: 0

Views: 1351

Answers (1)

Andreas Christiansen
Andreas Christiansen

Reputation: 946

SemaphoreSlim will not protect your procedure from running simultaneously across multiple instances of your service. SemaphoreSlim will indeed lock your code within the application's domain, but scaling out creates a whole new instance of your web application with its own process.

You can either fix this by creating a distributed lock, perhaps through a database or cache lookup, or you can redesign your application, to run the code, which may not run simultaneously, through a separate process. Consider if it can be implemented as an Azure function, or a webjob marked as a singleton.

Upvotes: 2

Related Questions