Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Octopets.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octopets.Backend", "backend
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octopets.AppHost", "apphost\Octopets.AppHost.csproj", "{9AD74B40-D0B3-4BF3-A695-5190CD75C07D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octopets.ServiceDefaults", "ServiceDefaults\Octopets.ServiceDefaults.csproj", "{66B1E172-8267-57A5-DADE-D709CF68DD45}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octopets.ServiceDefaults", "servicedefaults\Octopets.ServiceDefaults.csproj", "{66B1E172-8267-57A5-DADE-D709CF68DD45}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{089100B1-113F-4E66-888A-E83F3999EAFD}"
ProjectSection(SolutionItems) = preProject
Expand Down
66 changes: 42 additions & 24 deletions backend/Endpoints/ListingEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,49 @@
namespace Octopets.Backend.Endpoints;

public static class ListingEndpoints
{ // Method to simulate memory exhaustion by allocating ~1GB of memory
private static void AReallyExpensiveOperation()
{ // Memory-safe operation with bounded allocations and proper resource management
private static async Task AReallyExpensiveOperation(ILogger logger, CancellationToken cancellationToken = default)
{
// Create lists to hold large amounts of data
var memoryHogs = new List<byte[]>();

// Allocate memory in chunks until we reach approximately 1GB
// Each iteration allocates 100MB
for (int i = 0; i < 10; i++)
// Add telemetry for monitoring
var startTime = DateTime.UtcNow;

try
{
// Allocate 100MB per iteration (100 * 1024 * 1024 = 104,857,600 bytes)
var largeArray = new byte[100 * 1024 * 1024];

// Fill with random data to ensure memory is actually allocated
new Random().NextBytes(largeArray);

// Add to list to prevent garbage collection
memoryHogs.Add(largeArray);

// Add a small delay to let the effect be more visible
Thread.Sleep(100);
// Use a bounded allocation instead of unbounded 1GB
// This simulates work without causing OOM
const int maxIterations = 10;
const int smallBufferSize = 1024; // 1KB instead of 100MB

var bufferPool = System.Buffers.ArrayPool<byte>.Shared;

for (int i = 0; i < maxIterations; i++)
{
// Check for cancellation
cancellationToken.ThrowIfCancellationRequested();

// Use pooled buffer to avoid GC pressure
byte[] buffer = bufferPool.Rent(smallBufferSize);
try
{
// Simulate some work without holding memory
Array.Fill(buffer, (byte)(i % 256), 0, smallBufferSize);

// Small delay to simulate work
await Task.Delay(10, cancellationToken);
}
finally
{
// Return buffer to pool
bufferPool.Return(buffer);
}
}
}
finally
{
// Add telemetry
var duration = DateTime.UtcNow - startTime;
logger.LogInformation("AReallyExpensiveOperation completed in {DurationMs}ms", duration.TotalMilliseconds);
}

// Retain the reference to prevent garbage collection
GC.KeepAlive(memoryHogs);
}

public static void MapListingEndpoints(this WebApplication app)
Expand All @@ -45,12 +63,12 @@ public static void MapListingEndpoints(this WebApplication app)
.WithName("GetAllListings")
.WithDescription("Gets all listings")
.WithOpenApi(); // GET listing by id
group.MapGet("/{id:int}", async (int id, IListingRepository repository, IConfiguration config) =>
group.MapGet("/{id:int}", async (int id, IListingRepository repository, IConfiguration config, ILogger<Program> logger, CancellationToken cancellationToken) =>
{
// Only throw exception or simulate memory issues if ERRORS flag is set to true
if (config.GetValue<bool>("ERRORS"))
{
AReallyExpensiveOperation();
await AReallyExpensiveOperation(logger, cancellationToken);
}

var listing = await repository.GetByIdAsync(id);
Expand Down