Skip to content

Commit f84dd71

Browse files
author
rhamlett_microsoft
committed
Added app crash simulator
1 parent 67fb0ec commit f84dd71

File tree

10 files changed

+721
-1
lines changed

10 files changed

+721
-1
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using PerfProblemSimulator.Models;
3+
using PerfProblemSimulator.Services;
4+
5+
namespace PerfProblemSimulator.Controllers;
6+
7+
/// <summary>
8+
/// Controller for triggering intentional application crashes.
9+
/// </summary>
10+
/// <remarks>
11+
/// <para>
12+
/// <strong>Educational Note:</strong> This controller provides endpoints to intentionally
13+
/// crash the application in various ways. This is useful for learning:
14+
/// </para>
15+
/// <list type="bullet">
16+
/// <item>How to configure Azure App Service crash monitoring</item>
17+
/// <item>How to collect and analyze crash dumps</item>
18+
/// <item>Understanding different types of fatal errors in .NET</item>
19+
/// <item>Practicing crash dump analysis with WinDbg or Visual Studio</item>
20+
/// </list>
21+
/// <para>
22+
/// <strong>WARNING:</strong> These endpoints will terminate the application!
23+
/// Azure App Service will automatically restart the application after a crash.
24+
/// </para>
25+
/// </remarks>
26+
[ApiController]
27+
[Route("api/[controller]")]
28+
[Produces("application/json")]
29+
[Tags("Crash Simulation")]
30+
public class CrashController : ControllerBase
31+
{
32+
private readonly ICrashService _crashService;
33+
private readonly ILogger<CrashController> _logger;
34+
35+
public CrashController(ICrashService crashService, ILogger<CrashController> logger)
36+
{
37+
_crashService = crashService ?? throw new ArgumentNullException(nameof(crashService));
38+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
39+
}
40+
41+
/// <summary>
42+
/// Triggers an application crash of the specified type.
43+
/// </summary>
44+
/// <param name="request">The crash configuration.</param>
45+
/// <returns>Confirmation that the crash has been scheduled (response sent before crash occurs).</returns>
46+
/// <remarks>
47+
/// <para>
48+
/// <strong>WARNING:</strong> This endpoint will TERMINATE the application!
49+
/// </para>
50+
/// <para>
51+
/// The response is sent before the crash occurs, so you will receive a 200 OK
52+
/// indicating the crash has been scheduled. The actual crash happens shortly after.
53+
/// </para>
54+
/// <para>
55+
/// <strong>Azure Crash Monitoring Setup:</strong>
56+
/// </para>
57+
/// <list type="number">
58+
/// <item>In Azure Portal, go to your App Service</item>
59+
/// <item>Navigate to "Diagnose and solve problems"</item>
60+
/// <item>Search for "Crash Monitoring"</item>
61+
/// <item>Enable crash monitoring with "Collect Memory Dump"</item>
62+
/// <item>Call this endpoint to trigger a crash</item>
63+
/// <item>Download the crash dump from the Azure portal</item>
64+
/// </list>
65+
/// </remarks>
66+
/// <response code="200">Crash has been scheduled</response>
67+
/// <response code="400">Invalid crash configuration</response>
68+
/// <response code="503">Problem endpoints are disabled</response>
69+
[HttpPost("trigger")]
70+
[ProducesResponseType(typeof(SimulationResult), StatusCodes.Status200OK)]
71+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
72+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status503ServiceUnavailable)]
73+
public IActionResult TriggerCrash([FromBody] CrashRequest? request)
74+
{
75+
request ??= new CrashRequest();
76+
77+
// Validate delay
78+
if (request.DelaySeconds < 0 || request.DelaySeconds > 60)
79+
{
80+
return BadRequest(new ErrorResponse
81+
{
82+
Error = "INVALID_DELAY",
83+
Message = "DelaySeconds must be between 0 and 60"
84+
});
85+
}
86+
87+
_logger.LogCritical(
88+
"🚨 CRASH REQUESTED: Type={CrashType}, Delay={DelaySeconds}s",
89+
request.CrashType, request.DelaySeconds);
90+
91+
// Trigger the crash
92+
_crashService.TriggerCrash(request.CrashType, request.DelaySeconds, request.Message);
93+
94+
var crashMessage = $"💥 {request.CrashType} crash scheduled! " +
95+
(request.DelaySeconds > 0
96+
? $"Crash will occur in {request.DelaySeconds} seconds."
97+
: "Crash will occur in ~100ms (after this response is sent).");
98+
99+
return Ok(new SimulationResult
100+
{
101+
SimulationId = Guid.NewGuid(),
102+
Type = SimulationType.Crash,
103+
Status = "Scheduled",
104+
Message = crashMessage,
105+
ActualParameters = new Dictionary<string, object>
106+
{
107+
["CrashType"] = request.CrashType.ToString(),
108+
["DelaySeconds"] = request.DelaySeconds
109+
}
110+
});
111+
}
112+
113+
/// <summary>
114+
/// Gets information about available crash types.
115+
/// </summary>
116+
/// <returns>A dictionary of crash types and their descriptions.</returns>
117+
/// <remarks>
118+
/// Use this endpoint to understand what each crash type does before triggering it.
119+
/// </remarks>
120+
/// <response code="200">List of crash types and descriptions</response>
121+
[HttpGet("types")]
122+
[ProducesResponseType(typeof(Dictionary<string, CrashTypeInfo>), StatusCodes.Status200OK)]
123+
public IActionResult GetCrashTypes()
124+
{
125+
var descriptions = _crashService.GetCrashTypeDescriptions();
126+
127+
var result = descriptions.ToDictionary(
128+
kvp => kvp.Key.ToString(),
129+
kvp => new CrashTypeInfo
130+
{
131+
Name = kvp.Key.ToString(),
132+
Value = (int)kvp.Key,
133+
Description = kvp.Value,
134+
RecommendedForAzure = kvp.Key == CrashType.FailFast || kvp.Key == CrashType.StackOverflow
135+
});
136+
137+
return Ok(result);
138+
}
139+
140+
/// <summary>
141+
/// Triggers a FailFast crash (most common for Azure crash monitoring).
142+
/// </summary>
143+
/// <param name="delaySeconds">Optional delay before crash (0-60 seconds).</param>
144+
/// <returns>Confirmation that the crash has been scheduled.</returns>
145+
/// <remarks>
146+
/// This is a convenience endpoint for the most commonly used crash type.
147+
/// Environment.FailFast is the recommended method for testing Azure crash monitoring.
148+
/// </remarks>
149+
/// <response code="200">Crash has been scheduled</response>
150+
/// <response code="503">Problem endpoints are disabled</response>
151+
[HttpPost("failfast")]
152+
[ProducesResponseType(typeof(SimulationResult), StatusCodes.Status200OK)]
153+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status503ServiceUnavailable)]
154+
public IActionResult TriggerFailFast([FromQuery] int delaySeconds = 0)
155+
{
156+
return TriggerCrash(new CrashRequest
157+
{
158+
CrashType = CrashType.FailFast,
159+
DelaySeconds = Math.Clamp(delaySeconds, 0, 60),
160+
Message = "FailFast triggered via /api/crash/failfast endpoint"
161+
});
162+
}
163+
164+
/// <summary>
165+
/// Triggers a StackOverflow crash.
166+
/// </summary>
167+
/// <param name="delaySeconds">Optional delay before crash (0-60 seconds).</param>
168+
/// <returns>Confirmation that the crash has been scheduled.</returns>
169+
/// <remarks>
170+
/// Creates interesting stack traces for analysis. The crash dump will show
171+
/// repeated calls to the same method, demonstrating infinite recursion.
172+
/// </remarks>
173+
/// <response code="200">Crash has been scheduled</response>
174+
/// <response code="503">Problem endpoints are disabled</response>
175+
[HttpPost("stackoverflow")]
176+
[ProducesResponseType(typeof(SimulationResult), StatusCodes.Status200OK)]
177+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status503ServiceUnavailable)]
178+
public IActionResult TriggerStackOverflow([FromQuery] int delaySeconds = 0)
179+
{
180+
return TriggerCrash(new CrashRequest
181+
{
182+
CrashType = CrashType.StackOverflow,
183+
DelaySeconds = Math.Clamp(delaySeconds, 0, 60)
184+
});
185+
}
186+
}
187+
188+
/// <summary>
189+
/// Information about a crash type.
190+
/// </summary>
191+
public class CrashTypeInfo
192+
{
193+
/// <summary>
194+
/// Name of the crash type.
195+
/// </summary>
196+
public required string Name { get; set; }
197+
198+
/// <summary>
199+
/// Numeric value for the crash type enum.
200+
/// </summary>
201+
public int Value { get; set; }
202+
203+
/// <summary>
204+
/// Detailed description of what this crash type does.
205+
/// </summary>
206+
public required string Description { get; set; }
207+
208+
/// <summary>
209+
/// Whether this crash type is recommended for Azure crash monitoring.
210+
/// </summary>
211+
public bool RecommendedForAzure { get; set; }
212+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
namespace PerfProblemSimulator.Models;
2+
3+
/// <summary>
4+
/// Request model for triggering application crashes.
5+
/// </summary>
6+
/// <remarks>
7+
/// <para>
8+
/// <strong>Educational Note:</strong> This request triggers intentional application crashes
9+
/// for learning how to use Azure crash monitoring and memory dump collection.
10+
/// </para>
11+
/// <para>
12+
/// <strong>WARNING:</strong> These operations will terminate the application process!
13+
/// The application will need to be restarted (Azure App Service does this automatically).
14+
/// </para>
15+
/// </remarks>
16+
public class CrashRequest
17+
{
18+
/// <summary>
19+
/// The type of crash to trigger.
20+
/// </summary>
21+
public CrashType CrashType { get; set; } = CrashType.FailFast;
22+
23+
/// <summary>
24+
/// Optional delay in seconds before the crash occurs.
25+
/// Allows time to observe the application state before crash.
26+
/// Default: 0 (immediate)
27+
/// </summary>
28+
public int DelaySeconds { get; set; } = 0;
29+
30+
/// <summary>
31+
/// Custom message to include in the crash (for FailFast and UnhandledException types).
32+
/// </summary>
33+
public string? Message { get; set; }
34+
}
35+
36+
/// <summary>
37+
/// Types of crashes that can be triggered.
38+
/// </summary>
39+
public enum CrashType
40+
{
41+
/// <summary>
42+
/// Calls Environment.FailFast() which immediately terminates the process.
43+
/// Creates a Windows Error Report and crash dump if configured.
44+
/// </summary>
45+
FailFast = 0,
46+
47+
/// <summary>
48+
/// Triggers a StackOverflowException via infinite recursion.
49+
/// Cannot be caught and immediately terminates the process.
50+
/// Creates interesting stack traces for analysis.
51+
/// </summary>
52+
StackOverflow = 1,
53+
54+
/// <summary>
55+
/// Throws an unhandled exception on a background thread.
56+
/// Terminates the process if unhandled exception policy is set to terminate.
57+
/// </summary>
58+
UnhandledException = 2,
59+
60+
/// <summary>
61+
/// Triggers an access violation by writing to protected memory.
62+
/// Requires unsafe code and demonstrates native-level crashes.
63+
/// </summary>
64+
AccessViolation = 3,
65+
66+
/// <summary>
67+
/// Allocates memory until the process runs out and crashes.
68+
/// Different from memory pressure - this is meant to be fatal.
69+
/// </summary>
70+
OutOfMemory = 4
71+
}

src/PerfProblemSimulator/Models/SimulationType.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,11 @@ public enum SimulationType
5252
/// Thread pool starvation simulation using sync-over-async anti-patterns.
5353
/// Diagnosis tools: ThreadPool.GetAvailableThreads(), dotnet-counters, Application Insights request queuing.
5454
/// </summary>
55-
ThreadBlock
55+
ThreadBlock,
56+
57+
/// <summary>
58+
/// Application crash simulation that terminates the process.
59+
/// Diagnosis tools: Azure Crash Monitoring, Windows Error Reporting, crash dump analysis with WinDbg.
60+
/// </summary>
61+
Crash
5662
}

src/PerfProblemSimulator/PerfProblemSimulator.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
Common properties (TargetFramework, Nullable, ImplicitUsings) are inherited from Directory.Build.props
66
-->
77

8+
<PropertyGroup>
9+
<!-- Enable unsafe code for AccessViolation crash simulation -->
10+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
11+
</PropertyGroup>
12+
813
<ItemGroup>
914
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
1015
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.0" />

src/PerfProblemSimulator/Program.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@
108108
// its own simulation, and state is tracked by the singleton SimulationTracker.
109109
builder.Services.AddTransient<IThreadBlockService, ThreadBlockService>();
110110

111+
// CrashService - Transient service for triggering intentional application crashes
112+
// Educational Note: This service demonstrates various crash scenarios for learning
113+
// how to use Azure crash monitoring and memory dump collection.
114+
builder.Services.AddTransient<ICrashService, CrashService>();
115+
111116
// MetricsCollector - Singleton service for collecting system metrics
112117
// Educational Note: This service runs on a DEDICATED THREAD (not the thread pool)
113118
// so it remains responsive even during thread pool starvation scenarios.

0 commit comments

Comments
 (0)