A simple C# class that allows multiple concurrent requests for the same operation to run that operation just once and share the result. It's intended to be used in systems that expect real-time results but want to avoid the waste that comes with concurrent processing of the same input. The more concurrent requests, the greater the benefit: this solution thrives under intense load tests.
This is not a cache: once an action is completed, the results are shared with everyone supplying the same input and discarded.
To get started, copy SharedAction/SharedAction.cs directly into your project.
Note: if you load test these using a browser, you may encounter stalls due to queuing. A purpose-built load generator tool is recommended.
public record Inventory(decimal Price, int InventoryCount); // Example data object.
// The key must include every input variable.
private static readonly SharedAction<(string Sku, int WarehouseId), Inventory?> inventoryActions = new();
[HttpGet]
public async Task<Inventory?> GetAsync(string sku, int warehouseId, CancellationToken cancellationToken)
{
return await inventoryActions.RunAsync((sku, warehouseId), async (input, cancellationToken) =>
{
// The "input" parameter avoids the overhead of capturing variables.
// "GetInventoryAsync" is a placeholder for the real call to the underlying system.
return await GetInventoryAsync(input.Sku, input.WarehouseId, cancellationToken);
}, cancellationToken);
}
// The key must include every input variable.
var inventoryActions = new SharedAction<(string Sku, int WarehouseId), Inventory?>();
app.MapGet("/api/realtimeinventory", async (string sku, int warehouseId, CancellationToken cancellationToken) =>
{
var result = await inventoryActions.RunAsync((sku, warehouseId), async (input, cancellationToken) =>
{
// The "input" parameter avoids the overhead of capturing variables.
// "GetInventoryAsync" is a placeholder for the real call to the underlying system.
return await GetInventoryAsync(input.Sku, input.WarehouseId, cancellationToken);
}, cancellationToken);
return result;
});