From 0674123fcd9186f0f2fb3594b7260ad5aeee2a7e Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Thu, 20 Mar 2025 10:27:48 -0400 Subject: [PATCH 1/8] Update sample apps --- .../LambdaMessaging/HandlerSampleRequest.json | 20 +++++++++++++++++++ .../LambdaMessaging/LambdaMessaging.csproj | 9 +++------ .../Properties/launchSettings.json | 13 +++++++----- sampleapps/LambdaMessaging/Startup.cs | 18 ++++++++++------- .../LambdaMessaging/serverless.template | 4 ++-- 5 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 sampleapps/LambdaMessaging/HandlerSampleRequest.json diff --git a/sampleapps/LambdaMessaging/HandlerSampleRequest.json b/sampleapps/LambdaMessaging/HandlerSampleRequest.json new file mode 100644 index 00000000..e48166d4 --- /dev/null +++ b/sampleapps/LambdaMessaging/HandlerSampleRequest.json @@ -0,0 +1,20 @@ +{ + "Records": [ + { + "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", + "receiptHandle": "MessageReceiptHandle", + "body": "{\"id\":\"d9b4bfc7-9398-44aa-8049-85c07490fb35\",\"source\":\"/AWSLambda/FunctionName\",\"specversion\":\"1.0\",\"type\":\"ChatMessage\",\"time\":\"2024-03-22T21:01:03.5484607+00:00\",\"data\":\"{\\u0022MessageDescription\\u0022:\\u0022value2\\u0022}\"}", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1523232000000", + "SenderId": "123456789012", + "ApproximateFirstReceiveTimestamp": "1523232000001" + }, + "messageAttributes": {}, + "md5OfBody": "7b270e59b47ff90a553787216d55d91d", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:{partition}:sqs:{region}:123456789012:MyQueue", + "awsRegion": "{region}" + } + ] +} diff --git a/sampleapps/LambdaMessaging/LambdaMessaging.csproj b/sampleapps/LambdaMessaging/LambdaMessaging.csproj index d1a946f0..c5ce35c0 100644 --- a/sampleapps/LambdaMessaging/LambdaMessaging.csproj +++ b/sampleapps/LambdaMessaging/LambdaMessaging.csproj @@ -1,22 +1,19 @@ - net6.0 + net8.0 enable enable true Lambda - true true - + - - - + diff --git a/sampleapps/LambdaMessaging/Properties/launchSettings.json b/sampleapps/LambdaMessaging/Properties/launchSettings.json index a82d4042..99072c4a 100644 --- a/sampleapps/LambdaMessaging/Properties/launchSettings.json +++ b/sampleapps/LambdaMessaging/Properties/launchSettings.json @@ -1,10 +1,13 @@ { "profiles": { - "Mock Lambda Test Tool": { + "LambdaRuntimeClient_FunctionHandler": { + "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", "commandName": "Executable", - "commandLineArgs": "--port 5050", - "workingDirectory": ".\\bin\\$(Configuration)\\net6.0", - "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe" + "commandLineArgs": "exec --depsfile ./LambdaMessaging.deps.json --runtimeconfig ./LambdaMessaging.runtimeconfig.json %USERPROFILE%/.dotnet/tools/.store/amazon.lambda.testtool/0.9.1/amazon.lambda.testtool/0.9.1/content/Amazon.Lambda.RuntimeSupport/net8.0/Amazon.Lambda.RuntimeSupport.dll LambdaMessaging::LambdaMessaging.Function_FunctionHandler_Generated::FunctionHandler", + "executablePath": "dotnet", + "environmentVariables": { + "AWS_LAMBDA_RUNTIME_API": "localhost:5050/MyFunction" + } } } -} \ No newline at end of file +} diff --git a/sampleapps/LambdaMessaging/Startup.cs b/sampleapps/LambdaMessaging/Startup.cs index 3958e72d..85bb937e 100644 --- a/sampleapps/LambdaMessaging/Startup.cs +++ b/sampleapps/LambdaMessaging/Startup.cs @@ -1,5 +1,6 @@ using Amazon.Lambda.Annotations; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace LambdaMessaging; @@ -7,21 +8,24 @@ namespace LambdaMessaging; [LambdaStartup] public class Startup { - public void ConfigureServices(IServiceCollection services) + public HostApplicationBuilder ConfigureHostBuilder() { - services.AddLogging(builder => + var builder = new HostApplicationBuilder(); + builder.Services.AddLogging(b => { - builder.SetMinimumLevel(LogLevel.Trace); - builder.AddLambdaLogger(); + b.SetMinimumLevel(LogLevel.Trace); + b.AddLambdaLogger(); }); - services.AddAWSMessageBus(builder => + builder.Services.AddAWSMessageBus(b => { - builder.AddMessageHandler("chatMessage"); + b.AddMessageHandler("chatMessage"); - builder.AddLambdaMessageProcessor(options => + b.AddLambdaMessageProcessor(options => { options.MaxNumberOfConcurrentMessages = 2; }); }); + + return builder; } } diff --git a/sampleapps/LambdaMessaging/serverless.template b/sampleapps/LambdaMessaging/serverless.template index 1fdee3f4..8881b851 100644 --- a/sampleapps/LambdaMessaging/serverless.template +++ b/sampleapps/LambdaMessaging/serverless.template @@ -1,7 +1,7 @@ { "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::Serverless-2016-10-31", - "Description": "This template is partially managed by Amazon.Lambda.Annotations (v1.0.0.0).", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v1.7.0.0).", "Resources": { "ChatQueue": { "Type": "AWS::SQS::Queue", @@ -13,7 +13,7 @@ "Tool": "Amazon.Lambda.Annotations" }, "Properties": { - "Runtime": "dotnet6", + "Runtime": "dotnet8", "CodeUri": ".", "MemorySize": 256, "Timeout": 30, From 7d44c76d46df1cfb76c72842cfe219ddb703ce46 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Thu, 20 Mar 2025 11:28:21 -0400 Subject: [PATCH 2/8] update readme --- .../LambdaMessaging/HandlerSampleRequest.json | 2 +- sampleapps/LambdaMessaging/README.md | 55 +++++++++++++++++++ sampleapps/PollyIntegration/README.md | 0 sampleapps/PublisherAPI/README.md | 1 + sampleapps/SubscriberService/README.md | 1 + src/AWS.Messaging.Lambda/README.md | 8 ++- 6 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 sampleapps/LambdaMessaging/README.md create mode 100644 sampleapps/PollyIntegration/README.md create mode 100644 sampleapps/PublisherAPI/README.md create mode 100644 sampleapps/SubscriberService/README.md diff --git a/sampleapps/LambdaMessaging/HandlerSampleRequest.json b/sampleapps/LambdaMessaging/HandlerSampleRequest.json index e48166d4..91602565 100644 --- a/sampleapps/LambdaMessaging/HandlerSampleRequest.json +++ b/sampleapps/LambdaMessaging/HandlerSampleRequest.json @@ -3,7 +3,7 @@ { "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", "receiptHandle": "MessageReceiptHandle", - "body": "{\"id\":\"d9b4bfc7-9398-44aa-8049-85c07490fb35\",\"source\":\"/AWSLambda/FunctionName\",\"specversion\":\"1.0\",\"type\":\"ChatMessage\",\"time\":\"2024-03-22T21:01:03.5484607+00:00\",\"data\":\"{\\u0022MessageDescription\\u0022:\\u0022value2\\u0022}\"}", + "body": "{\"id\":\"d9b4bfc7-9398-44aa-8049-85c07490fb35\",\"source\":\"/AWSLambda/FunctionName\",\"specversion\":\"1.0\",\"type\":\"chatMessage\",\"time\":\"2024-03-22T21:01:03.5484607+00:00\",\"data\":\"{\\u0022MessageDescription\\u0022:\\u0022Testing!!!\\u0022}\"}", "attributes": { "ApproximateReceiveCount": "1", "SentTimestamp": "1523232000000", diff --git a/sampleapps/LambdaMessaging/README.md b/sampleapps/LambdaMessaging/README.md new file mode 100644 index 00000000..ab257f59 --- /dev/null +++ b/sampleapps/LambdaMessaging/README.md @@ -0,0 +1,55 @@ +# Lambda Messaging Sample Application + +This sample application demonstrates how to use AWS Lambda with the AWS Message Processing Framework for .NET to process messages from SQS queues. + +## Overview + +This sample shows how to: +- Configure a Lambda function to process messages from SQS +- Use dependency injection with Lambda Annotations +- Handle message batch processing +- Implement partial batch failure responses +- Set up message handlers for specific message types + +## Prerequisites + +- .NET 8.0 or later + + +## Project Structure + +``` +LambdaMessaging/ +├── Function.cs # Lambda function handler +├── Startup.cs # DI and service configuration +├── ChatMessage.cs # Message type definition +├── ChatMessageHandler.cs # Message handler implementation +├── serverless.template # AWS SAM template +├── LambdaMessaging.csproj # Project file +``` + + +## Getting Started + +In order to test the lambda function locally with the messaging processing framework, it requires installing the Lambda Test Tool https://github.com/aws/aws-lambda-dotnet/blob/master/Tools/LambdaTestTool-v2 first. + +1. Install the AWS Lambda Test Tool: +```bash +dotnet tool install -g amazon.lambda.testtool +``` + +2. Start the Lambda Test Tool: + +```bash +dotnet lambda-test-tool start --lambda-emulator-port 5050 +``` + +3. Update the `Properties/launchSettings.json` file to contain the test tools's current version. You can determine the test tool's version by running `dotnet lambda-test-tool info`. + +4. Run the `LambdaMessaging` project. // TODO come back to this + +5. You should now see the `MyFunction` appear in the test tools function list drop down in the top right corner. Select `MyFunction`. + +6. We have provided a `HandlerSampleRequest.json` file to be used to test this function. Copy and paste this json into the test tools input window and then hit the "invoke button". + +7. You should see in the console window that the `ChatMessageHandler` successfully processed the message. There should be a log statement saying `Message Description: Testing!!!`. diff --git a/sampleapps/PollyIntegration/README.md b/sampleapps/PollyIntegration/README.md new file mode 100644 index 00000000..e69de29b diff --git a/sampleapps/PublisherAPI/README.md b/sampleapps/PublisherAPI/README.md new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/sampleapps/PublisherAPI/README.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/sampleapps/SubscriberService/README.md b/sampleapps/SubscriberService/README.md new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/sampleapps/SubscriberService/README.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/AWS.Messaging.Lambda/README.md b/src/AWS.Messaging.Lambda/README.md index c5bb8461..757caff7 100644 --- a/src/AWS.Messaging.Lambda/README.md +++ b/src/AWS.Messaging.Lambda/README.md @@ -22,9 +22,11 @@ Publishers can also be configured if you expect the Lambda function to publish m [LambdaStartup] public class Startup { - public void ConfigureServices(IServiceCollection services) + public HostApplicationBuilder ConfigureHostBuilder() { - services.AddAWSMessageBus(builder => + var hostBuilder = new HostApplicationBuilder(); + + hostBuilder.Services.AddAWSMessageBus(builder => { builder.AddMessageHandler(); @@ -33,6 +35,8 @@ public class Startup options.MaxNumberOfConcurrentMessages = 4; }); }); + + return hostBuilder; } } ``` From 5e6da1a796eea3bbba7bbb1c64539c20a4d79419 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Fri, 21 Mar 2025 10:00:54 -0400 Subject: [PATCH 3/8] update deps --- sampleapps/PollyIntegration/PollyIntegration.csproj | 6 +++--- sampleapps/PublisherAPI/PublisherAPI.csproj | 8 ++++---- .../SubscriberService/SubscriberService.csproj | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sampleapps/PollyIntegration/PollyIntegration.csproj b/sampleapps/PollyIntegration/PollyIntegration.csproj index 11b14630..1546d67e 100644 --- a/sampleapps/PollyIntegration/PollyIntegration.csproj +++ b/sampleapps/PollyIntegration/PollyIntegration.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 enable enable @@ -18,8 +18,8 @@ - - + + diff --git a/sampleapps/PublisherAPI/PublisherAPI.csproj b/sampleapps/PublisherAPI/PublisherAPI.csproj index 9d9f42c5..91a45c77 100644 --- a/sampleapps/PublisherAPI/PublisherAPI.csproj +++ b/sampleapps/PublisherAPI/PublisherAPI.csproj @@ -1,15 +1,15 @@ - net6.0 + net8.0 enable enable - - - + + + diff --git a/sampleapps/SubscriberService/SubscriberService.csproj b/sampleapps/SubscriberService/SubscriberService.csproj index de382e3b..85f8ef5e 100644 --- a/sampleapps/SubscriberService/SubscriberService.csproj +++ b/sampleapps/SubscriberService/SubscriberService.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 enable enable @@ -16,12 +16,12 @@ PreserveNewest - + - - - - + + + + From 0339d9c491dc6b2c9ba0f4a22fb59bf0af81797a Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Fri, 21 Mar 2025 12:27:06 -0400 Subject: [PATCH 4/8] more readmes --- sampleapps/LambdaMessaging/README.md | 1 - sampleapps/PollyIntegration/README.md | 177 +++++++++++++++++++++ sampleapps/PublisherAPI/README.md | 210 ++++++++++++++++++++++++- sampleapps/README.md | 34 ++++ sampleapps/SubscriberService/README.md | 161 ++++++++++++++++++- 5 files changed, 580 insertions(+), 3 deletions(-) create mode 100644 sampleapps/README.md diff --git a/sampleapps/LambdaMessaging/README.md b/sampleapps/LambdaMessaging/README.md index ab257f59..f3c88cb6 100644 --- a/sampleapps/LambdaMessaging/README.md +++ b/sampleapps/LambdaMessaging/README.md @@ -24,7 +24,6 @@ LambdaMessaging/ ├── Startup.cs # DI and service configuration ├── ChatMessage.cs # Message type definition ├── ChatMessageHandler.cs # Message handler implementation -├── serverless.template # AWS SAM template ├── LambdaMessaging.csproj # Project file ``` diff --git a/sampleapps/PollyIntegration/README.md b/sampleapps/PollyIntegration/README.md index e69de29b..79fc4d8f 100644 --- a/sampleapps/PollyIntegration/README.md +++ b/sampleapps/PollyIntegration/README.md @@ -0,0 +1,177 @@ +# AWS Message Processing Framework with Polly Integration + +This sample application demonstrates how to use the AWS Message Processing Framework for .NET with Polly for resilient message processing. It showcases integration between SQS message processing and Polly's retry policies. + +## Overview + +This sample demonstrates: +- Integration of AWS Message Processing Framework with Polly for resilient messaging +- Custom backoff handling for message processing +- SQS message processing with typed handlers +- OpenTelemetry integration for observability +- Both code-based and configuration-based setup options + +## Prerequisites + +- .NET 8.0 or later +- AWS Account with appropriate permissions +- Basic understanding of Amazon SQS and AWS Message Processing Framework + +## Setup + +### 1. Create an SQS Queue + +1. Open the AWS Management Console +2. Navigate to Amazon SQS +3. Click "Create Queue" +4. Choose "Standard Queue" +5. Enter a queue name (e.g., "MPF") +6. Keep default settings for this demo +7. Click "Create Queue" +8. Copy the Queue URL - you'll need this later + +### 2. Configure Message Processing + +You can choose either configuration approach: + +#### Option A: Code-based Configuration + +In `Program.cs`, update the queue URL and keep these lines uncommented: +```csharp +builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MPF"); // Replace with your Queue URL +builder.AddMessageHandler("chatMessage"); +``` +And keep this line commented: +``` +// builder.LoadConfigurationFromSettings(context.Configuration); +``` + +#### Option B: Configuration-based (appsettings.json) +1. Comment out the code-based configuration in Program.cs: + +``` +// builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MPF"); +// builder.AddMessageHandler("chatMessage"); +``` +2. Uncomment the configuration loading: + +``` +builder.LoadConfigurationFromSettings(context.Configuration); +``` +3. Update appsettings.json: + +``` +{ + "AWS.Messaging": { + "SQSPollers": [ + { + "QueueUrl": "https://sqs.us-west-2.amazonaws.com/012345678910/MPF" // Replace with your Queue URL + } + ], + "MessageHandlers": [ + { + "HandlerType": "PollyIntegration.MessageHandlers.ChatMessageHandler", + "MessageType": "PollyIntegration.Models.ChatMessage", + "MessageTypeIdentifier": "chatMessage" + } + ] + } +} + +``` + +Choose Option A if you: + +- Want configuration close to the code + +- Need dynamic runtime configuration + +- Are prototyping or testing + + +Choose Option B if you: + +- Need configuration changes without recompiling + +- Want environment-specific settings + +- Prefer separation of configuration from code + +- Need to manage multiple configurations + + +### 3. Configure AWS Credentials + +Ensure you have AWS credentials configured either through: + +- AWS CLI (  + + ```plaintext + aws configure + ``` + + ) + +- Environment variables + +- AWS credentials file + +- IAM role (if running on AWS) + +## Project Structure +PollyIntegration/ +├── MessageHandlers/ +│ └── ChatMessageHandler.cs # Sample message handler +├── Models/ +│ └── ChatMessage.cs # Message type definition +├── Program.cs # Application entry point +├── PollyBackoffHandler.cs # Custom Polly integration +└── appsettings.json # Application configuration + +## Running the Application +1. Build the project +``` +dotnet build +``` +2. Run the application +``` +dotnet run +``` +## Testing + +### Send a Test Message + +You can send a test message to your SQS queue using the AWS Console or AWS CLI: + +Using AWS CLI: +``` +aws sqs send-message \ + --queue-url YOUR_QUEUE_URL \ + --message-body '{ + "type": "chatMessage", + "id": "123", + "source": "test", + "specversion": "1.0", + "time": "2024-01-01T00:00:00Z", + "data": { + "messageDescription": "Test message" + } + }' + +``` +Replace YOUR_QUEUE_URL with your actual SQS queue URL. + +## Additional Configuration Options + +### Polly Backoff Configuration +``` +{ + "AWS.Messaging": { + "BackoffPolicy": "CappedExponential", + "CappedExponentialBackoffOptions": { + "CapBackoffTime": 2 + } + } +} + +``` diff --git a/sampleapps/PublisherAPI/README.md b/sampleapps/PublisherAPI/README.md index 5f282702..36c5d034 100644 --- a/sampleapps/PublisherAPI/README.md +++ b/sampleapps/PublisherAPI/README.md @@ -1 +1,209 @@ - \ No newline at end of file +# AWS Message Processing Framework Publisher API Sample + +This sample application demonstrates how to use the AWS Message Processing Framework for .NET to publish messages to different AWS messaging services (SQS, SNS, and EventBridge). + +## Overview + +This sample demonstrates: +- Publishing messages to SQS queues (standard and FIFO) +- Publishing messages to SNS topics (standard and FIFO) +- Publishing messages to EventBridge +- Configuration-based and code-based setup options +- Handling service-specific message options + +## Prerequisites + +- .NET 8.0 or later +- AWS Account with appropriate permissions +- Basic understanding of AWS messaging services (SQS, SNS, EventBridge) + +## Setup + +### 1. Create AWS Resources + +#### SQS Queues +1. Create a standard SQS queue named "MPF" +2. Create a FIFO SQS queue named "MPF.fifo" +3. Note the queue URLs + +#### SNS Topics +1. Create a standard SNS topic named "MPF" +2. Create a FIFO SNS topic named "MPF.fifo" +3. Note the topic ARNs + +#### EventBridge +1. Note your default event bus ARN or create a custom event bus + +### 2. Configure Message Publishing + +You can choose either configuration approach: + +#### Option A: Code-based Configuration + +In `Program.cs`, update the endpoints and keep these lines uncommented: +```csharp +bus.AddSQSPublisher("https://sqs.us-west-2.amazonaws.com/012345678910/MPF", "chatMessage"); +bus.AddSNSPublisher("arn:aws:sns:us-west-2:012345678910:MPF", "orderInfo"); +bus.AddEventBridgePublisher("arn:aws:events:us-west-2:012345678910:event-bus/default", "foodItem"); + +// FIFO endpoints +bus.AddSQSPublisher("https://sqs.us-west-2.amazonaws.com/012345678910/MPF.fifo", "transactionInfo"); +bus.AddSNSPublisher("arn:aws:sns:us-west-2:012345678910:MPF.fifo", "bidInfo"); +``` +And keep this line commented: + +``` +// bus.LoadConfigurationFromSettings(builder.Configuration); +``` +#### Option B: Configuration-based (appsettings.json) + +1. Comment out the code-based configuration in Program.cs + +2. Uncomment the configuration loading: +``` +bus.LoadConfigurationFromSettings(builder.Configuration); +``` +3. Update appsettings.json: + +``` +{ + "AWS.Messaging": { + "SQSPublishers": [ + { + "MessageType": "PublisherAPI.Models.ChatMessage", + "QueueUrl": "https://sqs.us-west-2.amazonaws.com/012345678910/MPF", + "MessageTypeIdentifier": "chatMessage" + }, + { + "MessageType": "PublisherAPI.Models.TransactionInfo", + "QueueUrl": "https://sqs.us-west-2.amazonaws.com/012345678910/MPF.fifo", + "MessageTypeIdentifier": "transactionInfo" + } + ], + "SNSPublishers": [ + { + "MessageType": "PublisherAPI.Models.OrderInfo", + "TopicUrl": "arn:aws:sns:us-west-2:012345678910:MPF", + "MessageTypeIdentifier": "orderInfo" + }, + { + "MessageType": "PublisherAPI.Models.BidInfo", + "TopicUrl": "arn:aws:sns:us-west-2:012345678910:MPF.fifo", + "MessageTypeIdentifier": "bidInfo" + } + ], + "EventBridgePublishers": [ + { + "MessageType": "PublisherAPI.Models.FoodItem", + "EventBusName": "arn:aws:events:us-west-2:012345678910:event-bus/default", + "MessageTypeIdentifier": "foodItem" + } + ] + } +} + +``` +### 3. Configure AWS Credentials + +Ensure you have AWS credentials configured either through: + +- AWS CLI + +- Environment variables + +- AWS credentials file + +- IAM role (if running on AWS) + +## Project Structure + +``` +PublisherAPI/ +├── Controllers/ +│ └── PublisherController.cs # API endpoints for publishing +├── Models/ +│ ├── ChatMessage.cs # Standard queue message +│ ├── TransactionInfo.cs # FIFO queue message +│ ├── OrderInfo.cs # Standard topic message +│ ├── BidInfo.cs # FIFO topic message +│ └── FoodItem.cs # EventBridge message +├── Program.cs # Application entry point +└── appsettings.json # Application configuration + +``` + +## Running the Application + +1. Build the project: + + +```bash +dotnet build +``` + +2. Run the application: + + +```bash +dotnet run +``` + + +## Testing +The API includes Swagger UI for testing. Access it at: + +``` +https://localhost:7204/swagger +``` +### Example API Requests + +#### Send Chat Message (Standard SQS): +``` +POST /Publisher/chatmessage +Content-Type: application/json + +{ + "messageDescription": "Hello World!" +} +``` + +#### Send Transaction (FIFO SQS): +``` +POST /Publisher/transactioninfo +Content-Type: application/json + +{ + "transactionId": "123" +} +``` +#### Send Order (Standard SNS): +``` +POST /Publisher/order +Content-Type: application/json + +{ + "orderId": "456", + "userId": "user123" +} +``` +#### Send Bid (FIFO SNS): +``` +POST /Publisher/bidinfo +Content-Type: application/json + +{ + "bidId": "789" +} + +``` + +#### Send Food Item (EventBridge): +``` +POST /Publisher/fooditem +Content-Type: application/json + +{ + "id": 1, + "name": "Pizza" +} +``` \ No newline at end of file diff --git a/sampleapps/README.md b/sampleapps/README.md new file mode 100644 index 00000000..7a549a7d --- /dev/null +++ b/sampleapps/README.md @@ -0,0 +1,34 @@ +# AWS Message Processing Framework Sample Applications + +This directory contains sample applications demonstrating different aspects and use cases of the AWS Message Processing Framework for .NET. + +## Sample Projects + +### PublisherAPI +A REST API demonstrating how to publish messages to various AWS messaging services: +- Publishing to SQS (standard and FIFO queues) +- Publishing to SNS (standard and FIFO topics) +- Publishing to EventBridge +- Configuration-based and code-based setup options + +### SubscriberService +A service application showing how to process messages from SQS queues: +- Configurable SQS message polling +- Message handler implementation +- Backoff policies +- Configuration options for concurrent processing + +### PollyIntegration +Demonstrates integration with the Polly resilience library: +- Custom backoff handling +- Retry policies +- Circuit breaker patterns +- Integration with message processing + +### LambdaMessaging +Shows how to use the framework with AWS Lambda: +- Lambda function configuration +- SQS event processing +- Batch message handling +- Partial batch failures +- Dependency injection with Lambda Annotations diff --git a/sampleapps/SubscriberService/README.md b/sampleapps/SubscriberService/README.md index 5f282702..70f3a743 100644 --- a/sampleapps/SubscriberService/README.md +++ b/sampleapps/SubscriberService/README.md @@ -1 +1,160 @@ - \ No newline at end of file +# AWS Message Processing Framework Subscriber Service Sample + +This sample application demonstrates how to use the AWS Message Processing Framework for .NET to process messages from SQS queues with configurable polling and message handling. + +## Overview + +This sample demonstrates: +- Configuring and using SQS message pollers +- Implementing typed message handlers +- Configuration-based and code-based setup options +- OpenTelemetry integration for observability +- Configurable backoff policies for message processing +- Proper message handling patterns + +## Prerequisites + +- .NET 8.0 or later +- AWS Account with appropriate permissions +- Basic understanding of Amazon SQS and message processing + +## Setup + +### 1. Create AWS Resources + +#### SQS Queue +1. Open the AWS Management Console +2. Navigate to Amazon SQS +3. Click "Create Queue" +4. Choose "Standard Queue" +5. Enter a queue name (e.g., "MPF") +6. Keep default settings for this demo +7. Click "Create Queue" +8. Copy the Queue URL - you'll need this later + +### 2. Configure Message Processing + +You can choose either configuration approach: + +#### Option A: Code-based Configuration + +In `Program.cs`, update the queue URL and keep these lines uncommented: +```csharp +builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MPF"); +builder.AddMessageHandler("chatMessage"); +``` +And keep this line commented: + +``` +// builder.LoadConfigurationFromSettings(context.Configuration); +``` +#### Option B: Configuration-based (appsettings.json) + +1. Comment out the code-based configuration in Program.cs +2. Uncomment the configuration loading: +``` +builder.LoadConfigurationFromSettings(context.Configuration); +``` +3. Update appsettings.json: +``` +{ + "AWS.Messaging": { + "MessageHandlers": [ + { + "HandlerType": "SubscriberService.MessageHandlers.ChatMessageHandler", + "MessageType": "SubscriberService.Models.ChatMessage", + "MessageTypeIdentifier": "chatMessage" + } + ], + "SQSPollers": [ + { + "QueueUrl": "https://sqs.us-west-2.amazonaws.com/012345678910/MPF", + "Options": { + "MaxNumberOfConcurrentMessages": 10, + "VisibilityTimeout": 20, + "WaitTimeSeconds": 20, + "VisibilityTimeoutExtensionHeartbeatInterval": 1, + "VisibilityTimeoutExtensionThreshold": 5 + } + } + ], + "BackoffPolicy": "CappedExponential" + } +} +``` + +### 3. Configure AWS Credentials + +Ensure you have AWS credentials configured either through: + +- AWS CLI + +- Environment variables + +- AWS credentials file + +- IAM role (if running on AWS) + + +## Project Structure +``` +SubscriberService/ +├── MessageHandlers/ +│ └── ChatMessageHandler.cs # Message handler implementation +├── Models/ +│ └── ChatMessage.cs # Message type definition +├── Program.cs # Application entry point +└── appsettings.json # Application configuration +``` + +## Running the Application + +1. Build the project: +``` +dotnet build +``` +2. Run the application: +``` +dotnet run +``` + +## Testing + +You can test the service by sending messages to the SQS queue using the AWS Console, AWS CLI, or the companion PublisherAPI project. + +### Using AWS CLI: +``` +aws sqs send-message \ + --queue-url YOUR_QUEUE_URL \ + --message-body '{ + "type": "chatMessage", + "id": "123", + "source": "test", + "specversion": "1.0", + "time": "2024-01-01T00:00:00Z", + "data": { + "messageDescription": "Test message" + } + }' +``` + +## Configuration Options +``` +{ + "MaxNumberOfConcurrentMessages": 10, // Maximum number of messages to process concurrently + "VisibilityTimeout": 20, // Time (in seconds) that a message is invisible after being received + "WaitTimeSeconds": 20, // Long polling duration + "VisibilityTimeoutExtensionHeartbeatInterval": 1, // How often to extend visibility timeout + "VisibilityTimeoutExtensionThreshold": 5 // When to extend visibility timeout +} +``` +### Backoff Policy Options +``` +{ + "BackoffPolicy": "CappedExponential", // Available options: Linear, Exponential, CappedExponential + "CappedExponentialBackoffOptions": { + "CapBackoffTime": 60 // Maximum backoff time in seconds + } +} +``` + From 7b1adcd47fe5e2ba08976c7688628f429e7e8a0f Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Fri, 21 Mar 2025 13:10:41 -0400 Subject: [PATCH 5/8] launch profile --- sampleapps/LambdaMessaging/Properties/launchSettings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sampleapps/LambdaMessaging/Properties/launchSettings.json b/sampleapps/LambdaMessaging/Properties/launchSettings.json index 99072c4a..44a5eb71 100644 --- a/sampleapps/LambdaMessaging/Properties/launchSettings.json +++ b/sampleapps/LambdaMessaging/Properties/launchSettings.json @@ -1,6 +1,6 @@ { "profiles": { - "LambdaRuntimeClient_FunctionHandler": { + "Default": { "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", "commandName": "Executable", "commandLineArgs": "exec --depsfile ./LambdaMessaging.deps.json --runtimeconfig ./LambdaMessaging.runtimeconfig.json %USERPROFILE%/.dotnet/tools/.store/amazon.lambda.testtool/0.9.1/amazon.lambda.testtool/0.9.1/content/Amazon.Lambda.RuntimeSupport/net8.0/Amazon.Lambda.RuntimeSupport.dll LambdaMessaging::LambdaMessaging.Function_FunctionHandler_Generated::FunctionHandler", @@ -10,4 +10,4 @@ } } } -} +} \ No newline at end of file From 2af9f3fce1a8cdd69882e8e11b672ac77dda33dd Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Fri, 21 Mar 2025 13:48:57 -0400 Subject: [PATCH 6/8] update readme --- .../Properties/launchSettings.json | 2 +- sampleapps/LambdaMessaging/README.md | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/sampleapps/LambdaMessaging/Properties/launchSettings.json b/sampleapps/LambdaMessaging/Properties/launchSettings.json index 44a5eb71..1712041f 100644 --- a/sampleapps/LambdaMessaging/Properties/launchSettings.json +++ b/sampleapps/LambdaMessaging/Properties/launchSettings.json @@ -3,7 +3,7 @@ "Default": { "workingDirectory": ".\\bin\\$(Configuration)\\net8.0", "commandName": "Executable", - "commandLineArgs": "exec --depsfile ./LambdaMessaging.deps.json --runtimeconfig ./LambdaMessaging.runtimeconfig.json %USERPROFILE%/.dotnet/tools/.store/amazon.lambda.testtool/0.9.1/amazon.lambda.testtool/0.9.1/content/Amazon.Lambda.RuntimeSupport/net8.0/Amazon.Lambda.RuntimeSupport.dll LambdaMessaging::LambdaMessaging.Function_FunctionHandler_Generated::FunctionHandler", + "commandLineArgs": "exec --depsfile ./LambdaMessaging.deps.json --runtimeconfig ./LambdaMessaging.runtimeconfig.json %USERPROFILE%/.dotnet/tools/.store/amazon.lambda.testtool/${VERSION}/amazon.lambda.testtool/${VERSION}/content/Amazon.Lambda.RuntimeSupport/net8.0/Amazon.Lambda.RuntimeSupport.dll LambdaMessaging::LambdaMessaging.Function_FunctionHandler_Generated::FunctionHandler", "executablePath": "dotnet", "environmentVariables": { "AWS_LAMBDA_RUNTIME_API": "localhost:5050/MyFunction" diff --git a/sampleapps/LambdaMessaging/README.md b/sampleapps/LambdaMessaging/README.md index f3c88cb6..636e8a47 100644 --- a/sampleapps/LambdaMessaging/README.md +++ b/sampleapps/LambdaMessaging/README.md @@ -43,9 +43,28 @@ dotnet tool install -g amazon.lambda.testtool dotnet lambda-test-tool start --lambda-emulator-port 5050 ``` -3. Update the `Properties/launchSettings.json` file to contain the test tools's current version. You can determine the test tool's version by running `dotnet lambda-test-tool info`. +3. Get the test tool version: -4. Run the `LambdaMessaging` project. // TODO come back to this +``` +dotnet lambda-test-tool info +``` + +4. Run the `LambdaMessaging` project. + +There are 2 ways to run it +1. Visual studio (easiest way). + 1a. Update `Properties/launchSettings.json` and replace `${VERSIOMN} with the actual test tool version. +2. Via command line + +``` +cd bin\Debug\net8.0 +$env:AWS_LAMBDA_RUNTIME_API = "localhost:5050/MyFunction" +$env:VERSION = "0.9.1" // Use the version returned from dotnet lambda-test-tool info + +dotnet exec --depsfile ./LambdaMessaging.deps.json --runtimeconfig ./LambdaMessaging.runtimeconfig.json "$env:USERPROFILE\.dotnet\tools\.store\amazon.lambda.testtool\$env:VERSION\amazon.lambda.testtool\$env:VERSION\content\Amazon.Lambda.RuntimeSupport\net8.0\Amazon.Lambda.RuntimeSupport.dll" LambdaMessaging::LambdaMessaging.Function_FunctionHandler_Generated::FunctionHandler + + +``` 5. You should now see the `MyFunction` appear in the test tools function list drop down in the top right corner. Select `MyFunction`. From ff164e2a7f10a4f3805afbaa8450a6b6cfd5d417 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Fri, 21 Mar 2025 13:56:44 -0400 Subject: [PATCH 7/8] update readme --- sampleapps/LambdaMessaging/README.md | 22 ++++++---- sampleapps/PollyIntegration/README.md | 60 +++++++------------------- sampleapps/PublisherAPI/README.md | 20 ++++----- sampleapps/SubscriberService/README.md | 24 +++-------- 4 files changed, 47 insertions(+), 79 deletions(-) diff --git a/sampleapps/LambdaMessaging/README.md b/sampleapps/LambdaMessaging/README.md index 636e8a47..e6fe17aa 100644 --- a/sampleapps/LambdaMessaging/README.md +++ b/sampleapps/LambdaMessaging/README.md @@ -32,26 +32,32 @@ LambdaMessaging/ In order to test the lambda function locally with the messaging processing framework, it requires installing the Lambda Test Tool https://github.com/aws/aws-lambda-dotnet/blob/master/Tools/LambdaTestTool-v2 first. -1. Install the AWS Lambda Test Tool: +1. Build the project + +``` +dotnet build +``` + +2Install the AWS Lambda Test Tool: ```bash dotnet tool install -g amazon.lambda.testtool ``` -2. Start the Lambda Test Tool: +3. Start the Lambda Test Tool: ```bash dotnet lambda-test-tool start --lambda-emulator-port 5050 ``` -3. Get the test tool version: +4. Get the test tool version: ``` dotnet lambda-test-tool info ``` -4. Run the `LambdaMessaging` project. +5. Run the `LambdaMessaging` project. -There are 2 ways to run it +There are 2 ways to run it 1. Visual studio (easiest way). 1a. Update `Properties/launchSettings.json` and replace `${VERSIOMN} with the actual test tool version. 2. Via command line @@ -66,8 +72,8 @@ dotnet exec --depsfile ./LambdaMessaging.deps.json --runtimeconfig ./LambdaMessa ``` -5. You should now see the `MyFunction` appear in the test tools function list drop down in the top right corner. Select `MyFunction`. +6. You should now see the `MyFunction` appear in the test tools function list drop down in the top right corner. Select `MyFunction`. -6. We have provided a `HandlerSampleRequest.json` file to be used to test this function. Copy and paste this json into the test tools input window and then hit the "invoke button". +7. We have provided a `HandlerSampleRequest.json` file to be used to test this function. Copy and paste this json into the test tools input window and then hit the "invoke button". -7. You should see in the console window that the `ChatMessageHandler` successfully processed the message. There should be a log statement saying `Message Description: Testing!!!`. +8. You should see in the console window that the `ChatMessageHandler` successfully processed the message. There should be a log statement saying `Message Description: Testing!!!`. diff --git a/sampleapps/PollyIntegration/README.md b/sampleapps/PollyIntegration/README.md index 79fc4d8f..acfbb96f 100644 --- a/sampleapps/PollyIntegration/README.md +++ b/sampleapps/PollyIntegration/README.md @@ -8,7 +8,6 @@ This sample demonstrates: - Integration of AWS Message Processing Framework with Polly for resilient messaging - Custom backoff handling for message processing - SQS message processing with typed handlers -- OpenTelemetry integration for observability - Both code-based and configuration-based setup options ## Prerequisites @@ -83,42 +82,37 @@ builder.LoadConfigurationFromSettings(context.Configuration); Choose Option A if you: - Want configuration close to the code - + - Need dynamic runtime configuration - + - Are prototyping or testing - + Choose Option B if you: - Need configuration changes without recompiling - + - Want environment-specific settings - + - Prefer separation of configuration from code - + - Need to manage multiple configurations - + ### 3. Configure AWS Credentials Ensure you have AWS credentials configured either through: -- AWS CLI (  - - ```plaintext - aws configure - ``` - - ) - +- AWS CLI  + - Environment variables - + - AWS credentials file - + - IAM role (if running on AWS) ## Project Structure +``` PollyIntegration/ ├── MessageHandlers/ │ └── ChatMessageHandler.cs # Sample message handler @@ -127,6 +121,7 @@ PollyIntegration/ ├── Program.cs # Application entry point ├── PollyBackoffHandler.cs # Custom Polly integration └── appsettings.json # Application configuration +``` ## Running the Application 1. Build the project @@ -145,33 +140,10 @@ You can send a test message to your SQS queue using the AWS Console Using AWS CLI: ``` -aws sqs send-message \ - --queue-url YOUR_QUEUE_URL \ - --message-body '{ - "type": "chatMessage", - "id": "123", - "source": "test", - "specversion": "1.0", - "time": "2024-01-01T00:00:00Z", - "data": { - "messageDescription": "Test message" - } - }' -``` -Replace YOUR_QUEUE_URL with your actual SQS queue URL. +$messageBody = "{""""type"""":""""chatMessage"""",""""id"""":""""123"""",""""source"""":""""test"""",""""specversion"""":""""1.0"""",""""time"""":""""2024-01-01T00:00:00Z"""",""""data"""":""""{\\""""messageDescription\\"""":\\""""Test message\\""""}""""}" -## Additional Configuration Options - -### Polly Backoff Configuration -``` -{ - "AWS.Messaging": { - "BackoffPolicy": "CappedExponential", - "CappedExponentialBackoffOptions": { - "CapBackoffTime": 2 - } - } -} +aws sqs send-message --queue-url YOUR_QUEUE_URL --message-body $messageBody ``` +Replace YOUR_QUEUE_URL with your actual SQS queue URL. diff --git a/sampleapps/PublisherAPI/README.md b/sampleapps/PublisherAPI/README.md index 36c5d034..5cd789ce 100644 --- a/sampleapps/PublisherAPI/README.md +++ b/sampleapps/PublisherAPI/README.md @@ -23,12 +23,12 @@ This sample demonstrates: #### SQS Queues 1. Create a standard SQS queue named "MPF" -2. Create a FIFO SQS queue named "MPF.fifo" +2. Create a FIFO SQS queue named "MPF.fifo". When creating the queue be sure to enable `Content-based deduplication`. 3. Note the queue URLs #### SNS Topics 1. Create a standard SNS topic named "MPF" -2. Create a FIFO SNS topic named "MPF.fifo" +2. Create a FIFO SNS topic named "MPF.fifo". When creating the topic be sure to enable `Content-based deduplication`. 3. Note the topic ARNs #### EventBridge @@ -58,7 +58,7 @@ And keep this line commented: #### Option B: Configuration-based (appsettings.json) 1. Comment out the code-based configuration in Program.cs - + 2. Uncomment the configuration loading: ``` bus.LoadConfigurationFromSettings(builder.Configuration); @@ -108,11 +108,11 @@ bus.LoadConfigurationFromSettings(builder.Configuration); Ensure you have AWS credentials configured either through: - AWS CLI - + - Environment variables - + - AWS credentials file - + - IAM role (if running on AWS) ## Project Structure @@ -135,14 +135,14 @@ PublisherAPI/ ## Running the Application 1. Build the project: - + ```bash dotnet build ``` -2. Run the application: - +2. Run the application: + ```bash dotnet run @@ -206,4 +206,4 @@ Content-Type: application/json "id": 1, "name": "Pizza" } -``` \ No newline at end of file +``` diff --git a/sampleapps/SubscriberService/README.md b/sampleapps/SubscriberService/README.md index 70f3a743..b66ff68c 100644 --- a/sampleapps/SubscriberService/README.md +++ b/sampleapps/SubscriberService/README.md @@ -8,7 +8,6 @@ This sample demonstrates: - Configuring and using SQS message pollers - Implementing typed message handlers - Configuration-based and code-based setup options -- OpenTelemetry integration for observability - Configurable backoff policies for message processing - Proper message handling patterns @@ -88,13 +87,13 @@ builder.LoadConfigurationFromSettings(context.Configuration); Ensure you have AWS credentials configured either through: - AWS CLI - + - Environment variables - + - AWS credentials file - + - IAM role (if running on AWS) - + ## Project Structure ``` @@ -124,18 +123,9 @@ You can test the service by sending messages to the SQS queue using ### Using AWS CLI: ``` -aws sqs send-message \ - --queue-url YOUR_QUEUE_URL \ - --message-body '{ - "type": "chatMessage", - "id": "123", - "source": "test", - "specversion": "1.0", - "time": "2024-01-01T00:00:00Z", - "data": { - "messageDescription": "Test message" - } - }' +$messageBody = "{""""type"""":""""chatMessage"""",""""id"""":""""123"""",""""source"""":""""test"""",""""specversion"""":""""1.0"""",""""time"""":""""2024-01-01T00:00:00Z"""",""""data"""":""""{\\""""messageDescription\\"""":\\""""Test message\\""""}""""}" + +aws sqs send-message --queue-url YOUR_QUEUE_URL --message-body $messageBody ``` ## Configuration Options From bd8f983ee7bdb6fcf16510d76c854251cc83f637 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Mon, 24 Mar 2025 13:36:31 -0400 Subject: [PATCH 8/8] update package versions --- sampleapps/LambdaMessaging/LambdaMessaging.csproj | 2 +- sampleapps/PollyIntegration/PollyIntegration.csproj | 2 +- sampleapps/SubscriberService/SubscriberService.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sampleapps/LambdaMessaging/LambdaMessaging.csproj b/sampleapps/LambdaMessaging/LambdaMessaging.csproj index c5ce35c0..e735d8ab 100644 --- a/sampleapps/LambdaMessaging/LambdaMessaging.csproj +++ b/sampleapps/LambdaMessaging/LambdaMessaging.csproj @@ -13,7 +13,7 @@ - + diff --git a/sampleapps/PollyIntegration/PollyIntegration.csproj b/sampleapps/PollyIntegration/PollyIntegration.csproj index 1546d67e..7e356cdc 100644 --- a/sampleapps/PollyIntegration/PollyIntegration.csproj +++ b/sampleapps/PollyIntegration/PollyIntegration.csproj @@ -19,7 +19,7 @@ - + diff --git a/sampleapps/SubscriberService/SubscriberService.csproj b/sampleapps/SubscriberService/SubscriberService.csproj index 85f8ef5e..99f06212 100644 --- a/sampleapps/SubscriberService/SubscriberService.csproj +++ b/sampleapps/SubscriberService/SubscriberService.csproj @@ -19,7 +19,7 @@ - +