Create A Multi User Experience For Single Threaded Applications Using Azure Container Apps

Create A Multi User Experience For Single Threaded Applications Using Azure Container Apps

How to make a single-threaded app multi-threaded? This is the scenario I faced very recently. These were legacy web app(s) written to be single-threaded; in this context single-threaded means can only serve one request at a time. I know this goes against everything that a web app should be, but it what it is.

So if we have a single threaded web app (legacy) now all of a sudden we have a requirement to support multiple users at the same time. What are our options:

  1. Re-architect the app to be multi threaded
  2. Find a way to simulate multi threaded behavior

Both are great options, but in this scenario option 1 was out, due to the cost involved in re-writing this app to support multi threading. So that leaves us with option 2; how can we at a cloud infra level easily simulate multi threaded behavior. Turns out if we containerize the app (in this case it was easy enough to do) we orchestrate the app such that for each http request is routed to a new container (ie: every new http request should spin up a new container and request send to it)

Options For Running Containers

So when it comes to running a container in Azure our main options are below

Here we need to orchestrate containers, ie: at a minimum for every new http request spin a new one), which means we only have two viable options, Azure Kubernetes Service (AKS) or Azure Container Apps (ACA). Both are valid options, each with their own pros/cons, with AKS its a lot more complex we will need to :

So in short, as flexible as AKS is its not as easy as something like ACA which is a fully managed version of AKS that abstracts all the complexities of Kubernetes. So for this scenario to prove we can simulate multi threaded experience lets go ahead with ACA.

Sample Single Threaded Program

For this demo below is a simple C# DotNet app that simulates a single threaded behavior, essentially its doing a lock on a static variable which blocks the whole process for 6 seconds. So when we visit the /test endpoint we lock the whole app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class Program
{
private static readonly object LockObject = new();

public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthorization();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddApplicationInsightsTelemetry();


var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseAuthorization();

app.MapGet("/test", (HttpContext httpContext) =>
{
if (Monitor.TryEnter(LockObject, new TimeSpan(0, 0, 6)))
{
try
{
Thread.Sleep(5000);
}
finally
{
Monitor.Exit(LockObject);
}
}

return ("Hello From Container: " + System.Environment.MachineName);
});

app.Run();
}
}

Azure Container Apps

For this demo the easiest way to create the Azure Container Apps environment is through Visual Studio, you right click, publish and go through the menus and in the end VS will create a Container Apps Environment and deploy the code as a container to ACA.

Once this is all done, we should have a resource group like below

Azure Container Apps Scaling

Next we go to the container app (the single threaded api we just deployed) and set up a simple http scale rule that will spin up a new container for every 1 http incoming request. In the example below we set min-replicas to 0 and max to 30 this means that when there is no traffic it will scale down to 0 and at peak it will hit 30.

Testing

Now go to the url of the container app and hit it simultaneously in browser tabs, when I opened it in multiple browser tabs out of 10 tabs about 7 were served by unique containers and based on the test code above I see it being served by different container ids

1
2
3
4
Tab1: Hello From Container: single-threaded-api-app-20220731--ps4yjjp-66f4885b65-w5s6h
Tab2: Hello From Container: single-threaded-api-app-20220731--ps4yjjp-66f4885b65-gs8qf
Tab3: Hello From Container: single-threaded-api-app-20220731--ps4yjjp-66f4885b65-x7grl
etc

So its not 100% every single request goes to a brand new container, but very easily and very quickly with out too much complexity we were able to achieve a 70 - 90% of requests being served with new containers, so in essence we found a quick way to simulate a pseudo - multi threaded experience for our legacy single threaded app with out too much effort.

Create A Multi User Experience For Single Threaded Applications Using Azure Container Apps

https://clouddev.blog/Azure/Container-Apps/create-a-multi-user-experience-for-single-threaded-applications-using-azure-container-apps/

Author

Ricky Gummadi

Posted on

2022-09-12

Updated on

2022-09-16

Licensed under

Comments