1

I am writing a web API that runs only on a local machine, deployed as a windows service. After implementing some tracing, I noticed that the the initial requests to the API are exponentially slower. I've manage to reproduce this observation even in barebone, new web API projects.

Here is a sample of the trace results. The first, slow request was 15.18ms while the second and faster one was 1.04ms

I've read and understood that this is called a "Cold Start" issue with .NET. But nonetheless, how would I eliminate, mitigate or attempt to get around this issue? Practically, I would like my first realistic request to be as fast as the 1.04ms.

Again, this behavior is reproducible in a clean and new project but here is the code where the sample was generated from:

Controller:

using Microsoft.AspNetCore.Mvc;

namespace Telemetry.Controllers;

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{

    [HttpPost]
    public void Post()
    {
        Console.WriteLine("Hello World");
    }

    [HttpGet]
    public Boolean Get() => true;

}

Program.cs

using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddOpenTelemetry().WithTracing(builder =>
{
    builder
        .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Test Distributed Tracing"))
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddJaegerExporter(options =>
        {
        });
});

var app = builder.Build();

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

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
    <PackageReference Include="OpenTelemetry" Version="1.5.0-alpha.1" />
    <PackageReference Include="OpenTelemetry.Api" Version="1.5.0-alpha.1" />
    <PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.4.0" />
    <PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.4.0" />
    <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.4.0" />
    <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9.14" />
    <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9.14" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>

At least in my actual project, I've attempted to code and call some other GET and POST requests in the same controller in an attempt to "warm up" the application, but the difference of the trace results were miniscule and negligible.

Jean
  • 11
  • 1

1 Answers1

1

I have tried to find the settings about idle timeout in kestrel. But not found the best practice for this issue.

The default idle timeout value should be 120s. And I don't think it's not the best choice to host your webapp as windows service. Because there is an idle timeout limit in kestrel.

Workaround for you

  1. Create a new executable file and use the curl command in the file to access our webapp's url.

  2. Create a schedule task to run this .bat file per minutes.

Jason Pan
  • 15,263
  • 1
  • 14
  • 29