.NET › Diagnostics & Performance

How would you diagnose a thread pool starvation issue in a production ASP.NET Core application?

Advanced

Answer

Thread pool starvation occurs when all available thread pool threads are busy (often due to blocking synchronous calls on async code, like .Result or .Wait()), causing queued work items to wait, visible via dotnet-counters' threadpool-queue-length metric climbing while threadpool-thread-count stays flat or grows slowly (since the pool only adds new threads gradually) -- diagnosed by capturing a trace or dump during the symptom window and looking for many threads blocked in synchronous wait states, then fixed by replacing blocking calls with proper async/await throughout the call chain.
// Common cause of starvation: blocking on async code
public IActionResult GetData() {
    var result = _service.GetDataAsync().Result;  // BLOCKS a thread pool thread
    return Ok(result);
}

// Fix: async all the way through
public async Task<IActionResult> GetData() {
    var result = await _service.GetDataAsync();
    return Ok(result);
}
Real-world example A production API experiencing periodic request timeouts under load is diagnosed via dotnet-counters showing threadpool-queue-length spiking to hundreds; a code audit finds a legacy synchronous .Result call blocking threads, and converting it to proper async/await resolves the starvation.

Common follow-ups: Why does the thread pool grow new threads slowly rather than immediately?;How does MinThreads configuration provide a (usually inadvisable) quick mitigation?