Skip to content

Commit e9a9d25

Browse files
author
rhamlett_microsoft
committed
Added request latency probing service to monitor thread pool starvation.
1 parent 653f6bd commit e9a9d25

File tree

8 files changed

+836
-1
lines changed

8 files changed

+836
-1
lines changed

src/PerfProblemSimulator/Controllers/HealthController.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,34 @@ public IActionResult GetStatus()
100100
.ToList()
101101
});
102102
}
103+
104+
/// <summary>
105+
/// Lightweight probe endpoint for latency measurement.
106+
/// </summary>
107+
/// <remarks>
108+
/// <para>
109+
/// <strong>Educational Note:</strong> This endpoint is designed for measuring
110+
/// request processing latency. It does minimal work - just returns a timestamp.
111+
/// During thread pool starvation, even this simple endpoint will show increased
112+
/// latency because the request must wait for a thread pool thread to process it.
113+
/// </para>
114+
/// <para>
115+
/// Compare the response time of this endpoint before and during thread pool
116+
/// starvation to see the dramatic impact on user-perceived performance.
117+
/// </para>
118+
/// </remarks>
119+
/// <response code="200">Returns probe timestamp for latency calculation.</response>
120+
[HttpGet("probe")]
121+
[ProducesResponseType(typeof(ProbeResponse), StatusCodes.Status200OK)]
122+
public IActionResult Probe()
123+
{
124+
return Ok(new ProbeResponse
125+
{
126+
ServerTimestamp = DateTimeOffset.UtcNow,
127+
ThreadPoolThreads = ThreadPool.ThreadCount,
128+
PendingWorkItems = ThreadPool.PendingWorkItemCount
129+
});
130+
}
103131
}
104132

105133
/// <summary>
@@ -159,3 +187,31 @@ public class ActiveSimulationSummary
159187
/// </summary>
160188
public int RunningDurationSeconds { get; init; }
161189
}
190+
191+
/// <summary>
192+
/// Response from the latency probe endpoint.
193+
/// </summary>
194+
/// <remarks>
195+
/// <para>
196+
/// <strong>Educational Note:</strong> This response includes thread pool information
197+
/// to help correlate latency with thread pool state. During starvation, you'll see
198+
/// high pending work items and latency increasing together.
199+
/// </para>
200+
/// </remarks>
201+
public class ProbeResponse
202+
{
203+
/// <summary>
204+
/// Server timestamp when the probe was processed.
205+
/// </summary>
206+
public DateTimeOffset ServerTimestamp { get; init; }
207+
208+
/// <summary>
209+
/// Current number of thread pool threads.
210+
/// </summary>
211+
public int ThreadPoolThreads { get; init; }
212+
213+
/// <summary>
214+
/// Number of work items waiting in the thread pool queue.
215+
/// </summary>
216+
public long PendingWorkItems { get; init; }
217+
}

src/PerfProblemSimulator/Hubs/IMetricsClient.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using PerfProblemSimulator.Models;
2+
using PerfProblemSimulator.Services;
23

34
namespace PerfProblemSimulator.Hubs;
45

@@ -41,4 +42,17 @@ public interface IMetricsClient
4142
/// <param name="simulationType">Type of simulation that completed.</param>
4243
/// <param name="simulationId">ID of the simulation.</param>
4344
Task SimulationCompleted(string simulationType, Guid simulationId);
45+
46+
/// <summary>
47+
/// Receives a latency measurement from the server-side probe.
48+
/// </summary>
49+
/// <param name="measurement">The latency measurement data.</param>
50+
/// <remarks>
51+
/// <para>
52+
/// <strong>Educational Note:</strong> This measurement shows real request processing
53+
/// latency. Compare baseline latency (~5-20ms) with latency during thread pool
54+
/// starvation (can exceed 30 seconds!) to see the impact of blocking threads.
55+
/// </para>
56+
/// </remarks>
57+
Task ReceiveLatency(LatencyMeasurement measurement);
4458
}

src/PerfProblemSimulator/Program.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@
114114
// This bridges the MetricsCollector (which fires events) with SignalR (which pushes to clients).
115115
builder.Services.AddHostedService<MetricsBroadcastService>();
116116

117+
// LatencyProbeService - Hosted service that measures request latency on a dedicated thread
118+
// Educational Note: This service demonstrates how thread pool starvation affects request
119+
// processing time. It runs on a dedicated thread (not the thread pool) to ensure it can
120+
// always measure latency, even during severe starvation conditions.
121+
builder.Services.AddHttpClient("LatencyProbe");
122+
builder.Services.AddHostedService<LatencyProbeService>();
123+
117124
// -----------------------------------------------------------------------------
118125
// CORS Configuration
119126
// -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)