user246392
user246392

Reputation: 3019

Can the same thread run multiple functions simultaneously in Azure Functions?

All of my functions are static methods. They look like the below sample with a static class and a static method to process the function.

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        await Task.CompletedTask;

        return new OkObjectResult("message");
    }
}

For every function call, I'm setting Thread.CurrentThread.CurrentUICulture based on a request parameter. This helps me return localized text based on the culture of the user device. (I'm using .resx files)

My question is, in a highly concurrent environment, is it possible for a user to receive text localized to another culture? If the same thread processes multiple functions simultaneously, then I believe this issue is possible. I'm trying to understand if Azure Functions allocates one function call per thread or not.

Upvotes: 4

Views: 2168

Answers (1)

Lolop
Lolop

Reputation: 574

I'm trying to understand if Azure Functions allocates one function call per thread or not

The important question that I think you want answered is 'Is the same thread allocated for the whole lifetime of a single function call'. To which the answer is: It depends, which in your case I think is as good as a no.

In a non async world, applications flow from top to bottom so there is no chance for the thread to change. So if you never use the await keyword, you can be pretty sure your function is going to run on a single thread.

Just using the await keyword doesn't guarantee it'll change threads though. If the async operation has already completed when you call await, it will continue syncronously. An example of this would be in your example code where you do

await Task.CompletedTask;

Because Task.CompleteTask is already complete, you won't get any thread swapping there.

On top of this, calling await on a proper asyncronous call doesn't guarantee that the thread will change when it completes. When you call await on a proper async call, it'll release the thread back into the thread pool so it can do other things. When the async call returns, two different things can happen.

If there is a SyncronizationContext (There isn't one by default in Azure Functions), it will use that to continue the function on the same thread.

If there isn't one though, a random thread from the thread pool is used to continue the request. It's possible that it could pick the same thread that started it, but that's unlikely.

So basically in your situation, if you are actually doing async calls in your azure function you cannot rely on the same thread being used throughout the whole of a function call.

What should you do

You said you are using Resx files for localization, while I've never had to do this it seems like it's a good way of doing it. I assume you were basing your solution off something like this post.

While you could manage the threads like this, I think it could potentially lead to unexpected issues if you have multiple Azure Functions inside your Azure Function App. Instead I'd recommend going off Microsoft's recommended localization practices and using the ResourceManager to get the localized resources without changing the thread culture.

*Extra note about Azure Functions

In the comments of the post Rex says Azure Functions run independently from one another. They each run in their own little sandbox. This is true, but I think potentially the terminology/naming of things is confusing.

In Azure, you create a Azure Function App, which contains Azure Function's. I can't find an exact reference for how things work, but to me it seems like the Azure Function App is the part that scales, not the individual Azure Function's. This makes sense because all your individual Functions are part of the same assembly.

So all Azure Function's inside a single Function App share the same resources, including the thread pool. This is why I think changing the thread culture could cause unexpected issues in other Functions.

If I'm wrong on this though, let me know. I was basing what logically makes sense to me and this blog post. It says 'Functions loaded into memory' when discussing what happens during a cold start. I assume if each Function was its own sandbox, they would specify that somewhere.

Upvotes: 4

Related Questions