From 57906410d4d10d6b391287a3810c197a4233112a Mon Sep 17 00:00:00 2001 From: Norm Johanson Date: Mon, 10 Mar 2025 20:59:27 -0700 Subject: [PATCH 1/4] Add integration for setting up SQS event source for a Lambda function. --- .../d530dfa0-e51a-4bcb-8061-835237914aee.json | 11 ++ .gitignore | 5 +- Directory.Packages.props | 1 + integrations-on-dotnet-aspire-for-aws.sln | 7 + .../Lambda.AppHost/Lambda.AppHost.csproj | 2 + playground/Lambda/Lambda.AppHost/Program.cs | 14 ++ .../Properties/launchSettings.json | 2 +- .../Lambda/SQSProcessorFunction/Function.cs | 44 ++++++ .../Properties/launchSettings.json | 22 +++ .../SQSProcessorFunction.csproj | 21 +++ .../aws-lambda-tools-defaults.json | 15 ++ .../Lambda/SQSEventSourceExtensions.cs | 144 ++++++++++++++++++ .../Lambda/SQSEventSourceOptions.cs | 26 ++++ .../Lambda/SQSEventSourceResource.cs | 27 ++++ .../SDKResourceAnnotation.cs | 17 +++ .../SDKResourceExtensions.cs | 2 + 16 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 .autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json create mode 100644 playground/Lambda/SQSProcessorFunction/Function.cs create mode 100644 playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json create mode 100644 playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj create mode 100644 playground/Lambda/SQSProcessorFunction/aws-lambda-tools-defaults.json create mode 100644 src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs create mode 100644 src/Aspire.Hosting.AWS/Lambda/SQSEventSourceOptions.cs create mode 100644 src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs create mode 100644 src/Aspire.Hosting.AWS/SDKResourceAnnotation.cs diff --git a/.autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json b/.autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json new file mode 100644 index 0000000..f3fb525 --- /dev/null +++ b/.autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json @@ -0,0 +1,11 @@ +{ + "Projects": [ + { + "Name": "Aspire.Hosting.AWS", + "Type": "Patch", + "ChangelogMessages": [ + "Add support for configuring SQS event source for a Lambda function" + ] + } + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index a879622..2b15a09 100644 --- a/.gitignore +++ b/.gitignore @@ -402,4 +402,7 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml -.idea/ \ No newline at end of file +.idea/ + +# CDK temp files +**/cdk.out/** \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index 51f5d72..1cb3572 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -28,6 +28,7 @@ + diff --git a/integrations-on-dotnet-aspire-for-aws.sln b/integrations-on-dotnet-aspire-for-aws.sln index 6e1bd32..aa77e3a 100644 --- a/integrations-on-dotnet-aspire-for-aws.sln +++ b/integrations-on-dotnet-aspire-for-aws.sln @@ -44,6 +44,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebAWSCallsLambdaFunction", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebCalculatorFunctions", "playground\Lambda\WebCalculatorFunctions\WebCalculatorFunctions.csproj", "{4CE69424-50B4-1D2F-EA87-E9FC81C4BEA6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQSProcessorFunction", "playground\Lambda\SQSProcessorFunction\SQSProcessorFunction.csproj", "{FC2267CD-9769-68B1-A271-774F98326A43}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -102,6 +104,10 @@ Global {4CE69424-50B4-1D2F-EA87-E9FC81C4BEA6}.Debug|Any CPU.Build.0 = Debug|Any CPU {4CE69424-50B4-1D2F-EA87-E9FC81C4BEA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {4CE69424-50B4-1D2F-EA87-E9FC81C4BEA6}.Release|Any CPU.Build.0 = Release|Any CPU + {FC2267CD-9769-68B1-A271-774F98326A43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC2267CD-9769-68B1-A271-774F98326A43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC2267CD-9769-68B1-A271-774F98326A43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC2267CD-9769-68B1-A271-774F98326A43}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -122,6 +128,7 @@ Global {A2750C2D-1F82-47CB-9EAB-B819E3EBDD74} = {C3C0B096-DB7C-4D1B-B8A0-91631B32B4DE} {96396A08-6FB9-49C2-A923-1AF1C97087EF} = {C3C0B096-DB7C-4D1B-B8A0-91631B32B4DE} {4CE69424-50B4-1D2F-EA87-E9FC81C4BEA6} = {C3C0B096-DB7C-4D1B-B8A0-91631B32B4DE} + {FC2267CD-9769-68B1-A271-774F98326A43} = {C3C0B096-DB7C-4D1B-B8A0-91631B32B4DE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FBA55172-92F1-4495-A082-E0ABE4F4AF09} diff --git a/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj b/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj index ac2cb8e..831f37d 100644 --- a/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj +++ b/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj @@ -6,11 +6,13 @@ Exe $(DefaultTargetFramework) true + $(NoWarn);CS8002 + diff --git a/playground/Lambda/Lambda.AppHost/Program.cs b/playground/Lambda/Lambda.AppHost/Program.cs index d7f7c5c..ca55eb2 100644 --- a/playground/Lambda/Lambda.AppHost/Program.cs +++ b/playground/Lambda/Lambda.AppHost/Program.cs @@ -1,5 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. using Amazon.Lambda; +using Aspire.Hosting; using Aspire.Hosting.AWS.Lambda; #pragma warning disable CA2252 // This API requires opting into preview features @@ -8,6 +9,13 @@ var awsSdkConfig = builder.AddAWSSDKConfig().WithRegion(Amazon.RegionEndpoint.USWest2); +var cdkStackResource = builder.AddAWSCDKStack("AWSLambdaPlaygroundResources"); +var sqsDemoQueue = cdkStackResource.AddSQSQueue("DemoQueue"); + + +// TODO: Remove this once the new version of the test tool that supports SQS has been released. +builder.AddAWSLambdaServiceEmulator(new LambdaEmulatorOptions { DisableAutoInstall = true }); + builder.AddAWSLambdaFunction("ToUpperFunction", lambdaHandler: "ToUpperLambdaFunctionExecutable", new LambdaFunctionOptions { ApplicationLogLevel = ApplicationLogLevel.DEBUG, LogFormat = LogFormat.JSON}); var defaultRouteLambda = builder.AddAWSLambdaFunction("LambdaDefaultRoute", lambdaHandler: "WebDefaultLambdaFunction"); @@ -30,5 +38,11 @@ .WithReference(multiplyFunction, Method.Get, "/multiply/{x}/{y}") .WithReference(divideFunction, Method.Get, "/divide/{x}/{y}"); + +builder.AddAWSLambdaFunction("SQSProcessorFunction", "SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler") + .WithReference(awsSdkConfig) + .WithSQSEventSource(sqsDemoQueue); + + builder.Build().Run(); \ No newline at end of file diff --git a/playground/Lambda/Lambda.AppHost/Properties/launchSettings.json b/playground/Lambda/Lambda.AppHost/Properties/launchSettings.json index c42f360..769afcf 100644 --- a/playground/Lambda/Lambda.AppHost/Properties/launchSettings.json +++ b/playground/Lambda/Lambda.AppHost/Properties/launchSettings.json @@ -5,7 +5,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:17295;http://localhost:15136", + "applicationUrl": "https://localhost:17296;http://localhost:15137", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", diff --git a/playground/Lambda/SQSProcessorFunction/Function.cs b/playground/Lambda/SQSProcessorFunction/Function.cs new file mode 100644 index 0000000..a6494b3 --- /dev/null +++ b/playground/Lambda/SQSProcessorFunction/Function.cs @@ -0,0 +1,44 @@ +using Amazon.Lambda.Core; +using Amazon.Lambda.SQSEvents; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using OpenTelemetry.Instrumentation.AWSLambda; +using OpenTelemetry.Trace; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace SQSProcessorFunction; + +public class Function +{ + IHost _host; + TracerProvider _traceProvider; + + public Function() + { + var builder = new HostApplicationBuilder(); + + builder.AddServiceDefaults(); + _host = builder.Build(); + + _traceProvider = _host.Services.GetRequiredService(); + } + + public Task FunctionHandler(SQSEvent evnt, ILambdaContext context) + => AWSLambdaWrapper.TraceAsync(_traceProvider, async (evnt, context) => + { + foreach (var message in evnt.Records) + { + await ProcessMessageAsync(message, context); + } + }, evnt, context); + + private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context) + { + context.Logger.LogInformation($"Processed message {message.Body}"); + + // TODO: Do interesting work based on the new message + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json b/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json new file mode 100644 index 0000000..b5763c2 --- /dev/null +++ b/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json @@ -0,0 +1,22 @@ +{ + "profiles": { + "Mock Lambda Test Tool": { + "commandName": "Executable", + "commandLineArgs": "--port 5050", + "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", + "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-8.0.exe" + }, + "Aspire_ProcessorFunction": { + "commandName": "Executable", + "executablePath": "dotnet", + "commandLineArgs": "exec --depsfile ./SQSProcessorFunction.deps.json --runtimeconfig ./SQSProcessorFunction.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.9.999\\amazon.lambda.testtool\\0.9.999\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler", + "workingDirectory": ".\\bin\\$(Configuration)\\net8.0" + }, + "Aspire_SQSProcessorFunction": { + "commandName": "Executable", + "executablePath": "dotnet", + "commandLineArgs": "exec --depsfile ./SQSProcessorFunction.deps.json --runtimeconfig ./SQSProcessorFunction.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.9.888\\amazon.lambda.testtool\\0.9.888\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler", + "workingDirectory": ".\\bin\\$(Configuration)\\net8.0" + } + } +} \ No newline at end of file diff --git a/playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj b/playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj new file mode 100644 index 0000000..fea9b11 --- /dev/null +++ b/playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj @@ -0,0 +1,21 @@ + + + net8.0 + enable + enable + true + Lambda + + true + + true + + + + + + + + + + \ No newline at end of file diff --git a/playground/Lambda/SQSProcessorFunction/aws-lambda-tools-defaults.json b/playground/Lambda/SQSProcessorFunction/aws-lambda-tools-defaults.json new file mode 100644 index 0000000..87d664e --- /dev/null +++ b/playground/Lambda/SQSProcessorFunction/aws-lambda-tools-defaults.json @@ -0,0 +1,15 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "default", + "region": "us-west-2", + "configuration": "Release", + "function-runtime": "dotnet8", + "function-memory-size": 512, + "function-timeout": 30, + "function-handler": "SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler" +} \ No newline at end of file diff --git a/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs new file mode 100644 index 0000000..3667d92 --- /dev/null +++ b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs @@ -0,0 +1,144 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +using Aspire.Hosting.ApplicationModel; +using Aspire.Hosting.AWS; +using Aspire.Hosting.AWS.CDK; +using Aspire.Hosting.AWS.CloudFormation; +using Aspire.Hosting.AWS.Lambda; +using Constructs; +using System.Runtime.Versioning; +using System.Text; + +#pragma warning disable IDE0130 +namespace Aspire.Hosting; + +/// +/// Extension methods adding SQS event source for Lambda functions. +/// +[RequiresPreviewFeatures(Constants.LambdaPreviewMessage)] +public static class SQSEventSourceExtensions +{ + /// + /// Add an SQS event source to a Lambda function. This feature emulates adding an SQS event source to a Lambda function when deployed to AWS. + /// A separate sub resource will be added to the .NET Aspire application that polls the SQS queue. As messages + /// are received from the queue the Lambda function will be invoked with the messages. + /// + /// The Lambda function to add the event source to. + /// The queue url for an SQS queue that will be polled for messages. + /// Optional configuration for the event source. + /// + /// + public static IResourceBuilder WithSQSEventSource(this IResourceBuilder lambdaFunction, string queueUrl, SQSEventSourceOptions? options = null) + { + return WithSQSEventSource(lambdaFunction, () => ValueTask.FromResult(queueUrl), options); + } + + /// + /// Add an SQS event source to a Lambda function. This feature emulates adding an SQS event source to a Lambda function when deployed to AWS. + /// A separate sub resource will be added to the .NET Aspire application that polls the SQS queue. As messages + /// are received from the queue the Lambda function will be invoked with the messages. + /// + /// The Lambda function to add the event source to. + /// CDK SQS queue construct that will be polled for messages. + /// Optional configuration for the event source. + /// + /// + public static IResourceBuilder WithSQSEventSource(this IResourceBuilder lambdaFunction, IResourceBuilder> queue, SQSEventSourceOptions? options = null) + { + var queueOutputReference = queue.GetOutput("QueueUrl", queue => queue.QueueUrl); + return WithSQSEventSource(lambdaFunction, queueOutputReference, options); + } + + /// + /// Add an SQS event source to a Lambda function. This feature emulates adding an SQS event source to a Lambda function when deployed to AWS. + /// A separate sub resource will be added to the .NET Aspire application that polls the SQS queue. As messages + /// are received from the queue the Lambda function will be invoked with the messages. + /// + /// The Lambda function to add the event source to. + /// CloudFormation StackOutputReference that should point to a SQS queue url output parameter in the CloudFormation stack. + /// Optional configuration for the event source. + /// + /// + public static IResourceBuilder WithSQSEventSource(this IResourceBuilder lambdaFunction, StackOutputReference queueCfnOutputReference, SQSEventSourceOptions? options = null) + { + Func> resolver = async () => + { + var queueUrl = await queueCfnOutputReference.GetValueAsync(); + if (string.IsNullOrEmpty(queueUrl)) + { + throw new InvalidOperationException("Output parameter for queue url failed to resolve"); + } + + if (!Uri.TryCreate(queueUrl, UriKind.Absolute, out _)) + { + throw new InvalidOperationException($"Output parameter value {queueUrl} is not a SQS queue url."); + } + + return queueUrl; + }; + + return WithSQSEventSource(lambdaFunction, resolver, options); + } + + private static IResourceBuilder WithSQSEventSource(IResourceBuilder lambdaFunction, Func> queueUrlResolver, SQSEventSourceOptions? options = null) + { + var sqsEventSourceResource = lambdaFunction.ApplicationBuilder.AddResource(new SQSEventSourceResource($"SQSEventSource-{lambdaFunction.Resource.Name}")) + .WithParentRelationship(lambdaFunction) + .ExcludeFromManifest(); + + sqsEventSourceResource.WithArgs(context => + { + sqsEventSourceResource.Resource.AddCommandLineArguments(context.Args); + }); + + sqsEventSourceResource.WithEnvironment(async (context) => + { + LambdaEmulatorAnnotation? lambdaEmulatorAnnotation = null; + if (lambdaFunction.ApplicationBuilder.Resources.FirstOrDefault(x => x.TryGetLastAnnotation(out lambdaEmulatorAnnotation)) == null || + lambdaEmulatorAnnotation == null) + { + throw new InvalidOperationException("Lambda function is missing required annotations for Lambda emulator"); + } + + var queueUrl = await queueUrlResolver(); + + var configBuilder = new StringBuilder(); + configBuilder.Append($"QueueUrl={queueUrl},FunctionName={lambdaFunction.Resource.Name},LambdaRuntimeApi={lambdaEmulatorAnnotation.Endpoint.Url}"); + + if (options != null) + { + if (options.BatchSize.HasValue) + { + configBuilder.Append($",BatchSize={options.BatchSize.Value}"); + } + if (options.DisableMessageDelete.HasValue) + { + configBuilder.Append($",DisableMessageDelete={options.DisableMessageDelete.Value}"); + } + if (options.VisibilityTimeout.HasValue) + { + configBuilder.Append($",VisibilityTimeout={options.VisibilityTimeout.Value}"); + } + } + + // Look to see if the Lambda function has been configured with an AWS SDK config. If so then + // configure the SQS event source with the same config to access the SQS queue. + var awsSdkConfig = lambdaFunction.Resource.Annotations.OfType().FirstOrDefault()?.SdkConfig; + if (awsSdkConfig != null) + { + if (!string.IsNullOrEmpty(awsSdkConfig.Profile)) + { + configBuilder.Append($",Profile={awsSdkConfig.Profile}"); + } + if (awsSdkConfig.Region != null) + { + configBuilder.Append($",Region={awsSdkConfig.Region.SystemName}"); + } + } + + context.EnvironmentVariables[SQSEventSourceResource.SQS_EVENT_CONFIG_ENV_VAR] = configBuilder.ToString(); + }); + + return lambdaFunction; + } +} diff --git a/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceOptions.cs b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceOptions.cs new file mode 100644 index 0000000..bffc4aa --- /dev/null +++ b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceOptions.cs @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +namespace Aspire.Hosting.AWS.Lambda; + +/// +/// Optional settings for configuring an SQS event source for a Lambda function. +/// +public class SQSEventSourceOptions +{ + /// + /// The batch size to read and send to Lambda function. + /// SQS will return with less then batch size if there are not enough messages in the queue. + /// + public int? BatchSize { get; set; } + + /// + /// If true the messages read from the queue will not be deleted after being processed. + /// + public bool? DisableMessageDelete { get; set; } + + /// + /// The visibility timeout used for messages read from the queue. This is the length the message will not be visible to be read + /// again once it is returned in the receive call. + /// + public int? VisibilityTimeout { get; set; } +} diff --git a/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs new file mode 100644 index 0000000..1ca8528 --- /dev/null +++ b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs @@ -0,0 +1,27 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +using Aspire.Hosting.ApplicationModel; +using System.Text; + +namespace Aspire.Hosting.AWS.Lambda; + +internal class SQSEventSourceResource(string name) : ExecutableResource(name, + "dotnet", + Environment.CurrentDirectory + ) +{ + internal const string SQS_EVENT_CONFIG_ENV_VAR = "SQS_EVENTSOURCE_CONFIG"; + internal void AddCommandLineArguments(IList arguments) + { + arguments.Add("lambda-test-tool"); + arguments.Add("start"); + arguments.Add("--no-launch-window"); + + arguments.Add("--sqs-eventsource-config"); + + // The TestTool will look for the config in the environment variable. The environment variable + // is used because the config contains information like port numbers and queue urls from CloudFormation + // stacks that haven't been resolved at the time of settup up the command line arguments. + arguments.Add($"env:{SQS_EVENT_CONFIG_ENV_VAR}"); + } +} diff --git a/src/Aspire.Hosting.AWS/SDKResourceAnnotation.cs b/src/Aspire.Hosting.AWS/SDKResourceAnnotation.cs new file mode 100644 index 0000000..d77648e --- /dev/null +++ b/src/Aspire.Hosting.AWS/SDKResourceAnnotation.cs @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +using Aspire.Hosting.ApplicationModel; + +namespace Aspire.Hosting.AWS; + +/// +/// Annotation to attach to resources to indicate what AWS SDK config the resource is configured for. +/// +/// +internal class SDKResourceAnnotation(IAWSSDKConfig awsSdkConfig) : IResourceAnnotation +{ + /// + /// The AWS SDK config for the SDK to use to connect to AWS. + /// + public IAWSSDKConfig SdkConfig { get; set; } = awsSdkConfig; +} diff --git a/src/Aspire.Hosting.AWS/SDKResourceExtensions.cs b/src/Aspire.Hosting.AWS/SDKResourceExtensions.cs index 464e718..3696cef 100644 --- a/src/Aspire.Hosting.AWS/SDKResourceExtensions.cs +++ b/src/Aspire.Hosting.AWS/SDKResourceExtensions.cs @@ -55,6 +55,8 @@ public static IAWSSDKConfig WithRegion(this IAWSSDKConfig config, RegionEndpoint public static IResourceBuilder WithReference(this IResourceBuilder builder, IAWSSDKConfig awsSdkConfig) where TDestination : IResourceWithEnvironment { + builder.WithAnnotation(new SDKResourceAnnotation(awsSdkConfig)); + builder.WithEnvironment(context => { if (context.ExecutionContext.IsPublishMode) From 2b391ba8b1fd8e41e4bde75d19cfcc222dd66ab8 Mon Sep 17 00:00:00 2001 From: Norm Johanson Date: Fri, 4 Apr 2025 17:11:13 -0700 Subject: [PATCH 2/4] Update to version 0.10.0 and add unit and integ tests for SQS event source integration --- .../d530dfa0-e51a-4bcb-8061-835237914aee.json | 3 +- .../Lambda.AppHost/Lambda.AppHost.csproj | 1 + playground/Lambda/Lambda.AppHost/Program.cs | 4 --- .../Properties/launchSettings.json | 2 +- .../Properties/launchSettings.json | 14 +++++--- src/Aspire.Hosting.AWS/Constants.cs | 2 +- .../Lambda/SQSEventSourceExtensions.cs | 34 ++---------------- .../Lambda/SQSEventSourceResource.cs | 36 +++++++++++++++++++ .../Lambda/PlaygroundE2ETests.cs | 32 ++++++++++++++++- .../LambdaLifecycleHookTests.cs | 4 ++- .../SQSEventSourceConfigTests.cs | 35 ++++++++++++++++++ 11 files changed, 123 insertions(+), 44 deletions(-) create mode 100644 tests/Aspire.Hosting.AWS.UnitTests/SQSEventSourceConfigTests.cs diff --git a/.autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json b/.autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json index f3fb525..9005e28 100644 --- a/.autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json +++ b/.autover/changes/d530dfa0-e51a-4bcb-8061-835237914aee.json @@ -4,7 +4,8 @@ "Name": "Aspire.Hosting.AWS", "Type": "Patch", "ChangelogMessages": [ - "Add support for configuring SQS event source for a Lambda function" + "Add support for configuring SQS event source for a Lambda function", + "Update version of Amazon.Lambda.TestTool to install to version 0.10.0" ] } ] diff --git a/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj b/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj index 831f37d..a341d47 100644 --- a/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj +++ b/playground/Lambda/Lambda.AppHost/Lambda.AppHost.csproj @@ -10,6 +10,7 @@ + diff --git a/playground/Lambda/Lambda.AppHost/Program.cs b/playground/Lambda/Lambda.AppHost/Program.cs index ca55eb2..a8c1f99 100644 --- a/playground/Lambda/Lambda.AppHost/Program.cs +++ b/playground/Lambda/Lambda.AppHost/Program.cs @@ -12,10 +12,6 @@ var cdkStackResource = builder.AddAWSCDKStack("AWSLambdaPlaygroundResources"); var sqsDemoQueue = cdkStackResource.AddSQSQueue("DemoQueue"); - -// TODO: Remove this once the new version of the test tool that supports SQS has been released. -builder.AddAWSLambdaServiceEmulator(new LambdaEmulatorOptions { DisableAutoInstall = true }); - builder.AddAWSLambdaFunction("ToUpperFunction", lambdaHandler: "ToUpperLambdaFunctionExecutable", new LambdaFunctionOptions { ApplicationLogLevel = ApplicationLogLevel.DEBUG, LogFormat = LogFormat.JSON}); var defaultRouteLambda = builder.AddAWSLambdaFunction("LambdaDefaultRoute", lambdaHandler: "WebDefaultLambdaFunction"); diff --git a/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json b/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json index b5763c2..31504fb 100644 --- a/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json +++ b/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json @@ -15,7 +15,7 @@ "Aspire_SQSProcessorFunction": { "commandName": "Executable", "executablePath": "dotnet", - "commandLineArgs": "exec --depsfile ./SQSProcessorFunction.deps.json --runtimeconfig ./SQSProcessorFunction.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.9.888\\amazon.lambda.testtool\\0.9.888\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler", + "commandLineArgs": "exec --depsfile ./SQSProcessorFunction.deps.json --runtimeconfig ./SQSProcessorFunction.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler", "workingDirectory": ".\\bin\\$(Configuration)\\net8.0" } } diff --git a/playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json b/playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json index daae879..35e3af0 100644 --- a/playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json +++ b/playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json @@ -2,27 +2,33 @@ "profiles": { "Aspire_AddFunction": { "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.0.2-preview\\amazon.lambda.testtool\\0.0.2-preview\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::AddFunctionHandler", + "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::AddFunctionHandler", "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", "executablePath": "dotnet" }, "Aspire_MinusFunction": { "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.0.2-preview\\amazon.lambda.testtool\\0.0.2-preview\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::MinusFunctionHandler", + "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::MinusFunctionHandler", "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", "executablePath": "dotnet" }, "Aspire_MultiplyFunction": { "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.0.2-preview\\amazon.lambda.testtool\\0.0.2-preview\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::MultiplyFunctionHandler", + "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::MultiplyFunctionHandler", "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", "executablePath": "dotnet" }, "Aspire_DivideFunction": { "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.0.2-preview\\amazon.lambda.testtool\\0.0.2-preview\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::DivideFunctionHandler", + "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::DivideFunctionHandler", "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", "executablePath": "dotnet" + }, + "Mock Lambda Test Tool": { + "commandName": "Executable", + "commandLineArgs": "--port 5050", + "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", + "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-8.0.exe" } } } \ No newline at end of file diff --git a/src/Aspire.Hosting.AWS/Constants.cs b/src/Aspire.Hosting.AWS/Constants.cs index 76f92c0..28dbb5f 100644 --- a/src/Aspire.Hosting.AWS/Constants.cs +++ b/src/Aspire.Hosting.AWS/Constants.cs @@ -46,5 +46,5 @@ internal static class Constants /// /// The default version of Amazon.Lambda.TestTool that will be automatically installed /// - internal const string DefaultLambdaTestToolVersion = "0.9.1"; + internal const string DefaultLambdaTestToolVersion = "0.10.0"; } diff --git a/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs index 3667d92..0486d81 100644 --- a/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs +++ b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceExtensions.cs @@ -1,5 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +using Amazon.CDK.AWS.Events.Targets; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.AWS; using Aspire.Hosting.AWS.CDK; @@ -102,41 +103,12 @@ private static IResourceBuilder WithSQSEventSource(IResou var queueUrl = await queueUrlResolver(); - var configBuilder = new StringBuilder(); - configBuilder.Append($"QueueUrl={queueUrl},FunctionName={lambdaFunction.Resource.Name},LambdaRuntimeApi={lambdaEmulatorAnnotation.Endpoint.Url}"); - - if (options != null) - { - if (options.BatchSize.HasValue) - { - configBuilder.Append($",BatchSize={options.BatchSize.Value}"); - } - if (options.DisableMessageDelete.HasValue) - { - configBuilder.Append($",DisableMessageDelete={options.DisableMessageDelete.Value}"); - } - if (options.VisibilityTimeout.HasValue) - { - configBuilder.Append($",VisibilityTimeout={options.VisibilityTimeout.Value}"); - } - } - // Look to see if the Lambda function has been configured with an AWS SDK config. If so then // configure the SQS event source with the same config to access the SQS queue. var awsSdkConfig = lambdaFunction.Resource.Annotations.OfType().FirstOrDefault()?.SdkConfig; - if (awsSdkConfig != null) - { - if (!string.IsNullOrEmpty(awsSdkConfig.Profile)) - { - configBuilder.Append($",Profile={awsSdkConfig.Profile}"); - } - if (awsSdkConfig.Region != null) - { - configBuilder.Append($",Region={awsSdkConfig.Region.SystemName}"); - } - } - context.EnvironmentVariables[SQSEventSourceResource.SQS_EVENT_CONFIG_ENV_VAR] = configBuilder.ToString(); + var sqsEventConfig = SQSEventSourceResource.CreateSQSEventConfig(queueUrl, lambdaFunction.Resource.Name, lambdaEmulatorAnnotation.Endpoint.Url, options, awsSdkConfig); + context.EnvironmentVariables[SQSEventSourceResource.SQS_EVENT_CONFIG_ENV_VAR] = sqsEventConfig; }); return lambdaFunction; diff --git a/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs index 1ca8528..00d26b9 100644 --- a/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs +++ b/src/Aspire.Hosting.AWS/Lambda/SQSEventSourceResource.cs @@ -24,4 +24,40 @@ internal void AddCommandLineArguments(IList arguments) // stacks that haven't been resolved at the time of settup up the command line arguments. arguments.Add($"env:{SQS_EVENT_CONFIG_ENV_VAR}"); } + + internal static string CreateSQSEventConfig(string queueUrl, string lambdaFunctionName, string lambdaEmulatorUrl, SQSEventSourceOptions? options, IAWSSDKConfig? awsSdkConfig) + { + var configBuilder = new StringBuilder(); + configBuilder.Append($"QueueUrl={queueUrl},FunctionName={lambdaFunctionName},LambdaRuntimeApi={lambdaEmulatorUrl}"); + + if (options != null) + { + if (options.BatchSize.HasValue) + { + configBuilder.Append($",BatchSize={options.BatchSize.Value}"); + } + if (options.DisableMessageDelete.HasValue) + { + configBuilder.Append($",DisableMessageDelete={options.DisableMessageDelete.Value}"); + } + if (options.VisibilityTimeout.HasValue) + { + configBuilder.Append($",VisibilityTimeout={options.VisibilityTimeout.Value}"); + } + } + + if (awsSdkConfig != null) + { + if (!string.IsNullOrEmpty(awsSdkConfig.Profile)) + { + configBuilder.Append($",Profile={awsSdkConfig.Profile}"); + } + if (awsSdkConfig.Region != null) + { + configBuilder.Append($",Region={awsSdkConfig.Region.SystemName}"); + } + } + + return configBuilder.ToString(); + } } diff --git a/tests/Aspire.Hosting.AWS.Integ.Tests/Lambda/PlaygroundE2ETests.cs b/tests/Aspire.Hosting.AWS.Integ.Tests/Lambda/PlaygroundE2ETests.cs index 2f44fcd..7ece417 100644 --- a/tests/Aspire.Hosting.AWS.Integ.Tests/Lambda/PlaygroundE2ETests.cs +++ b/tests/Aspire.Hosting.AWS.Integ.Tests/Lambda/PlaygroundE2ETests.cs @@ -1,4 +1,8 @@ -using Aspire.Hosting.AWS.Lambda; +using Aspire.Hosting.AWS.CDK; +using Aspire.Hosting.AWS.Lambda; +using Amazon; +using Amazon.SQS; +using Amazon.SQS.Model; namespace Aspire.Hosting.AWS.Integ.Tests.Lambda; @@ -22,6 +26,12 @@ await resourceNotificationService await resourceNotificationService .WaitForResourceAsync("APIGatewayEmulator", KnownResourceStates.Running) .WaitAsync(TimeSpan.FromSeconds(120)); + await resourceNotificationService + .WaitForResourceAsync("AWSLambdaPlaygroundResources", KnownResourceStates.Running) + .WaitAsync(TimeSpan.FromSeconds(120)); + await resourceNotificationService + .WaitForResourceAsync("SQSEventSource-SQSProcessorFunction", KnownResourceStates.Running) + .WaitAsync(TimeSpan.FromSeconds(120)); var lambdaServiceEmulator = (LambdaEmulatorResource)appHost.Resources .Single(static r => r.Name == "LambdaServiceEmulator"); @@ -43,6 +53,26 @@ await resourceNotificationService await TestEndpoint("/multiply/2/1", app, "APIGatewayEmulator")); Assert.Equal("2", await TestEndpoint("/divide/2/1", app, "APIGatewayEmulator")); + + var stackResource = (IStackResource)appHost.Resources + .Single(static r => r.Name == "AWSLambdaPlaygroundResources"); + + var queueUrl = stackResource.Outputs?.FirstOrDefault(x => + { + // The output key has a hash in the middle which could change. To avoid hardcoded logic on the hash check the start and end. + // Example value of the output key "DemoQueue955156E8QueueUrl". + return x.OutputKey.StartsWith("DemoQueue") && x.OutputKey.EndsWith("QueueUrl"); + })?.OutputValue; + + Assert.NotNull(queueUrl); + + using var sqsClient = new AmazonSQSClient(RegionEndpoint.USWest2); + await sqsClient.SendMessageAsync(queueUrl, "themessage", cancellationToken.Token); + + // Wait for the Lambda function to consume the message it gets deleted. + await Task.Delay(5000); + var queueAttributesRepsonse = await sqsClient.GetQueueAttributesAsync(new GetQueueAttributesRequest { QueueUrl = queueUrl, AttributeNames = new List { "All" } }); + Assert.Equal(0, queueAttributesRepsonse.ApproximateNumberOfMessages + queueAttributesRepsonse.ApproximateNumberOfMessagesNotVisible); } finally { diff --git a/tests/Aspire.Hosting.AWS.UnitTests/LambdaLifecycleHookTests.cs b/tests/Aspire.Hosting.AWS.UnitTests/LambdaLifecycleHookTests.cs index 75a91ea..ab9728f 100644 --- a/tests/Aspire.Hosting.AWS.UnitTests/LambdaLifecycleHookTests.cs +++ b/tests/Aspire.Hosting.AWS.UnitTests/LambdaLifecycleHookTests.cs @@ -17,7 +17,9 @@ public async Task GetCurrentInstallPathAsync_ReturnsInstallPath_WhenValidJsonOut { // Arrange string expectedInstallPath = Path.GetTempPath(); - string jsonOutput = JsonNode.Parse($"{{ \"InstallPath\": \"{expectedInstallPath}\" }}")!.ToJsonString(); + + // Escape Windows forward slashes when injecting the value into the JSON document. + string jsonOutput = JsonNode.Parse($"{{ \"InstallPath\": \"{expectedInstallPath.Replace("\\", "\\\\")}\" }}")!.ToJsonString(); _processCommandService .Setup(s => s.RunProcessAndCaptureOuputAsync( diff --git a/tests/Aspire.Hosting.AWS.UnitTests/SQSEventSourceConfigTests.cs b/tests/Aspire.Hosting.AWS.UnitTests/SQSEventSourceConfigTests.cs new file mode 100644 index 0000000..f9c3736 --- /dev/null +++ b/tests/Aspire.Hosting.AWS.UnitTests/SQSEventSourceConfigTests.cs @@ -0,0 +1,35 @@ +using Aspire.Hosting.AWS.Lambda; +using Xunit; + +namespace Aspire.Hosting.AWS.UnitTests; + +public class SQSEventSourceConfigTests +{ + [Fact] + public void Minimal() + { + var config = SQSEventSourceResource.CreateSQSEventConfig("theQueueUrl", "theFunction", "theEmulatorUrl", null, null); + Assert.Equal("QueueUrl=theQueueUrl,FunctionName=theFunction,LambdaRuntimeApi=theEmulatorUrl", config); + } + + [Fact] + public void WithOptions() + { + var config = SQSEventSourceResource.CreateSQSEventConfig("theQueueUrl", "theFunction", "theEmulatorUrl", new SQSEventSourceOptions { BatchSize = 10, DisableMessageDelete= true, VisibilityTimeout = 4}, null); + Assert.Equal("QueueUrl=theQueueUrl,FunctionName=theFunction,LambdaRuntimeApi=theEmulatorUrl,BatchSize=10,DisableMessageDelete=True,VisibilityTimeout=4", config); + } + + [Fact] + public void WithSDKProfile() + { + var config = SQSEventSourceResource.CreateSQSEventConfig("theQueueUrl", "theFunction", "theEmulatorUrl", null, new AWSSDKConfig { Profile = "beta", Region=Amazon.RegionEndpoint.USWest2}); + Assert.Equal("QueueUrl=theQueueUrl,FunctionName=theFunction,LambdaRuntimeApi=theEmulatorUrl,Profile=beta,Region=us-west-2", config); + } + + [Fact] + public void WithOptionsAndProfile() + { + var config = SQSEventSourceResource.CreateSQSEventConfig("theQueueUrl", "theFunction", "theEmulatorUrl", new SQSEventSourceOptions { BatchSize = 10, }, new AWSSDKConfig { Profile = "beta" }); + Assert.Equal("QueueUrl=theQueueUrl,FunctionName=theFunction,LambdaRuntimeApi=theEmulatorUrl,BatchSize=10,Profile=beta", config); + } +} From d390005c7e40b9452eeb8dcde33866c433ea79fe Mon Sep 17 00:00:00 2001 From: Norm Johanson Date: Sat, 5 Apr 2025 09:46:33 -0700 Subject: [PATCH 3/4] Delete unnecessary launchSettings.json --- .../Properties/launchSettings.json | 22 ------------ .../SQSProcessorFunction.csproj | 3 ++ .../Properties/launchSettings.json | 34 ------------------- 3 files changed, 3 insertions(+), 56 deletions(-) delete mode 100644 playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json delete mode 100644 playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json diff --git a/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json b/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json deleted file mode 100644 index 31504fb..0000000 --- a/playground/Lambda/SQSProcessorFunction/Properties/launchSettings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "profiles": { - "Mock Lambda Test Tool": { - "commandName": "Executable", - "commandLineArgs": "--port 5050", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", - "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-8.0.exe" - }, - "Aspire_ProcessorFunction": { - "commandName": "Executable", - "executablePath": "dotnet", - "commandLineArgs": "exec --depsfile ./SQSProcessorFunction.deps.json --runtimeconfig ./SQSProcessorFunction.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.9.999\\amazon.lambda.testtool\\0.9.999\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0" - }, - "Aspire_SQSProcessorFunction": { - "commandName": "Executable", - "executablePath": "dotnet", - "commandLineArgs": "exec --depsfile ./SQSProcessorFunction.deps.json --runtimeconfig ./SQSProcessorFunction.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll SQSProcessorFunction::SQSProcessorFunction.Function::FunctionHandler", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0" - } - } -} \ No newline at end of file diff --git a/playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj b/playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj index fea9b11..74c6791 100644 --- a/playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj +++ b/playground/Lambda/SQSProcessorFunction/SQSProcessorFunction.csproj @@ -18,4 +18,7 @@ + + + \ No newline at end of file diff --git a/playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json b/playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json deleted file mode 100644 index 35e3af0..0000000 --- a/playground/Lambda/WebCalculatorFunctions/Properties/launchSettings.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "profiles": { - "Aspire_AddFunction": { - "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::AddFunctionHandler", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", - "executablePath": "dotnet" - }, - "Aspire_MinusFunction": { - "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::MinusFunctionHandler", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", - "executablePath": "dotnet" - }, - "Aspire_MultiplyFunction": { - "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::MultiplyFunctionHandler", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", - "executablePath": "dotnet" - }, - "Aspire_DivideFunction": { - "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./WebCalculatorFunctions.deps.json --runtimeconfig ./WebCalculatorFunctions.runtimeconfig.json %USERPROFILE%\\.dotnet\\tools\\.store\\amazon.lambda.testtool\\0.10.0\\amazon.lambda.testtool\\0.10.0\\content\\Amazon.Lambda.RuntimeSupport\\net8.0\\Amazon.Lambda.RuntimeSupport.dll WebCalculatorFunctions::WebCalculatorFunctions.Functions::DivideFunctionHandler", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", - "executablePath": "dotnet" - }, - "Mock Lambda Test Tool": { - "commandName": "Executable", - "commandLineArgs": "--port 5050", - "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", - "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-8.0.exe" - } - } -} \ No newline at end of file From 17c7febd24aa4195f35d555282f45c62179ed07e Mon Sep 17 00:00:00 2001 From: Norm Johanson Date: Sat, 5 Apr 2025 09:48:43 -0700 Subject: [PATCH 4/4] Add git ignore for launchsettings.json --- .gitignore | 2 ++ .../WebCalculatorFunctions/WebCalculatorFunctions.csproj | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 2b15a09..3226850 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ *.userosscache *.sln.docstates +playground/**/launchSettings.json + # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs diff --git a/playground/Lambda/WebCalculatorFunctions/WebCalculatorFunctions.csproj b/playground/Lambda/WebCalculatorFunctions/WebCalculatorFunctions.csproj index 545d09b..70f0119 100644 --- a/playground/Lambda/WebCalculatorFunctions/WebCalculatorFunctions.csproj +++ b/playground/Lambda/WebCalculatorFunctions/WebCalculatorFunctions.csproj @@ -18,4 +18,7 @@ + + + \ No newline at end of file