aws-lambda-dotnet icon indicating copy to clipboard operation
aws-lambda-dotnet copied to clipboard

Support async function initialization with the .NET 6 managed runtime

Open martincostello opened this issue 2 years ago • 3 comments

Issue #1087

Description of changes:

Adds support for asynchronous initialization of classes that implement handlers for lambdas by introducing a new IHandlerInitializer interface (the specific name is open for discussion).

If an instance-based class (i.e. not a static class) used for a handler implements the IHandlerInitializer interface, it is invoked during the initialization of user code. If the method throws an exception or returns false (the need to return a boolean is also open for discussion), then an exception is thrown and the Lambda runtime would report the initialization failure. Otherwise if the method returns true, then the code is considered to be initialized and ready to process requests.

If the handler class is static or does not implement this interface, execution is the same as it is today.

Using the interface allows the user to opt-in to asynchronous initialization in an idiomatic way that integrates with the existing asynchronous initialization support for custom runtimes without the need to block on tasks in a class constructor.

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

martincostello avatar Feb 25 '22 13:02 martincostello

The challenge for this is a Lambda function using managed runtime doesn't have a direct dependency on Amazon.Lambda.RuntimeSupport. The alternative would be to put IHandlerInitializer in Amazon.Lambda.Core but that also has problems because the user brings the version of Amazon.Lambda.Core. If a user brings in an old version that doesn't have IHandlerInitializer then Amazon.Lambda.RuntimeSupport blows up with a missing type exception. That is why the new logging methods added for .NET 6 were added to the logger interface with a default implementation.

I think the safe way to add this is lookup the InitializeAsync method by convention just like we look for the handler method instead of relying on an interface.

Another concern is we would be making one more reflection call during cold start, so we need to make sure that does not add any significant performance hit when there isn't a InitializeAsync at the lowest memory setting.

Also the boolean seems unnecessary. If the task returned has a failed status we know initialization failed.

normj avatar Feb 26 '22 07:02 normj

Thanks for the feedback Norm. I'll have a rethink on how to approach this.

martincostello avatar Feb 26 '22 07:02 martincostello

I've changed this to remove the interface, and instead invoke a method with either of the following two signatures if found on the handler's type:

  • public static Task InitializeAsync()
  • public Task InitializeAsync()

There's a few open questions marked with // TODO comments.

martincostello avatar Feb 26 '22 16:02 martincostello

I'm going to close for lack of activity.

normj avatar Jan 13 '23 08:01 normj

InitializeAsync would still be a nice shot ..

Rayzbam avatar Jul 18 '23 14:07 Rayzbam