Skip to content

Commit c02e045

Browse files
author
rhamlett_microsoft
committed
Removed timeout references. Request do not really timeout at 30s.
1 parent 34f6928 commit c02e045

File tree

4 files changed

+97
-10
lines changed

4 files changed

+97
-10
lines changed

src/PerfProblemSimulator/Controllers/HealthController.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Microsoft.AspNetCore.Http.Timeouts;
22
using Microsoft.AspNetCore.Mvc;
33
using PerfProblemSimulator.Services;
4+
using System.Reflection;
45

56
namespace PerfProblemSimulator.Controllers;
67

@@ -130,6 +131,34 @@ public IActionResult Probe()
130131
PendingWorkItems = ThreadPool.PendingWorkItemCount
131132
});
132133
}
134+
135+
/// <summary>
136+
/// Returns build information including the build timestamp.
137+
/// </summary>
138+
/// <remarks>
139+
/// <para>
140+
/// <strong>Educational Note:</strong> The build timestamp is embedded in the assembly
141+
/// during compilation via MSBuild. This provides an accurate record of when the
142+
/// deployed code was built, useful for debugging and deployment verification.
143+
/// </para>
144+
/// </remarks>
145+
/// <response code="200">Returns build information.</response>
146+
[HttpGet("build")]
147+
[ProducesResponseType(typeof(BuildInfoResponse), StatusCodes.Status200OK)]
148+
public IActionResult GetBuildInfo()
149+
{
150+
var assembly = Assembly.GetExecutingAssembly();
151+
var buildTimestamp = assembly
152+
.GetCustomAttributes<AssemblyMetadataAttribute>()
153+
.FirstOrDefault(a => a.Key == "BuildTimestamp")?.Value;
154+
155+
return Ok(new BuildInfoResponse
156+
{
157+
BuildTimestamp = buildTimestamp,
158+
AssemblyVersion = assembly.GetName().Version?.ToString(),
159+
EnvironmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"
160+
});
161+
}
133162
}
134163

135164
/// <summary>
@@ -217,3 +246,24 @@ public class ProbeResponse
217246
/// </summary>
218247
public long PendingWorkItems { get; init; }
219248
}
249+
250+
/// <summary>
251+
/// Response containing build information.
252+
/// </summary>
253+
public class BuildInfoResponse
254+
{
255+
/// <summary>
256+
/// UTC timestamp when the application was built (ISO 8601 format).
257+
/// </summary>
258+
public string? BuildTimestamp { get; init; }
259+
260+
/// <summary>
261+
/// Assembly version of the application.
262+
/// </summary>
263+
public string? AssemblyVersion { get; init; }
264+
265+
/// <summary>
266+
/// Current environment name (Development, Staging, Production).
267+
/// </summary>
268+
public string? EnvironmentName { get; init; }
269+
}

src/PerfProblemSimulator/PerfProblemSimulator.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,17 @@
2222
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.0" />
2323
</ItemGroup>
2424

25+
<!-- Generate build timestamp as assembly metadata -->
26+
<Target Name="SetBuildTimestamp" BeforeTargets="CoreCompile">
27+
<PropertyGroup>
28+
<BuildTimestamp>$([System.DateTime]::UtcNow.ToString("o"))</BuildTimestamp>
29+
</PropertyGroup>
30+
<ItemGroup>
31+
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
32+
<_Parameter1>BuildTimestamp</_Parameter1>
33+
<_Parameter2>$(BuildTimestamp)</_Parameter2>
34+
</AssemblyAttribute>
35+
</ItemGroup>
36+
</Target>
37+
2538
</Project>

src/PerfProblemSimulator/wwwroot/index.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ <h3>🧵 Thread Pool Starvation</h3>
8787
<div class="control-group slowrequest-group">
8888
<h3>🐌 Slow Requests</h3>
8989
<p>Generates requests using sync-over-async patterns. Ideal for CLR Profiler diagnosis.</p>
90-
<p class="timeout-warning">⚠️ Note: Requests exceeding 30 seconds total time (queue + execution) will timeout with HTTP 502.3</p>
90+
<p class="timeout-warning">⚠️ Note: Requests exceeding 30 seconds total time (queue + execution) are flagged as critical</p>
9191
<div class="control-inputs">
9292
<label>Request Execution Time (s) <span style="cursor: help; color: var(--color-primary);" title="This value controls only the processing time. Total Duration = Queue Time + Execution Time."></span>:
9393
<input type="number" id="slowRequestDuration" value="25" min="5" max="60">
@@ -220,7 +220,7 @@ <h2>⏱️ Request Latency Monitor</h2>
220220
<span class="latency-value" id="latencyMax">--</span>
221221
</div>
222222
<div class="latency-stat">
223-
<span class="latency-label">Timeouts</span>
223+
<span class="latency-label">Critical (&gt;30s)</span>
224224
<span class="latency-value" id="latencyTimeouts">0</span>
225225
</div>
226226
</div>
@@ -230,7 +230,7 @@ <h2>⏱️ Request Latency Monitor</h2>
230230
<span class="threshold-item good">● Good (&lt;150ms)</span>
231231
<span class="threshold-item warning">● Degraded (150ms-1s)</span>
232232
<span class="threshold-item danger">● Critical (&gt;1s)</span>
233-
<span class="threshold-item timeout">Timeout (30s)</span>
233+
<span class="threshold-item timeout">Critical (&gt;30s)</span>
234234
</div>
235235

236236
<div class="chart-container latency-chart-container" style="position: relative;">
@@ -262,7 +262,8 @@ <h2>📜 Event Log</h2>
262262

263263
<footer class="footer">
264264
<p>Performance Problem Simulator - Educational Tool for Azure App Service Diagnostics</p>
265-
<p>Last Update: <span id="lastUpdate">--</span></p>
265+
<p>Created by <a href="https://speckit.org/" target="_blank">SpecKit</a> in collaboration with <a href="mailto:rhamlett@microsoft.com">Richard Hamlett</a></p>
266+
<p>Build: <span id="buildTime">--</span></p>
266267
</footer>
267268

268269
<script src="js/dashboard.js?v=2"></script>

src/PerfProblemSimulator/wwwroot/js/dashboard.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ function initializeCharts() {
447447
const isTimeout = state.latencyHistory.isTimeout[index];
448448
const isError = state.latencyHistory.isError[index];
449449

450-
if (isTimeout) return `Timeout: ${latency}ms (30s)`;
450+
if (isTimeout) return `Critical (>30s): ${latency}ms`;
451451
if (isError) return `Error: ${latency}ms`;
452452
return `Latency: ${latency}ms`;
453453
}
@@ -488,7 +488,7 @@ function handleLatencyUpdate(measurement) {
488488
if (measurement.isError) {
489489
logEvent('error', `⚠️ Health Probe Error: ${measurement.errorMessage || 'Unknown error'} (${formatLatency(measurement.latencyMs)})`);
490490
} else if (measurement.isTimeout) {
491-
logEvent('error', `⚠️ Health Probe Timeout: >${formatLatency(measurement.latencyMs)}`);
491+
logEvent('warning', `⚠️ Health Probe Critical (>30s): ${formatLatency(measurement.latencyMs)}`);
492492
} else if (measurement.latencyMs > 5000) {
493493
// Log extremely high latency (starvation)
494494
logEvent('warning', `⚠️ High Latency Probe: ${formatLatency(measurement.latencyMs)}`);
@@ -559,10 +559,9 @@ function handleSlowRequestLatency(data) {
559559
}
560560
logEvent('error', msg);
561561
} else if (isTimeout) {
562-
// Request completed but exceeded the 30s timeout threshold
563-
// In IIS with requestTimeout="00:00:30", this would have been terminated with HTTP 502.3
564-
let msg = `⏱️ Slow request #${data.requestNumber} TIMEOUT: ${durationSec}s exceeded 30s threshold (${scenario}) [Queue Time: ${queueSec}s]`;
565-
logEvent('error', msg);
562+
// Request completed but exceeded the 30s critical threshold
563+
let msg = `🐌 Slow request #${data.requestNumber} completed: ${durationSec}s (${scenario}) [Queue Time: ${queueSec}s] ⚠️ CRITICAL (>30s)`;
564+
logEvent('warning', msg);
566565
} else {
567566
let msg = `🐌 Slow request #${data.requestNumber} completed: ${durationSec}s (${scenario}) [Queue Time: ${queueSec}s]`;
568567
logEvent('warning', msg);
@@ -1204,13 +1203,37 @@ async function fetchAzureSku() {
12041203
}
12051204
}
12061205

1206+
/**
1207+
* Fetches and displays the build timestamp.
1208+
*/
1209+
async function fetchBuildInfo() {
1210+
try {
1211+
const response = await fetch(`${CONFIG.apiBaseUrl}/health/build`);
1212+
if (response.ok) {
1213+
const data = await response.json();
1214+
const buildTimeElement = document.getElementById('buildTime');
1215+
if (buildTimeElement && data.buildTimestamp) {
1216+
// Parse ISO 8601 timestamp and format as date + time
1217+
const buildDate = new Date(data.buildTimestamp);
1218+
const formatted = buildDate.toISOString().replace('T', ' ').substring(0, 19) + ' UTC';
1219+
buildTimeElement.textContent = formatted;
1220+
}
1221+
}
1222+
} catch (error) {
1223+
console.error('Failed to fetch build info', error);
1224+
}
1225+
}
1226+
12071227
document.addEventListener('DOMContentLoaded', () => {
12081228
// Initialize charts first
12091229
initializeCharts();
12101230

12111231
// Fetch SKU info
12121232
fetchAzureSku();
12131233

1234+
// Fetch build info
1235+
fetchBuildInfo();
1236+
12141237
// Start SignalR connection
12151238
initializeSignalR();
12161239

0 commit comments

Comments
 (0)