Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapstart Minimal API Performance Improvements #2010

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from

Conversation

ppittle
Copy link
Member

@ppittle ppittle commented Mar 12, 2025

Issue #, if available:
It is not feasible for users to warm up the asp.net and lambda pipelines via SnapshotRestore.RegisterBeforeSnapshot when using .NET MinimalAPI Lambda.

Description of changes:
Creates a new extension method, AddAWSLambdaBeforeSnapshotRequest that allows users to add a function meant to initialize the asp.net and lambda pipelines during SnapshotRestore.RegisterBeforeSnapshot, improving the performance gains offered by SnapStart.

Example:

var builder = WebApplication.CreateSlimBuilder(args);

builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);

// Initialize asp.net pipeline before Snapshot
builder.Services.AddAWSLambdaBeforeSnapshotRequest(async httpClient =>
{
     await httpClient.GetAsync($"/test");
});

var app = builder.Build();
 
app.MapGet($"/test", () => "Success");
 
app.Run();

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@ppittle ppittle changed the base branch from master to dev March 12, 2025 18:25
@ppittle ppittle changed the title Snapstart Minimal API Performance Improvements [DRAFT] Snapstart Minimal API Performance Improvements Mar 12, 2025
@ppittle ppittle marked this pull request as draft March 12, 2025 18:25
@ppittle ppittle force-pushed the snapstart-minapi-perf-improvements branch from 520905f to 784e195 Compare March 12, 2025 22:52
@ppittle ppittle marked this pull request as ready for review March 13, 2025 05:48
@philasmar philasmar requested a review from normj March 13, 2025 13:12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@normj I don't know if there's an implication of Strong Name signing the RuntimeSupport library. Not sure if there are any ramifications for Lambda and our customers.

@philasmar
Copy link
Contributor

@ppittle ppittle changed the title [DRAFT] Snapstart Minimal API Performance Improvements Snapstart Minimal API Performance Improvements Mar 14, 2025
@ppittle ppittle requested a review from philasmar March 19, 2025 19:06
@@ -16,7 +15,9 @@ namespace Amazon.Lambda.AspNetCoreServer.Hosting.Internal
/// </summary>
public abstract class LambdaRuntimeSupportServer : LambdaServer
{
IServiceProvider _serviceProvider;
private readonly IServiceProvider _serviceProvider;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this logic can't be moved into AbstractAspNetCoreFunction of Amazon.Lambda.AspNetCoreServer? This solution is currently not available to users that using just Amazon.Lambda.AspNetCoreServer. I don't have metrics on how many people that is but based on NuGet download counts Amazon.Lambda.AspNetCoreServer has twice the downloads of the latest version compared to Amazon.Lambda.AspNetCoreServer.Hosting implying half of the users building ASP.NET Core Lambda functions are not using Amazon.Lambda.AspNetCoreServer.Hosting.

{
#if NET8_0_OR_GREATER

Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(async () =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this behavior surprising that when the user makes calls with the HttpClient it doesn't actually make calls just records them. For example in my testing I setup a callback that hit an endpoint that would return my list of DynamoDB tables.

builder.Services.AddAWSLambdaBeforeSnapshotRequest(async client => 
{
    var tables = await client.GetStringAsync("/tables");
    Console.WriteLine(tables);
});

I was really confused why the logs didn't show my tables when I had the print statement. Now I understand because the call wasn't actually made till some time later. Customers might have other logging or behavioral changes they do based on what they expect the return to be.

Seems like we should be able to refactor this so the call is actually made so users don't get caught surprised.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you feel this is impractical to do then we shouldn't send in an HttpClient into the users Func<HttpClient, Task>. Maybe change the callback to be Func<HttpMessageRequest> where users just return the request to be made. That way there would be no confusion what the HttpClient is capable of doing.


<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>Amazon.Lambda.AspNetCoreServer.Hosting, PublicKey="0024000004800000940000000602000000240000525341310004000001000100db5f59f098d27276c7833875a6263a3cc74ab17ba9a9df0b52aedbe7252745db7274d5271fd79c1f08f668ecfa8eaab5626fa76adc811d3c8fc55859b0d09d3bc0a84eecd0ba891f2b8a2fc55141cdcc37c2053d53491e650a479967c3622762977900eddbf1252ed08a2413f00a28f3a0752a81203f03ccb7f684db373518b4"</_Parameter1>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want Amazon.Lambda.AspNetCoreServer.Hosting relying on the internals of Amazon.Lambda.RuntimeSupport. I don't see why you need to use the InternalLogger.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The internal reference was necessary in order to create a LambdaContext:

 public static async Task ExecuteSnapstartInitRequests(string jsonRequest, int times, HandlerWrapper handlerWrapper)
 {
            var dummyRequest = new InvocationRequest
            {
                InputStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonRequest)),
                LambdaContext = new LambdaContext(
                    _fakeRuntimeApiHeaders,
                    new LambdaEnvironment(),
                    new SimpleLoggerWriter())
            };

@normj - I agree that the InternalsVisibleTo is less than ideal, Is there a better way?

@ppittle ppittle force-pushed the snapstart-minapi-perf-improvements branch 2 times, most recently from 3df5501 to fa3658e Compare March 25, 2025 23:40
@ppittle ppittle force-pushed the snapstart-minapi-perf-improvements branch from fa3658e to fc98552 Compare March 26, 2025 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants