From 21c487cc1f131d504664ef12bee81c57590b8aab Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 00:15:47 +0100 Subject: [PATCH 01/24] fixing .net 8 minimal api --- loadtest/codebuild/load-test-buildspec.yml | 1 + loadtest/codebuild/run-all-load-tests.sh | 11 ++ .../ApiBootstrap/ApiBootstrap.csproj | 18 +-- .../ApiBootstrap/CloudWatchQueryExecution.cs | 51 -------- src/NET8MinimalAPI/ApiBootstrap/DateUtils.cs | 13 -- src/NET8MinimalAPI/ApiBootstrap/Function.cs | 53 ++------ .../ApiBootstrap/QueryResult.cs | 25 ---- src/NET8MinimalAPI/Makefile | 5 +- .../Report/load-test-report-arm64.json | 62 +++++++++ .../Report/load-test-report-arm64.txt | 18 +++ .../Report/load-test-report-x86.json | 62 +++++++++ .../Report/load-test-report-x86.txt | 18 +++ src/NET8MinimalAPI/Shared/Shared.csproj | 6 +- src/NET8MinimalAPI/deploy.sh | 2 + src/NET8MinimalAPI/omnisharp.json | 11 -- src/NET8MinimalAPI/run-loadtest.sh | 121 ++++++++++++++++++ src/NET8MinimalAPI/template.yaml | 66 +++++++--- 17 files changed, 369 insertions(+), 174 deletions(-) delete mode 100644 src/NET8MinimalAPI/ApiBootstrap/CloudWatchQueryExecution.cs delete mode 100644 src/NET8MinimalAPI/ApiBootstrap/DateUtils.cs delete mode 100644 src/NET8MinimalAPI/ApiBootstrap/QueryResult.cs create mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.json create mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.txt create mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.json create mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.txt create mode 100755 src/NET8MinimalAPI/deploy.sh delete mode 100644 src/NET8MinimalAPI/omnisharp.json create mode 100755 src/NET8MinimalAPI/run-loadtest.sh diff --git a/loadtest/codebuild/load-test-buildspec.yml b/loadtest/codebuild/load-test-buildspec.yml index d2c1e0f..af4fbcb 100644 --- a/loadtest/codebuild/load-test-buildspec.yml +++ b/loadtest/codebuild/load-test-buildspec.yml @@ -13,4 +13,5 @@ artifacts: files: - src/NET6MinimalAPI/Report/* - src/NET6MinimalAPIWebAdapter/Report/* + - src/NET8MinimalAPI/Report/* name: loadtest-$(date +%Y-%m-%H-%M) \ No newline at end of file diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index 1076019..94cfc22 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -37,3 +37,14 @@ else source ./deploy.sh source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVALL_MIN $LOG_DELETE fi + +#export LT_NET6_MINIMAL_API_WEB_ADAPTER=1 +if [ x"${LT_NET8_MINIMAL_API}" == "x" ]; +then + echo SKIPPING net8 minimal api :$LT_NET8_MINIMAL_API +else + echo "RUNNING load test for net8 minimal api" + cd ../../src/NET8MinimalAPI/ + source ./deploy.sh + source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVALL_MIN $LOG_DELETE +fi diff --git a/src/NET8MinimalAPI/ApiBootstrap/ApiBootstrap.csproj b/src/NET8MinimalAPI/ApiBootstrap/ApiBootstrap.csproj index cf7e8a5..c3879a4 100644 --- a/src/NET8MinimalAPI/ApiBootstrap/ApiBootstrap.csproj +++ b/src/NET8MinimalAPI/ApiBootstrap/ApiBootstrap.csproj @@ -5,7 +5,7 @@ net8.0 true Lambda - bootstrap + bootstrap true false true @@ -15,14 +15,14 @@ - - - - - - - - + + + + + + + + diff --git a/src/NET8MinimalAPI/ApiBootstrap/CloudWatchQueryExecution.cs b/src/NET8MinimalAPI/ApiBootstrap/CloudWatchQueryExecution.cs deleted file mode 100644 index 23b847f..0000000 --- a/src/NET8MinimalAPI/ApiBootstrap/CloudWatchQueryExecution.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Amazon.CloudWatchLogs; -using Amazon.CloudWatchLogs.Model; -using Amazon.Lambda.Core; - -namespace GetProducts; - -public static class CloudWatchQueryExecution -{ - public static async Task>> RunQuery(AmazonCloudWatchLogsClient cloudWatchLogsClient) - { - var logGroupNamePrefix = - $"{Environment.GetEnvironmentVariable("LOG_GROUP_PREFIX")}{Environment.GetEnvironmentVariable("LAMBDA_ARCHITECTURE")}" - .Replace("_", "-"); - - var logGroupList = await cloudWatchLogsClient.DescribeLogGroupsAsync(new DescribeLogGroupsRequest() - { - LogGroupNamePrefix = logGroupNamePrefix, - }); - - var queryRes = await cloudWatchLogsClient.StartQueryAsync(new StartQueryRequest() - { - LogGroupNames = logGroupList.LogGroups.Select(p => p.LogGroupName).ToList(), - QueryString = - "filter @type=\"REPORT\" | fields greatest(@initDuration, 0) + @duration as duration, ispresent(@initDuration) as coldstart | stats count(*) as count, pct(duration, 50) as p50, pct(duration, 90) as p90, pct(duration, 99) as p99, max(duration) as max by coldstart", - StartTime = DateTime.Now.AddMinutes(-20).AsUnixTimestamp(), - EndTime = DateTime.Now.AsUnixTimestamp(), - }); - - QueryStatus currentQueryStatus = QueryStatus.Running; - List> finalResults = new List>(); - - while (currentQueryStatus == QueryStatus.Running || currentQueryStatus == QueryStatus.Scheduled) - { - var queryResults = await cloudWatchLogsClient.GetQueryResultsAsync(new GetQueryResultsRequest() - { - QueryId = queryRes.QueryId - }); - - currentQueryStatus = queryResults.Status; - finalResults = queryResults.Results; - - await Task.Delay(TimeSpan.FromSeconds(5)); - } - - return finalResults; - } -} \ No newline at end of file diff --git a/src/NET8MinimalAPI/ApiBootstrap/DateUtils.cs b/src/NET8MinimalAPI/ApiBootstrap/DateUtils.cs deleted file mode 100644 index 8a572e0..0000000 --- a/src/NET8MinimalAPI/ApiBootstrap/DateUtils.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace GetProducts; - -public static class DateUtils -{ - public static long AsUnixTimestamp(this DateTime date) - { - DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); - TimeSpan diff = date.ToUniversalTime() - origin; - return (long)Math.Floor(diff.TotalSeconds); - } -} \ No newline at end of file diff --git a/src/NET8MinimalAPI/ApiBootstrap/Function.cs b/src/NET8MinimalAPI/ApiBootstrap/Function.cs index a4cd497..10a82a7 100644 --- a/src/NET8MinimalAPI/ApiBootstrap/Function.cs +++ b/src/NET8MinimalAPI/ApiBootstrap/Function.cs @@ -4,7 +4,6 @@ using System.Text.Json; using Amazon.CloudWatchLogs; using Amazon.CloudWatchLogs.Model; -using GetProducts; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -14,6 +13,15 @@ using Shared.Models; var app = Startup.Build(args); +var basePath=Environment.GetEnvironmentVariable("DEMO_BASE_PATH"); +if(String.IsNullOrEmpty(basePath)) + app.Logger.LogInformation($"No BASE PATH specified"); +else +{ + app.Logger.LogInformation($"Using BASE PATH:{basePath}"); + app.UsePathBase(basePath); + app.UseRouting(); +} var dataAccess = app.Services.GetRequiredService(); @@ -37,7 +45,7 @@ { var id = context.Request.RouteValues["id"].ToString(); - app.Logger.LogInformation($"Received request to delete {id}"); + app.Logger.LogInformation($"Received request to delete {id} from the database"); var product = await dataAccess.GetProduct(id); @@ -123,45 +131,4 @@ await context.Response.WriteAsJsonAsync(product); }); -app.MapGet("/test-results", async (HttpContext context) => -{ - var resultRows = 0; - var queryCount = 0; - - List> finalResults = new List>(); - - while (resultRows < 2 || queryCount >= 3) - { - finalResults = await CloudWatchQueryExecution.RunQuery(cloudWatchClient); - - resultRows = finalResults.Count; - queryCount++; - } - - var wrapper = new QueryResultWrapper() - { - LoadTestType = - $"{Environment.GetEnvironmentVariable("LOAD_TEST_TYPE")} ({Environment.GetEnvironmentVariable("LAMBDA_ARCHITECTURE")})", - WarmStart = new QueryResult() - { - Count = finalResults[0][1].Value, - P50 = finalResults[0][2].Value, - P90 = finalResults[0][3].Value, - P99 = finalResults[0][4].Value, - Max = finalResults[0][5].Value, - }, - ColdStart = new QueryResult() - { - Count = finalResults[1][1].Value, - P50 = finalResults[1][2].Value, - P90 = finalResults[1][3].Value, - P99 = finalResults[1][4].Value, - Max = finalResults[1][5].Value, - } - }; - - context.Response.StatusCode = (int) HttpStatusCode.OK; - await context.Response.WriteAsync(wrapper.AsMarkdownTableRow()); -}); - app.Run(); \ No newline at end of file diff --git a/src/NET8MinimalAPI/ApiBootstrap/QueryResult.cs b/src/NET8MinimalAPI/ApiBootstrap/QueryResult.cs deleted file mode 100644 index ff692d2..0000000 --- a/src/NET8MinimalAPI/ApiBootstrap/QueryResult.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace GetProducts; - -public record QueryResultWrapper -{ - public string LoadTestType { get; set; } - - public QueryResult ColdStart { get; set; } - - public QueryResult WarmStart { get; set; } - - public string AsMarkdownTableRow() => $"
Cold Start (ms)Warm Start (ms)
p50p90p99maxp50p90p99max
{LoadTestType}{ColdStart.P50}{ColdStart.P90}{ColdStart.P99}{ColdStart.Max}{WarmStart.P50}{WarmStart.P90}{WarmStart.P99}{WarmStart.Max}
"; -} - -public record QueryResult -{ - public string Count { get; set; } - - public string P50 { get; set; } - - public string P90 { get; set; } - - public string P99 { get; set; } - - public string Max { get; set; } -} \ No newline at end of file diff --git a/src/NET8MinimalAPI/Makefile b/src/NET8MinimalAPI/Makefile index 3f5ee87..4ec8c4a 100644 --- a/src/NET8MinimalAPI/Makefile +++ b/src/NET8MinimalAPI/Makefile @@ -1,3 +1,6 @@ -build-ApiFunction: +build-MinimalApiX86: dotnet clean dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) +build-MinimalApiArm64: + dotnet clean + dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.json b/src/NET8MinimalAPI/Report/load-test-report-arm64.json new file mode 100644 index 0000000..93cb117 --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-arm64.json @@ -0,0 +1,62 @@ +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "2379" + }, + { + "field": "p50", + "value": "9.5259" + }, + { + "field": "p90", + "value": "23.9189" + }, + { + "field": "p99", + "value": "47.3338" + }, + { + "field": "max", + "value": "92.05" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "58" + }, + { + "field": "p50", + "value": "1918.93" + }, + { + "field": "p90", + "value": "1984.77" + }, + { + "field": "p99", + "value": "2030.69" + }, + { + "field": "max", + "value": "2030.69" + } + ] + ], + "statistics": { + "recordsMatched": 2437.0, + "recordsScanned": 22033.0, + "bytesScanned": 16894616.0 + }, + "status": "Complete" +} diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.txt b/src/NET8MinimalAPI/Report/load-test-report-arm64.txt new file mode 100644 index 0000000..b87ccb6 --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-arm64.txt @@ -0,0 +1,18 @@ +Sun Nov 5 00:12:47 CET 2023 +arm64 RESULTS lambda: Net8-MinimalApi-Arm64 +Test duration sec: 60 +Log interval min: 20 +Complete +RESULTS coldstart 0 +RESULTS count 2379 +RESULTS p50 9.5259 +RESULTS p90 23.9189 +RESULTS p99 47.3338 +RESULTS max 92.05 +RESULTS coldstart 1 +RESULTS count 58 +RESULTS p50 1918.93 +RESULTS p90 1984.77 +RESULTS p99 2030.69 +RESULTS max 2030.69 +STATISTICS 16894616.0 2437.0 22033.0 diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.json b/src/NET8MinimalAPI/Report/load-test-report-x86.json new file mode 100644 index 0000000..e3ec86e --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-x86.json @@ -0,0 +1,62 @@ +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "1526" + }, + { + "field": "p50", + "value": "8.1277" + }, + { + "field": "p90", + "value": "18.8511" + }, + { + "field": "p99", + "value": "37.9017" + }, + { + "field": "max", + "value": "78.73" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "38" + }, + { + "field": "p50", + "value": "1649.85" + }, + { + "field": "p90", + "value": "1712.45" + }, + { + "field": "p99", + "value": "1760.44" + }, + { + "field": "max", + "value": "1760.44" + } + ] + ], + "statistics": { + "recordsMatched": 1564.0, + "recordsScanned": 14095.0, + "bytesScanned": 10756719.0 + }, + "status": "Complete" +} diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.txt b/src/NET8MinimalAPI/Report/load-test-report-x86.txt new file mode 100644 index 0000000..20762d7 --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-x86.txt @@ -0,0 +1,18 @@ +Sun Nov 5 00:10:57 CET 2023 +x86 RESULTS lambda: Net8-MinimalApi-X86 +Test duration sec: 60 +Log interval min: 20 +Complete +RESULTS coldstart 0 +RESULTS count 1526 +RESULTS p50 8.1277 +RESULTS p90 18.8511 +RESULTS p99 37.9017 +RESULTS max 78.73 +RESULTS coldstart 1 +RESULTS count 38 +RESULTS p50 1649.85 +RESULTS p90 1712.45 +RESULTS p99 1760.44 +RESULTS max 1760.44 +STATISTICS 10756719.0 1564.0 14095.0 diff --git a/src/NET8MinimalAPI/Shared/Shared.csproj b/src/NET8MinimalAPI/Shared/Shared.csproj index 34cd820..50accf7 100644 --- a/src/NET8MinimalAPI/Shared/Shared.csproj +++ b/src/NET8MinimalAPI/Shared/Shared.csproj @@ -1,14 +1,14 @@ - net8.0 + net8.0 enable enable - - + + diff --git a/src/NET8MinimalAPI/deploy.sh b/src/NET8MinimalAPI/deploy.sh new file mode 100755 index 0000000..c3c63fa --- /dev/null +++ b/src/NET8MinimalAPI/deploy.sh @@ -0,0 +1,2 @@ +sam build +sam deploy --stack-name dotnet8-minimal-api --resolve-s3 --s3-prefix dotnet8-minimal-api --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file diff --git a/src/NET8MinimalAPI/omnisharp.json b/src/NET8MinimalAPI/omnisharp.json deleted file mode 100644 index c42f8db..0000000 --- a/src/NET8MinimalAPI/omnisharp.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "fileOptions": { - "excludeSearchPatterns": [ - "**/bin/**/*", - "**/obj/**/*" - ] - }, - "msbuild": { - "Platform": "rhel.7.2-x64" - } -} \ No newline at end of file diff --git a/src/NET8MinimalAPI/run-loadtest.sh b/src/NET8MinimalAPI/run-loadtest.sh new file mode 100755 index 0000000..1a8729d --- /dev/null +++ b/src/NET8MinimalAPI/run-loadtest.sh @@ -0,0 +1,121 @@ +#Arguments: +#$1 - load test duration in seconds +#$2 - log interval to be used in the cloudwatch query in minutes +#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat + +STACK_NAME=dotnet8-minimal-api +TEST_DURATIOMN_SEC=60 +LOG_INTERVAL_MIN=20 +LOG_DELETE=1 + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ x$1 != "x" ]; +then + TEST_DURATIOMN_SEC=$1 +fi + +if [ x$2 != "x" ]; +then + LOG_INTERVAL_MIN=$2 +fi + +if [ x$3 != "x" ]; +then + LOG_DELETE=$3 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DURATION:$TEST_DURATIOMN_SEC +echo LOG INTERVAL:$LOG_INTERVAL_MIN +echo -------------------------------------------- +echo "${NO_COLOR}" + +function RunLoadTest() +{ + #Params: + #$1 - Architecture (x86 or arm64).Used for logging and naming report file + #$2 - Stack output name to get API Url + #$3 - Stack output name to get lambda name + + #get test params from cloud formation output + echo "${COLOR}" + API_URL=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$2'].OutputValue" \ + --output text) + echo API URL: $API_URL + + LAMBDA=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$3'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA + + if [ $LOG_DELETE == "1" ]; + then + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA + echo --------------------------------------------- + echo Waiting 10 sec. for deletion to complete + echo -------------------------------------------- + sleep 10 + fi + + #run load test with artillery + echo -------------------------------------------- + echo $1 RUNNING LOAD TEST $TEST_DURATIOMN_SEC sec $LAMBDA: $API_URL + echo -------------------------------------------- + echo "${NO_COLOR}" + artillery run \ + --target "$API_URL" \ + --overrides '{"config": { "phases": [{ "duration": '$TEST_DURATIOMN_SEC', "arrivalRate": 100 }] } }' \ + --quiet \ + ../../loadtest/load-test.yml + + echo "${COLOR}" + echo -------------------------------------------- + echo Waiting 10 sec. for logs to consolidate + echo -------------------------------------------- + sleep 10 + + #get stats from cloudwatch + enddate=$(date "+%s") + startdate=$(($enddate-($LOG_INTERVAL_MIN*60))) + echo -------------------------------------------- + echo Log start:$startdate end:$enddate + echo -------------------------------------------- + + QUERY_ID=$(aws logs start-query \ + --log-group-name /aws/lambda/$LAMBDA \ + --start-time $startdate \ + --end-time $enddate \ + --query-string 'filter @type="REPORT" | fields greatest(@initDuration, 0) + @duration as duration, ispresent(@initDuration) as coldstart | stats count(*) as count, pct(duration, 50) as p50, pct(duration, 90) as p90, pct(duration, 99) as p99, max(duration) as max by coldstart' \ + | jq -r '.queryId') + + echo -------------------------------------------- + echo Query started, id: $QUERY_ID + echo -------------------------------------------- + + echo --------------------------------------------- + echo Waiting 10 sec. for cloudwatch query to complete + echo -------------------------------------------- + sleep 10 + + echo -------------------------------------------- + echo RESULTS $LAMBDA + echo -------------------------------------------- + echo "${NO_COLOR}" + date > ./Report/load-test-report-$1.txt + echo $1 RESULTS lambda: $LAMBDA >> ./Report/load-test-report-$1.txt + echo Test duration sec: $TEST_DURATIOMN_SEC >> ./Report/load-test-report-$1.txt + echo Log interval min: $LOG_INTERVAL_MIN >> ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt + cat ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json +} + +RunLoadTest x86 ApiUrlX86 LambdaX86Name +RunLoadTest arm64 ApiUrlArm64 LambdaArm64Name \ No newline at end of file diff --git a/src/NET8MinimalAPI/template.yaml b/src/NET8MinimalAPI/template.yaml index aeb8b06..e5501b8 100644 --- a/src/NET8MinimalAPI/template.yaml +++ b/src/NET8MinimalAPI/template.yaml @@ -1,47 +1,65 @@ AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 +Parameters: + x86FunctionName: + Type: String + Default: Net8-MinimalApi-X86 + arm64FunctionName: + Type: String + Default: Net8-MinimalApi-Arm64 + Globals: Function: MemorySize: 1024 - Architectures: ["x86_64"] Runtime: provided.al2 Timeout: 30 Tracing: Active Environment: Variables: PRODUCT_TABLE_NAME: !Ref Table - LOG_GROUP_PREFIX: !Sub "/aws/lambda/net-8-minimal-" - LOAD_TEST_TYPE: "NET 8 Minimal API" Resources: - ApiFunction: + MinimalApiX86: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Ref x86FunctionName + Architectures: [x86_64] + CodeUri: ./ + Handler: ApiBootstrap + Environment: + Variables: + DEMO_BASE_PATH: /x86 + Events: + Api: + Type: HttpApi + Properties: + Path: /x86/{proxy+} + Method: ANY + Policies: + - DynamoDBCrudPolicy: + TableName: + !Ref Table + MinimalApiArm64: Type: AWS::Serverless::Function Properties: + FunctionName: !Ref arm64FunctionName + Architectures: [arm64] CodeUri: ./ Handler: ApiBootstrap + Environment: + Variables: + DEMO_BASE_PATH: /arm64 Events: Api: Type: HttpApi Properties: - Path: /{proxy+} + Path: /arm64/{proxy+} Method: ANY Policies: - DynamoDBCrudPolicy: TableName: !Ref Table - - Version: "2012-10-17" - Statement: - - Sid: AllowStartQueries - Effect: Allow - Action: - - logs:DescribeLogGroups - - logs:StartQuery - Resource: "*" - - Sid: AllowGetQueryResults - Effect: Allow - Action: logs:GetQueryResults - Resource: "*" Table: Type: AWS::DynamoDB::Table @@ -59,4 +77,16 @@ Resources: Outputs: ApiUrl: Description: "API Gateway endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/" \ No newline at end of file + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/" + LambdaX86Name: + Description: "Lambda X86 Name" + Value: !Ref x86FunctionName + ApiUrlX86: + Description: "X86 API endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86/" + LambdaArm64Name: + Description: "Lambda Arm64 Name" + Value: !Ref arm64FunctionName + ApiUrlArm64: + Description: "Arm64 GateAPI endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64/" \ No newline at end of file From bab15e6be091cdd811e0dea794595d8da0cb92b8 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 09:55:35 +0100 Subject: [PATCH 02/24] . --- src/NET8MinimalAPI/run-loadtest.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NET8MinimalAPI/run-loadtest.sh b/src/NET8MinimalAPI/run-loadtest.sh index 1a8729d..4acbab4 100755 --- a/src/NET8MinimalAPI/run-loadtest.sh +++ b/src/NET8MinimalAPI/run-loadtest.sh @@ -26,6 +26,8 @@ then LOG_DELETE=$3 fi +mkdir Report -p + echo "${COLOR}" echo -------------------------------------------- echo DURATION:$TEST_DURATIOMN_SEC From 57e29764ea99dd2700f06a99d963486c9fb6b8da Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 10:10:34 +0100 Subject: [PATCH 03/24] fixing load test with codebuild --- loadtest/codebuild/run-all-load-tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index 4f30087..91a8975 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -38,8 +38,8 @@ else source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi -#export LT_NET6_MINIMAL_API_WEB_ADAPTER=1 -if [ x"${LT_NET8_MINIMAL_API}" == "x" ]; +#export LT_NET8_MINIMAL_API=1 +if [ $LT_NET8_MINIMAL_API != "yes" ]; then echo SKIPPING net8 minimal api :$LT_NET8_MINIMAL_API else From 994cd7f5d3ac89445b4a9614bc7da1dc0753c108 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 10:34:22 +0100 Subject: [PATCH 04/24] adding sdk 8.0 for code build compilation --- loadtest/codebuild/load-test-buildspec.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/loadtest/codebuild/load-test-buildspec.yml b/loadtest/codebuild/load-test-buildspec.yml index af4fbcb..1feec27 100644 --- a/loadtest/codebuild/load-test-buildspec.yml +++ b/loadtest/codebuild/load-test-buildspec.yml @@ -3,6 +3,7 @@ version: 0.2 phases: install: commands: + - curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0 - npm i artillery -g build: commands: From a97f739dac2b42cdf409dd57dbc51c43a854e39b Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 11:04:41 +0100 Subject: [PATCH 05/24] . --- loadtest/codebuild/run-all-load-tests.sh | 2 +- src/NET8MinimalAPI/run-loadtest.sh | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index 3164952..525d3d6 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -44,7 +44,7 @@ else fi #export LT_NET8_MINIMAL_API=1 -if [ $LT_NET8_MINIMAL_API != "yes" ]; +if [ "$LT_NET8_MINIMAL_API" != yes ]; then echo SKIPPING net8 minimal api :$LT_NET8_MINIMAL_API else diff --git a/src/NET8MinimalAPI/run-loadtest.sh b/src/NET8MinimalAPI/run-loadtest.sh index 4acbab4..322e04b 100755 --- a/src/NET8MinimalAPI/run-loadtest.sh +++ b/src/NET8MinimalAPI/run-loadtest.sh @@ -11,30 +11,31 @@ LOG_DELETE=1 COLOR='\033[0;33m' NO_COLOR='\033[0m' # No Color -if [ x$1 != "x" ]; +if [ "x$1" != x ]; then TEST_DURATIOMN_SEC=$1 fi -if [ x$2 != "x" ]; +if [ "x$2" != x ]; then LOG_INTERVAL_MIN=$2 fi -if [ x$3 != "x" ]; +if [ "x$3" != x ]; then LOG_DELETE=$3 fi -mkdir Report -p - echo "${COLOR}" echo -------------------------------------------- echo DURATION:$TEST_DURATIOMN_SEC echo LOG INTERVAL:$LOG_INTERVAL_MIN +echo LOG_DELETE: $LOG_DELETE echo -------------------------------------------- echo "${NO_COLOR}" +mkdir Report -p + function RunLoadTest() { #Params: From 74b5450afd287a97f6d7831a1ba4c37b69fddd3b Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 16:26:33 +0100 Subject: [PATCH 06/24] fixing typo --- loadtest/codebuild/run-all-load-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index 525d3d6..f49caa4 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -51,5 +51,5 @@ else echo "RUNNING load test for net8 minimal api" cd ../../src/NET8MinimalAPI/ source ./deploy.sh - source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVALL_MIN $LOG_DELETE + source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi From a8bd2d6208e422d3f606d855c95f0745b9db98d4 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 17:03:57 +0100 Subject: [PATCH 07/24] . --- loadtest/codebuild/run-all-load-tests.sh | 2 +- src/NET8MinimalAPI/deploy.sh | 41 ++++++++++++++++++++++++ src/NET8MinimalAPI/run-loadtest.sh | 4 +-- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index 6717046..f64b9cf 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -57,6 +57,6 @@ then else echo "RUNNING load test for net8 minimal api" cd ../../src/NET8MinimalAPI/ - source ./deploy.sh + source ./deploy.sh $DELETE_STACK source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi diff --git a/src/NET8MinimalAPI/deploy.sh b/src/NET8MinimalAPI/deploy.sh index c3c63fa..80e0ccd 100755 --- a/src/NET8MinimalAPI/deploy.sh +++ b/src/NET8MinimalAPI/deploy.sh @@ -1,2 +1,43 @@ +#Arguments: +#$1 - delete stack formation to ensure that all test have same conditon and favour similar ammount of cold start events + +STACK_NAME=dotnet8-minimal-api +DELETE_STACK=yes + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ "x$4" != x ]; +then + DELETE_STACK=$1 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DELETE_STACK: $DELETE_STACK +echo -------------------------------------------- +echo "${NO_COLOR}" + +if [ $DELETE_STACK == "yes" ]; +then + echo "${COLOR}" + echo -------------------------------------------- + echo DELETING STACK $STACK_NAME + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation delete-stack --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Waiting stack to be deleted + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Stack deleted + echo -------------------------------------------- + echo "${NO_COLOR}" +fi + sam build sam deploy --stack-name dotnet8-minimal-api --resolve-s3 --s3-prefix dotnet8-minimal-api --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file diff --git a/src/NET8MinimalAPI/run-loadtest.sh b/src/NET8MinimalAPI/run-loadtest.sh index 322e04b..d413e3b 100755 --- a/src/NET8MinimalAPI/run-loadtest.sh +++ b/src/NET8MinimalAPI/run-loadtest.sh @@ -6,7 +6,7 @@ STACK_NAME=dotnet8-minimal-api TEST_DURATIOMN_SEC=60 LOG_INTERVAL_MIN=20 -LOG_DELETE=1 +LOG_DELETE=yes COLOR='\033[0;33m' NO_COLOR='\033[0m' # No Color @@ -55,7 +55,7 @@ function RunLoadTest() --output text) echo LAMBDA: $LAMBDA - if [ $LOG_DELETE == "1" ]; + if [ $LOG_DELETE == "yes" ]; then echo -------------------------------------------- echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA From 87cd54e9763a3dcd09abf23e8356c04c64c349c4 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 19:22:13 +0100 Subject: [PATCH 08/24] . --- .../Report/load-test-report-arm64.json | 62 ------------------- .../Report/load-test-report-arm64.txt | 18 ------ .../Report/load-test-report-x86.json | 62 ------------------- .../Report/load-test-report-x86.txt | 18 ------ src/NET8MinimalAPI/run-loadtest.sh | 2 +- 5 files changed, 1 insertion(+), 161 deletions(-) delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.json delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.txt delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.json delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.txt diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.json b/src/NET8MinimalAPI/Report/load-test-report-arm64.json deleted file mode 100644 index 93cb117..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-arm64.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "2379" - }, - { - "field": "p50", - "value": "9.5259" - }, - { - "field": "p90", - "value": "23.9189" - }, - { - "field": "p99", - "value": "47.3338" - }, - { - "field": "max", - "value": "92.05" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "58" - }, - { - "field": "p50", - "value": "1918.93" - }, - { - "field": "p90", - "value": "1984.77" - }, - { - "field": "p99", - "value": "2030.69" - }, - { - "field": "max", - "value": "2030.69" - } - ] - ], - "statistics": { - "recordsMatched": 2437.0, - "recordsScanned": 22033.0, - "bytesScanned": 16894616.0 - }, - "status": "Complete" -} diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.txt b/src/NET8MinimalAPI/Report/load-test-report-arm64.txt deleted file mode 100644 index b87ccb6..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-arm64.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 00:12:47 CET 2023 -arm64 RESULTS lambda: Net8-MinimalApi-Arm64 -Test duration sec: 60 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 2379 -RESULTS p50 9.5259 -RESULTS p90 23.9189 -RESULTS p99 47.3338 -RESULTS max 92.05 -RESULTS coldstart 1 -RESULTS count 58 -RESULTS p50 1918.93 -RESULTS p90 1984.77 -RESULTS p99 2030.69 -RESULTS max 2030.69 -STATISTICS 16894616.0 2437.0 22033.0 diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.json b/src/NET8MinimalAPI/Report/load-test-report-x86.json deleted file mode 100644 index e3ec86e..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-x86.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "1526" - }, - { - "field": "p50", - "value": "8.1277" - }, - { - "field": "p90", - "value": "18.8511" - }, - { - "field": "p99", - "value": "37.9017" - }, - { - "field": "max", - "value": "78.73" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "38" - }, - { - "field": "p50", - "value": "1649.85" - }, - { - "field": "p90", - "value": "1712.45" - }, - { - "field": "p99", - "value": "1760.44" - }, - { - "field": "max", - "value": "1760.44" - } - ] - ], - "statistics": { - "recordsMatched": 1564.0, - "recordsScanned": 14095.0, - "bytesScanned": 10756719.0 - }, - "status": "Complete" -} diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.txt b/src/NET8MinimalAPI/Report/load-test-report-x86.txt deleted file mode 100644 index 20762d7..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-x86.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 00:10:57 CET 2023 -x86 RESULTS lambda: Net8-MinimalApi-X86 -Test duration sec: 60 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 1526 -RESULTS p50 8.1277 -RESULTS p90 18.8511 -RESULTS p99 37.9017 -RESULTS max 78.73 -RESULTS coldstart 1 -RESULTS count 38 -RESULTS p50 1649.85 -RESULTS p90 1712.45 -RESULTS p99 1760.44 -RESULTS max 1760.44 -STATISTICS 10756719.0 1564.0 14095.0 diff --git a/src/NET8MinimalAPI/run-loadtest.sh b/src/NET8MinimalAPI/run-loadtest.sh index d413e3b..41344f0 100755 --- a/src/NET8MinimalAPI/run-loadtest.sh +++ b/src/NET8MinimalAPI/run-loadtest.sh @@ -34,7 +34,7 @@ echo LOG_DELETE: $LOG_DELETE echo -------------------------------------------- echo "${NO_COLOR}" -mkdir Report -p +mkdir -p Report function RunLoadTest() { From 2d9db902e2f3dd52e24d92fca8cd66a9dfef381b Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 5 Nov 2023 21:45:21 +0100 Subject: [PATCH 09/24] adding net8 minimila api stats after 10 min loadtest --- README.md | 26 ++++++++ .../Report/load-test-report-arm64.json | 62 +++++++++++++++++++ .../Report/load-test-report-arm64.txt | 18 ++++++ .../Report/load-test-report-x86.json | 62 +++++++++++++++++++ .../Report/load-test-report-x86.txt | 18 ++++++ 5 files changed, 186 insertions(+) create mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.json create mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.txt create mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.json create mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.txt diff --git a/README.md b/README.md index b3b43dd..ac3bbbe 100755 --- a/README.md +++ b/README.md @@ -557,6 +557,32 @@ The .NET 8 benchmarks include the number of cold and warm starts, alongside the 23.84 120.45 + + Minimal API on X86 + 195 + 1672.85 + 1737.61 + 1833.97 + 1889.15 + 136,006 + 6.30 + 10.98 + 26.72 + 124.67 + + + Minimal API on ARM64 + 242 + 1972.79 + 2049.16 + 2107.32 + 2124.55 + 136,816 + 6.01 + 9.37 + 24.69 + 331.6 + *The .NET 8 native AOT examples need to be compiled on Amazon Linux 2, this is a temporary solution as a pre-cursor to a SAM build image being available for .NET 8. diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.json b/src/NET8MinimalAPI/Report/load-test-report-arm64.json new file mode 100644 index 0000000..8a37bf2 --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-arm64.json @@ -0,0 +1,62 @@ +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "136816" + }, + { + "field": "p50", + "value": "6.0116" + }, + { + "field": "p90", + "value": "9.3759" + }, + { + "field": "p99", + "value": "24.6905" + }, + { + "field": "max", + "value": "331.6" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "242" + }, + { + "field": "p50", + "value": "1972.7958" + }, + { + "field": "p90", + "value": "2049.1658" + }, + { + "field": "p99", + "value": "2107.3237" + }, + { + "field": "max", + "value": "2124.55" + } + ] + ], + "statistics": { + "recordsMatched": 137058.0, + "recordsScanned": 1233898.0, + "bytesScanned": 945917431.0 + }, + "status": "Complete" +} diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.txt b/src/NET8MinimalAPI/Report/load-test-report-arm64.txt new file mode 100644 index 0000000..e98f8f2 --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-arm64.txt @@ -0,0 +1,18 @@ +Sun Nov 5 19:38:43 UTC 2023 +arm64 RESULTS lambda: Net8-MinimalApi-Arm64 +Test duration sec: 600 +Log interval min: 20 +Complete +RESULTS coldstart 0 +RESULTS count 136816 +RESULTS p50 6.0116 +RESULTS p90 9.3759 +RESULTS p99 24.6905 +RESULTS max 331.6 +RESULTS coldstart 1 +RESULTS count 242 +RESULTS p50 1972.7958 +RESULTS p90 2049.1658 +RESULTS p99 2107.3237 +RESULTS max 2124.55 +STATISTICS 945917431.0 137058.0 1233898.0 diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.json b/src/NET8MinimalAPI/Report/load-test-report-x86.json new file mode 100644 index 0000000..6b47edc --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-x86.json @@ -0,0 +1,62 @@ +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "136006" + }, + { + "field": "p50", + "value": "6.3048" + }, + { + "field": "p90", + "value": "10.9888" + }, + { + "field": "p99", + "value": "26.7299" + }, + { + "field": "max", + "value": "124.67" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "195" + }, + { + "field": "p50", + "value": "1672.8591" + }, + { + "field": "p90", + "value": "1737.618" + }, + { + "field": "p99", + "value": "1833.9796" + }, + { + "field": "max", + "value": "1889.15" + } + ] + ], + "statistics": { + "recordsMatched": 136201.0, + "recordsScanned": 1226041.0, + "bytesScanned": 935106143.0 + }, + "status": "Complete" +} diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.txt b/src/NET8MinimalAPI/Report/load-test-report-x86.txt new file mode 100644 index 0000000..f57a52f --- /dev/null +++ b/src/NET8MinimalAPI/Report/load-test-report-x86.txt @@ -0,0 +1,18 @@ +Sun Nov 5 19:28:01 UTC 2023 +x86 RESULTS lambda: Net8-MinimalApi-X86 +Test duration sec: 600 +Log interval min: 20 +Complete +RESULTS coldstart 0 +RESULTS count 136006 +RESULTS p50 6.3048 +RESULTS p90 10.9888 +RESULTS p99 26.7299 +RESULTS max 124.67 +RESULTS coldstart 1 +RESULTS count 195 +RESULTS p50 1672.8591 +RESULTS p90 1737.618 +RESULTS p99 1833.9796 +RESULTS max 1889.15 +STATISTICS 935106143.0 136201.0 1226041.0 From 130cdb5409c760b3da7f932be825532fbc3e5c7d Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Fri, 10 Nov 2023 21:34:05 +0100 Subject: [PATCH 10/24] updating NET8 project with load test script --- loadtest/codebuild/load-test.yml | 32 +++ src/NET8/DeleteProduct/DeleteProduct.csproj | 12 +- src/NET8/GenerateLoadTestResults/DateUtils.cs | 13 - src/NET8/GenerateLoadTestResults/Function.cs | 146 ---------- .../GenerateLoadTestResults.csproj | 17 -- .../GenerateLoadTestResults/QueryResult.cs | 25 -- src/NET8/GetProduct/GetProduct.csproj | 12 +- src/NET8/GetProducts/GetProducts.csproj | 12 +- src/NET8/Makefile | 26 +- src/NET8/PutProduct/PutProduct.csproj | 12 +- src/NET8/Report/load-test-report-.json | 0 src/NET8/Report/load-test-report-.txt | 2 + src/NET8/Report/load-test-report-arm64.json | 186 +++++++++++++ src/NET8/Report/load-test-report-arm64.txt | 18 ++ src/NET8/Report/load-test-report-x86.json | 260 ++++++++++++++++++ src/NET8/Report/load-test-report-x86.txt | 18 ++ src/NET8/Shared/Shared.csproj | 8 +- src/NET8/deploy.sh | 43 +++ src/NET8/run-loadtest.sh | 153 +++++++++++ src/NET8/template.yaml | 165 +++++++++-- 20 files changed, 893 insertions(+), 267 deletions(-) create mode 100755 loadtest/codebuild/load-test.yml delete mode 100644 src/NET8/GenerateLoadTestResults/DateUtils.cs delete mode 100644 src/NET8/GenerateLoadTestResults/Function.cs delete mode 100644 src/NET8/GenerateLoadTestResults/GenerateLoadTestResults.csproj delete mode 100644 src/NET8/GenerateLoadTestResults/QueryResult.cs create mode 100644 src/NET8/Report/load-test-report-.json create mode 100644 src/NET8/Report/load-test-report-.txt create mode 100644 src/NET8/Report/load-test-report-arm64.json create mode 100644 src/NET8/Report/load-test-report-arm64.txt create mode 100644 src/NET8/Report/load-test-report-x86.json create mode 100644 src/NET8/Report/load-test-report-x86.txt create mode 100755 src/NET8/deploy.sh create mode 100755 src/NET8/run-loadtest.sh diff --git a/loadtest/codebuild/load-test.yml b/loadtest/codebuild/load-test.yml new file mode 100755 index 0000000..75c7beb --- /dev/null +++ b/loadtest/codebuild/load-test.yml @@ -0,0 +1,32 @@ +config: + target: "{{ $processEnvironment.API_URL }}" + http: + timeout : 60 + processor: "../generator.js" + phases: + - duration: 60 + arrivalRate: 100 + +scenarios: + - name: "Generate products" + weight: 8 + flow: + - function: "generateProduct" + - put: + url: "/{{ Id }}" + headers: + Content-Type: "application/json" + json: + Id: "{{ Id }}" + Name: "{{ Name }}" + Price: "{{ Price }}" + - get: + url: "/{{ Id }}" + - think: 3 + - delete: + url: "/{{ Id }}" + - name: "Get products" + weight: 2 + flow: + - get: + url: "{{ $processEnvironment.API_URL }}" \ No newline at end of file diff --git a/src/NET8/DeleteProduct/DeleteProduct.csproj b/src/NET8/DeleteProduct/DeleteProduct.csproj index 825e086..a386b03 100644 --- a/src/NET8/DeleteProduct/DeleteProduct.csproj +++ b/src/NET8/DeleteProduct/DeleteProduct.csproj @@ -15,12 +15,12 @@ - - - - - - + + + + + + diff --git a/src/NET8/GenerateLoadTestResults/DateUtils.cs b/src/NET8/GenerateLoadTestResults/DateUtils.cs deleted file mode 100644 index c37c43d..0000000 --- a/src/NET8/GenerateLoadTestResults/DateUtils.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace GenerateLoadTestResults; - -public static class DateUtils -{ - public static long AsUnixTimestamp(this DateTime date) - { - DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); - TimeSpan diff = date.ToUniversalTime() - origin; - return (long)Math.Floor(diff.TotalSeconds); - } -} \ No newline at end of file diff --git a/src/NET8/GenerateLoadTestResults/Function.cs b/src/NET8/GenerateLoadTestResults/Function.cs deleted file mode 100644 index 21a57a8..0000000 --- a/src/NET8/GenerateLoadTestResults/Function.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text.Json; -using System.Threading.Tasks; -using Amazon.CloudWatchLogs; -using Amazon.CloudWatchLogs.Model; -using Amazon.Lambda.APIGatewayEvents; -using Amazon.Lambda.Core; - -[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] - -namespace GenerateLoadTestResults -{ - public class Function - { - private AmazonCloudWatchLogsClient _cloudWatchLogsClient; - - public Function() - { - this._cloudWatchLogsClient = new AmazonCloudWatchLogsClient(); - } - - public async Task FunctionHandler( - APIGatewayHttpApiV2ProxyRequest apigProxyEvent, - ILambdaContext context) - { - if (!apigProxyEvent.RequestContext.Http.Method.Equals(HttpMethod.Get.Method)) - { - return new APIGatewayHttpApiV2ProxyResponse - { - Body = "Only GET allowed", - StatusCode = (int) HttpStatusCode.MethodNotAllowed, - }; - } - - try - { - var resultRows = 0; - var queryCount = 0; - - List> finalResults = new List>(); - - while (resultRows < 2 || queryCount >= 3) - { - finalResults = await runQuery(context); - - resultRows = finalResults.Count; - queryCount++; - } - - var wrapper = new QueryResultWrapper() - { - LoadTestType = - $"{Environment.GetEnvironmentVariable("LOAD_TEST_TYPE")} ({Environment.GetEnvironmentVariable("LAMBDA_ARCHITECTURE")})", - WarmStart = new QueryResult() - { - Count = finalResults[0][1].Value, - P50 = finalResults[0][2].Value, - P90 = finalResults[0][3].Value, - P99 = finalResults[0][4].Value, - Max = finalResults[0][5].Value, - }, - ColdStart = new QueryResult() - { - Count = finalResults[1][1].Value, - P50 = finalResults[1][2].Value, - P90 = finalResults[1][3].Value, - P99 = finalResults[1][4].Value, - Max = finalResults[1][5].Value, - } - }; - - return new APIGatewayHttpApiV2ProxyResponse - { - StatusCode = (int) HttpStatusCode.OK, - Body = wrapper.AsMarkdownTableRow(), - Headers = new Dictionary {{"Content-Type", "text/html"}} - }; - } - catch (Exception e) - { - context.Logger.LogLine($"Error retrieving results {e.Message} {e.StackTrace}"); - - return new APIGatewayHttpApiV2ProxyResponse - { - Body = "Not Found", - StatusCode = (int) HttpStatusCode.InternalServerError, - }; - } - } - - private async Task>> runQuery(ILambdaContext context) - { - var logGroupNamePrefix = - $"{Environment.GetEnvironmentVariable("LOG_GROUP_PREFIX")}{Environment.GetEnvironmentVariable("LAMBDA_ARCHITECTURE")}" - .Replace("_", "-"); - - context.Logger.LogLine($"Retrieving log groups with prefix {logGroupNamePrefix}"); - - var logGroupList = await _cloudWatchLogsClient.DescribeLogGroupsAsync(new DescribeLogGroupsRequest() - { - LogGroupNamePrefix = logGroupNamePrefix, - }); - - context.Logger.LogLine($"Found {logGroupList.LogGroups.Count} log group(s)"); - - var queryRes = await _cloudWatchLogsClient.StartQueryAsync(new StartQueryRequest() - { - LogGroupNames = logGroupList.LogGroups.Select(p => p.LogGroupName).ToList(), - QueryString = - "filter @type=\"REPORT\" | fields greatest(@initDuration, 0) + @duration as duration, ispresent(@initDuration) as coldstart | stats count(*) as count, pct(duration, 50) as p50, pct(duration, 90) as p90, pct(duration, 99) as p99, max(duration) as max by coldstart", - StartTime = DateTime.Now.AddMinutes(-20).AsUnixTimestamp(), - EndTime = DateTime.Now.AsUnixTimestamp(), - }); - - context.Logger.LogLine($"Running query, query id is {queryRes.QueryId}"); - - QueryStatus currentQueryStatus = QueryStatus.Running; - List> finalResults = new List>(); - - while (currentQueryStatus == QueryStatus.Running || currentQueryStatus == QueryStatus.Scheduled) - { - context.Logger.LogLine("Retrieving query results"); - - var queryResults = await _cloudWatchLogsClient.GetQueryResultsAsync(new GetQueryResultsRequest() - { - QueryId = queryRes.QueryId - }); - - context.Logger.LogLine($"Query result status is {queryResults.Status}"); - - currentQueryStatus = queryResults.Status; - finalResults = queryResults.Results; - - await Task.Delay(TimeSpan.FromSeconds(5)); - } - - context.Logger.LogLine($"Final results: {finalResults.Count} row(s)"); - - return finalResults; - } - } -} \ No newline at end of file diff --git a/src/NET8/GenerateLoadTestResults/GenerateLoadTestResults.csproj b/src/NET8/GenerateLoadTestResults/GenerateLoadTestResults.csproj deleted file mode 100644 index 4a8d708..0000000 --- a/src/NET8/GenerateLoadTestResults/GenerateLoadTestResults.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - net6.0 - true - true - - - - - - - - - - - diff --git a/src/NET8/GenerateLoadTestResults/QueryResult.cs b/src/NET8/GenerateLoadTestResults/QueryResult.cs deleted file mode 100644 index 69b5a31..0000000 --- a/src/NET8/GenerateLoadTestResults/QueryResult.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace GenerateLoadTestResults; - -public record QueryResultWrapper -{ - public string LoadTestType { get; set; } - - public QueryResult ColdStart { get; set; } - - public QueryResult WarmStart { get; set; } - - public string AsMarkdownTableRow() => $"
Cold Start (ms)Warm Start (ms)
p50p90p99maxp50p90p99max
{LoadTestType}{ColdStart.P50}{ColdStart.P90}{ColdStart.P99}{ColdStart.Max}{WarmStart.P50}{WarmStart.P90}{WarmStart.P99}{WarmStart.Max}
"; -} - -public record QueryResult -{ - public string Count { get; set; } - - public string P50 { get; set; } - - public string P90 { get; set; } - - public string P99 { get; set; } - - public string Max { get; set; } -} \ No newline at end of file diff --git a/src/NET8/GetProduct/GetProduct.csproj b/src/NET8/GetProduct/GetProduct.csproj index 9757d2d..8253d9e 100644 --- a/src/NET8/GetProduct/GetProduct.csproj +++ b/src/NET8/GetProduct/GetProduct.csproj @@ -13,12 +13,12 @@ linux-x64 - - - - - - + + + + + + diff --git a/src/NET8/GetProducts/GetProducts.csproj b/src/NET8/GetProducts/GetProducts.csproj index 55460a1..982b1ac 100644 --- a/src/NET8/GetProducts/GetProducts.csproj +++ b/src/NET8/GetProducts/GetProducts.csproj @@ -14,12 +14,12 @@ linux-x64 - - - - - - + + + + + + diff --git a/src/NET8/Makefile b/src/NET8/Makefile index 2aadd31..4850513 100644 --- a/src/NET8/Makefile +++ b/src/NET8/Makefile @@ -1,15 +1,23 @@ -build-GetProductFunction: - dotnet clean +build-GetProductFunctionX86: dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) -build-GetProductsFunction: - dotnet clean +build-GetProductsFunctionX86: dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) -build-PutProductFunction: - dotnet clean +build-PutProductFunctionX86: dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) -build-DeleteProductFunction: - dotnet clean - dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file +build-DeleteProductFunctionX86: + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) + +build-GetProductFunctionArm64: + dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + +build-GetProductsFunctionArm64: + dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + +build-PutProductFunctionArm64: + dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + +build-DeleteProductFunctionArm64: + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8/PutProduct/PutProduct.csproj b/src/NET8/PutProduct/PutProduct.csproj index 9fae9e3..3f79dae 100644 --- a/src/NET8/PutProduct/PutProduct.csproj +++ b/src/NET8/PutProduct/PutProduct.csproj @@ -15,12 +15,12 @@ - - - - - - + + + + + + diff --git a/src/NET8/Report/load-test-report-.json b/src/NET8/Report/load-test-report-.json new file mode 100644 index 0000000..e69de29 diff --git a/src/NET8/Report/load-test-report-.txt b/src/NET8/Report/load-test-report-.txt new file mode 100644 index 0000000..183df41 --- /dev/null +++ b/src/NET8/Report/load-test-report-.txt @@ -0,0 +1,2 @@ +Test duration sec: 60 +Log interval min: 20 diff --git a/src/NET8/Report/load-test-report-arm64.json b/src/NET8/Report/load-test-report-arm64.json new file mode 100644 index 0000000..a6c8a0a --- /dev/null +++ b/src/NET8/Report/load-test-report-arm64.json @@ -0,0 +1,186 @@ +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "806" + }, + { + "field": "p50", + "value": "9.5341" + }, + { + "field": "p90", + "value": "22.7017" + }, + { + "field": "p99", + "value": "42.4839" + }, + { + "field": "max", + "value": "107.71" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "146" + }, + { + "field": "p50", + "value": "1725.5032" + }, + { + "field": "p90", + "value": "1801.2795" + }, + { + "field": "p99", + "value": "1865.4079" + }, + { + "field": "max", + "value": "1961.07" + } + ] + ], + "statistics": { + "recordsMatched": 952.0, + "recordsScanned": 4680.0, + "bytesScanned": 1408784.0 + }, + "status": "Complete" +} +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "1968" + }, + { + "field": "p50", + "value": "9.7659" + }, + { + "field": "p90", + "value": "22.5459" + }, + { + "field": "p99", + "value": "38.4524" + }, + { + "field": "max", + "value": "113.03" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "334" + }, + { + "field": "p50", + "value": "1725.5032" + }, + { + "field": "p90", + "value": "1792.3" + }, + { + "field": "p99", + "value": "1835.8135" + }, + { + "field": "max", + "value": "1915.31" + } + ] + ], + "statistics": { + "recordsMatched": 2302.0, + "recordsScanned": 9347.0, + "bytesScanned": 3833050.0 + }, + "status": "Complete" +} +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "1736" + }, + { + "field": "p50", + "value": "9.0179" + }, + { + "field": "p90", + "value": "21.3228" + }, + { + "field": "p99", + "value": "36.6573" + }, + { + "field": "max", + "value": "57.18" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "123" + }, + { + "field": "p50", + "value": "1703.2279" + }, + { + "field": "p90", + "value": "1756.8276" + }, + { + "field": "p99", + "value": "1812.1142" + }, + { + "field": "max", + "value": "1845.97" + } + ] + ], + "statistics": { + "recordsMatched": 1859.0, + "recordsScanned": 7270.0, + "bytesScanned": 2523694.0 + }, + "status": "Complete" +} diff --git a/src/NET8/Report/load-test-report-arm64.txt b/src/NET8/Report/load-test-report-arm64.txt new file mode 100644 index 0000000..6cc0f30 --- /dev/null +++ b/src/NET8/Report/load-test-report-arm64.txt @@ -0,0 +1,18 @@ +Fri Nov 10 21:22:49 CET 2023 +arm64 RESULTS +Test duration sec: 60 +Log interval min: 20 +Complete +RESULTS coldstart 0 +RESULTS count 1736 +RESULTS p50 9.0179 +RESULTS p90 21.3228 +RESULTS p99 36.6573 +RESULTS max 57.18 +RESULTS coldstart 1 +RESULTS count 123 +RESULTS p50 1703.2279 +RESULTS p90 1756.8276 +RESULTS p99 1812.1142 +RESULTS max 1845.97 +STATISTICS 2523694.0 1859.0 7270.0 diff --git a/src/NET8/Report/load-test-report-x86.json b/src/NET8/Report/load-test-report-x86.json new file mode 100644 index 0000000..317de0a --- /dev/null +++ b/src/NET8/Report/load-test-report-x86.json @@ -0,0 +1,260 @@ +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "3387" + }, + { + "field": "p50", + "value": "5.6355" + }, + { + "field": "p90", + "value": "11.0938" + }, + { + "field": "p99", + "value": "28.4069" + }, + { + "field": "max", + "value": "65.62" + } + ] + ], + "statistics": { + "recordsMatched": 3387.0, + "recordsScanned": 27649.0, + "bytesScanned": 6866946.0 + }, + "status": "Complete" +} + +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "2742" + }, + { + "field": "p50", + "value": "6.9328" + }, + { + "field": "p90", + "value": "14.4304" + }, + { + "field": "p99", + "value": "34.3935" + }, + { + "field": "max", + "value": "54.72" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "445" + }, + { + "field": "p50", + "value": "1452.9626" + }, + { + "field": "p90", + "value": "1509.209" + }, + { + "field": "p99", + "value": "1608.9048" + }, + { + "field": "max", + "value": "1730.88" + } + ] + ], + "statistics": { + "recordsMatched": 3187.0, + "recordsScanned": 12122.0, + "bytesScanned": 4277937.0 + }, + "status": "Complete" +} +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "1010" + }, + { + "field": "p50", + "value": "9.6115" + }, + { + "field": "p90", + "value": "19.072" + }, + { + "field": "p99", + "value": "38.1472" + }, + { + "field": "max", + "value": "56.86" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "141" + }, + { + "field": "p50", + "value": "1457.3259" + }, + { + "field": "p90", + "value": "1503.1872" + }, + { + "field": "p99", + "value": "1556.7031" + }, + { + "field": "max", + "value": "1609.72" + } + ] + ], + "statistics": { + "recordsMatched": 1151.0, + "recordsScanned": 4761.0, + "bytesScanned": 2021156.0 + }, + "status": "Complete" +} + +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "2137" + }, + { + "field": "p50", + "value": "7.3743" + }, + { + "field": "p90", + "value": "9.0232" + }, + { + "field": "p99", + "value": "15.8828" + }, + { + "field": "max", + "value": "30.14" + } + ] + ], + "statistics": { + "recordsMatched": 2137.0, + "recordsScanned": 18984.0, + "bytesScanned": 8138385.0 + }, + "status": "Complete" +} +{ + "results": [ + [ + { + "field": "coldstart", + "value": "0" + }, + { + "field": "count", + "value": "2538" + }, + { + "field": "p50", + "value": "6.9328" + }, + { + "field": "p90", + "value": "14.3159" + }, + { + "field": "p99", + "value": "30.2766" + }, + { + "field": "max", + "value": "66.97" + } + ], + [ + { + "field": "coldstart", + "value": "1" + }, + { + "field": "count", + "value": "441" + }, + { + "field": "p50", + "value": "1471.9649" + }, + { + "field": "p90", + "value": "1527.4194" + }, + { + "field": "p99", + "value": "1701.5263" + }, + { + "field": "max", + "value": "1958.74" + } + ] + ], + "statistics": { + "recordsMatched": 2979.0, + "recordsScanned": 11840.0, + "bytesScanned": 3773751.0 + }, + "status": "Complete" +} diff --git a/src/NET8/Report/load-test-report-x86.txt b/src/NET8/Report/load-test-report-x86.txt new file mode 100644 index 0000000..a772c6d --- /dev/null +++ b/src/NET8/Report/load-test-report-x86.txt @@ -0,0 +1,18 @@ +Fri Nov 10 21:20:45 CET 2023 +x86 RESULTS +Test duration sec: 60 +Log interval min: 20 +Complete +RESULTS coldstart 0 +RESULTS count 2538 +RESULTS p50 6.9328 +RESULTS p90 14.3159 +RESULTS p99 30.2766 +RESULTS max 66.97 +RESULTS coldstart 1 +RESULTS count 441 +RESULTS p50 1471.9649 +RESULTS p90 1527.4194 +RESULTS p99 1701.5263 +RESULTS max 1958.74 +STATISTICS 3773751.0 2979.0 11840.0 diff --git a/src/NET8/Shared/Shared.csproj b/src/NET8/Shared/Shared.csproj index 31e5c9f..2797db9 100644 --- a/src/NET8/Shared/Shared.csproj +++ b/src/NET8/Shared/Shared.csproj @@ -13,10 +13,10 @@ linux-x64 - - - - + + + + diff --git a/src/NET8/deploy.sh b/src/NET8/deploy.sh new file mode 100755 index 0000000..9aae7f5 --- /dev/null +++ b/src/NET8/deploy.sh @@ -0,0 +1,43 @@ +#Arguments: +#$1 - delete stack formation to ensure that all test have same conditon and favour similar ammount of cold start events + +STACK_NAME=dotnet8 +DELETE_STACK=yes + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ "x$4" != x ]; +then + DELETE_STACK=$1 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DELETE_STACK: $DELETE_STACK +echo -------------------------------------------- +echo "${NO_COLOR}" + +if [ $DELETE_STACK == "yes" ]; +then + echo "${COLOR}" + echo -------------------------------------------- + echo DELETING STACK $STACK_NAME + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation delete-stack --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Waiting stack to be deleted + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Stack deleted + echo -------------------------------------------- + echo "${NO_COLOR}" +fi + +sam build +sam deploy --stack-name $STACK_NAME --resolve-s3 --s3-prefix $STACK_NAME --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file diff --git a/src/NET8/run-loadtest.sh b/src/NET8/run-loadtest.sh new file mode 100755 index 0000000..2391e84 --- /dev/null +++ b/src/NET8/run-loadtest.sh @@ -0,0 +1,153 @@ +#Arguments: +#$1 - load test duration in seconds +#$2 - log interval to be used in the cloudwatch query in minutes +#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat + +STACK_NAME=dotnet8 +TEST_DURATIOMN_SEC=60 +LOG_INTERVAL_MIN=20 +LOG_DELETE=yes + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ "x$1" != x ]; +then + TEST_DURATIOMN_SEC=$1 +fi + +if [ "x$2" != x ]; +then + LOG_INTERVAL_MIN=$2 +fi + +if [ "x$3" != x ]; +then + LOG_DELETE=$3 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DURATION:$TEST_DURATIOMN_SEC +echo LOG INTERVAL:$LOG_INTERVAL_MIN +echo LOG_DELETE: $LOG_DELETE +echo -------------------------------------------- +echo "${NO_COLOR}" + +mkdir -p Report + +function RunLoadTest() +{ + #Params: + #$1 - Architecture (x86 or arm64).Used for logging and naming report file + #$2 - Stack output name to get API Url + #$3 - Stack output name to get lambda name GetProducts + #$4 - Stack output name to get lambda name GetProduct + #$5 - Stack output name to get lambda name DeleteProduct + #$6 - Stack output name to get lambda name PutProduct + + #get test params from cloud formation output + echo "${COLOR}" + export API_URL=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$2'].OutputValue" \ + --output text) + echo API URL: $API_URL + + LAMBDA_GETPRODUCTS=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$3'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_GETPRODUCTS + + LAMBDA_GETPRODUCT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$4'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_GETPRODUCT + + LAMBDA_DELETEPRODUCT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$5'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_DELETEPRODUCT + + LAMBDA_PUTPRODUCT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$6'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_PUTPRODUCT + + if [ $LOG_DELETE == "yes" ]; + then + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_GETPRODUCTS + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_GETPRODUCTS + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_GETPRODUCT + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_GETPRODUCT + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_DELETEPRODUCT + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_DELETEPRODUCT + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_PUTPRODUCT + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_PUTPRODUCT + echo --------------------------------------------- + echo Waiting 10 sec. for deletion to complete + echo -------------------------------------------- + sleep 10 + fi + + #run load test with artillery + echo -------------------------------------------- + echo $1 RUNNING LOAD TEST $TEST_DURATIOMN_SEC sec $API_URL + echo -------------------------------------------- + echo "${NO_COLOR}" + artillery run \ + --overrides '{"config": { "phases": [{ "duration": '$TEST_DURATIOMN_SEC', "arrivalRate": 100 }] } }' \ + --quiet \ + ../../loadtest/codebuild/load-test.yml + + echo "${COLOR}" + echo -------------------------------------------- + echo Waiting 10 sec. for logs to consolidate + echo -------------------------------------------- + sleep 10 + + #get stats from cloudwatch + enddate=$(date "+%s") + startdate=$(($enddate-($LOG_INTERVAL_MIN*60))) + echo -------------------------------------------- + echo Log start:$startdate end:$enddate + echo -------------------------------------------- + + QUERY_ID=$(aws logs start-query \ + --log-group-names "/aws/lambda/$LAMBDA_GETPRODUCTS" "/aws/lambda/$LAMBDA_GETPRODUCT" "/aws/lambda/$LAMBDA_DELETEPRODUCT" "/aws/lambda/$LAMBDA_PUTPRODUCT" \ + --start-time $startdate \ + --end-time $enddate \ + --query-string 'filter @type="REPORT" | fields greatest(@initDuration, 0) + @duration as duration, ispresent(@initDuration) as coldstart | stats count(*) as count, pct(duration, 50) as p50, pct(duration, 90) as p90, pct(duration, 99) as p99, max(duration) as max by coldstart' \ + | jq -r '.queryId') + + echo -------------------------------------------- + echo Query started, id: $QUERY_ID + echo -------------------------------------------- + + echo --------------------------------------------- + echo Waiting 10 sec. for cloudwatch query to complete + echo -------------------------------------------- + sleep 10 + + echo -------------------------------------------- + echo RESULTS $1 + echo -------------------------------------------- + echo "${NO_COLOR}" + date > ./Report/load-test-report-$1.txt + echo $1 RESULTS >> ./Report/load-test-report-$1.txt + echo Test duration sec: $TEST_DURATIOMN_SEC >> ./Report/load-test-report-$1.txt + echo Log interval min: $LOG_INTERVAL_MIN >> ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt + cat ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json +} + +RunLoadTest x86 ApiUrlX86 LambdaX86NameGetProducts LambdaX86NameGetProduct LambdaX86NameDeleteProduct LambdaX86NamePutProduct +RunLoadTest arm64 ApiUrlArm64 LambdaArm64NameGetProducts LambdaArm64NameGetProduct LambdaArm64NameDeleteProduct LambdaArm64NamePutProduct \ No newline at end of file diff --git a/src/NET8/template.yaml b/src/NET8/template.yaml index c6c34f7..0e49fe0 100644 --- a/src/NET8/template.yaml +++ b/src/NET8/template.yaml @@ -1,10 +1,17 @@ AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 +Parameters: + x86FunctionNamePrefix: + Type: String + Default: Net8-X86 + arm64FunctionNamePrefix: + Type: String + Default: Net8-Arm64 + Globals: Function: MemorySize: 1024 - Architectures: ["x86_64"] Runtime: provided.al2 Timeout: 30 Tracing: Active @@ -13,16 +20,19 @@ Globals: PRODUCT_TABLE_NAME: !Ref Table Resources: - GetProductsFunction: + #X86 + GetProductsFunctionX86: Type: AWS::Serverless::Function Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,GetProducts]] + Architectures: [x86_64] CodeUri: ./ Handler: bootstrap Events: Api: Type: HttpApi Properties: - Path: / + Path: /x86 Method: GET Policies: - DynamoDBReadPolicy: @@ -31,16 +41,18 @@ Resources: Metadata: BuildMethod: makefile - GetProductFunction: + GetProductFunctionX86: Type: AWS::Serverless::Function Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,GetProduct]] + Architectures: [x86_64] CodeUri: ./ Handler: GetProduct Events: Api: Type: HttpApi Properties: - Path: /{id} + Path: /x86/{id} Method: GET Policies: - Version: "2012-10-17" @@ -51,16 +63,18 @@ Resources: Metadata: BuildMethod: makefile - DeleteProductFunction: + DeleteProductFunctionX86: Type: AWS::Serverless::Function Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,DeleteProduct]] + Architectures: [x86_64] CodeUri: ./ Handler: DeleteProduct Events: Api: Type: HttpApi Properties: - Path: /{id} + Path: /x86/{id} Method: DELETE Policies: - Version: "2012-10-17" @@ -73,16 +87,18 @@ Resources: Metadata: BuildMethod: makefile - PutProductFunction: + PutProductFunctionX86: Type: AWS::Serverless::Function Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,PutProduct]] + Architectures: [x86_64] CodeUri: ./ Handler: PutProduct Events: Api: Type: HttpApi Properties: - Path: /{id} + Path: /x86/{id} Method: PUT Policies: - Version: "2012-10-17" @@ -92,37 +108,94 @@ Resources: Resource: !GetAtt Table.Arn Metadata: BuildMethod: makefile + #ARM64 + GetProductsFunctionArm64: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProducts]] + Architectures: [arm64] + CodeUri: ./ + Handler: bootstrap + Events: + Api: + Type: HttpApi + Properties: + Path: /arm64 + Method: GET + Policies: + - DynamoDBReadPolicy: + TableName: + !Ref Table + Metadata: + BuildMethod: makefile - GenerateLoadTestResults: + GetProductFunctionArm64: Type: AWS::Serverless::Function Properties: - CodeUri: ./GenerateLoadTestResults/ - Handler: GenerateLoadTestResults::GenerateLoadTestResults.Function::FunctionHandler - Runtime: dotnet6 + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProduct]] + Architectures: [arm64] + CodeUri: ./ + Handler: GetProduct Events: Api: Type: HttpApi Properties: - Path: /test-results + Path: /arm64/{id} Method: GET - Environment: - Variables: - LOG_GROUP_PREFIX: !Sub "/aws/lambda/net-8-base-" - LOAD_TEST_TYPE: "NET 8" - LAMBDA_ARCHITECTURE: "x86_64" Policies: - Version: "2012-10-17" Statement: - - Sid: AllowStartQueries - Effect: Allow + - Effect: Allow + Action: dynamodb:GetItem + Resource: !GetAtt Table.Arn + Metadata: + BuildMethod: makefile + + DeleteProductFunctionArm64: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,DeleteProduct]] + Architectures: [arm64] + CodeUri: ./ + Handler: DeleteProduct + Events: + Api: + Type: HttpApi + Properties: + Path: /arm64/{id} + Method: DELETE + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow Action: - - logs:DescribeLogGroups - - logs:StartQuery - Resource: "*" - - Sid: AllowGetQueryResults - Effect: Allow - Action: logs:GetQueryResults - Resource: "*" + - dynamodb:DeleteItem + - dynamodb:GetItem + Resource: !GetAtt Table.Arn + Metadata: + BuildMethod: makefile + + PutProductFunctionArm64: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,PutProduct]] + Architectures: [arm64] + CodeUri: ./ + Handler: PutProduct + Events: + Api: + Type: HttpApi + Properties: + Path: /arm64/{id} + Method: PUT + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: dynamodb:PutItem + Resource: !GetAtt Table.Arn + Metadata: + BuildMethod: makefile Table: Type: AWS::DynamoDB::Table @@ -138,4 +211,38 @@ Resources: Outputs: ApiUrl: Description: "API Gateway endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/" \ No newline at end of file + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" + ApiUrlX86: + Description: "X86 API endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86" + ApiUrlArm64: + Description: "Arm64 GateAPI endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64" + + #x86 + LambdaX86NameGetProducts: + Description: "Lambda X86 GetProducts" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,GetProducts]] + LambdaX86NameGetProduct: + Description: "Lambda X86 GetProduct" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,GetProduct]] + LambdaX86NameDeleteProduct: + Description: "Lambda X86 DeleteProduct" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,DeleteProduct]] + LambdaX86NamePutProduct: + Description: "Lambda X86 PutProduct" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,PutProduct]] + + #arm64 + LambdaArm64NameGetProducts: + Description: "Lambda X86 GetProducts" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProducts]] + LambdaArm64NameGetProduct: + Description: "Lambda X86 GetProduct" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProduct]] + LambdaArm64NameDeleteProduct: + Description: "Lambda X86 DeleteProduct" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,DeleteProduct]] + LambdaArm64NamePutProduct: + Description: "Lambda X86 PutProduct" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,PutProduct]] \ No newline at end of file From e340cec061256763897d855c1d75ec4a41aaf685 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Fri, 10 Nov 2023 21:48:56 +0100 Subject: [PATCH 11/24] adding net8 load test in global script --- loadtest/codebuild/run-all-load-tests.sh | 11 +++++++++++ src/NET8MinimalAPI/run-loadtest.sh | 3 +-- src/NET8MinimalAPI/template.yaml | 10 +++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index f64b9cf..0156363 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -50,6 +50,17 @@ else source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi +#export LT_NET8_MINIMAL_API=1 +if [ "$LT_NET8" != yes ]; +then + echo SKIPPING net8 :$LT_NET8 +else + echo "RUNNING load test for net8" + cd ../../src/NET8/ + source ./deploy.sh $DELETE_STACK + source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE +fi + #export LT_NET8_MINIMAL_API=1 if [ "$LT_NET8_MINIMAL_API" != yes ]; then diff --git a/src/NET8MinimalAPI/run-loadtest.sh b/src/NET8MinimalAPI/run-loadtest.sh index 41344f0..4c69913 100755 --- a/src/NET8MinimalAPI/run-loadtest.sh +++ b/src/NET8MinimalAPI/run-loadtest.sh @@ -45,7 +45,7 @@ function RunLoadTest() #get test params from cloud formation output echo "${COLOR}" - API_URL=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + export API_URL=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ --query "Stacks[0].Outputs[?OutputKey=='$2'].OutputValue" \ --output text) echo API URL: $API_URL @@ -73,7 +73,6 @@ function RunLoadTest() echo -------------------------------------------- echo "${NO_COLOR}" artillery run \ - --target "$API_URL" \ --overrides '{"config": { "phases": [{ "duration": '$TEST_DURATIOMN_SEC', "arrivalRate": 100 }] } }' \ --quiet \ ../../loadtest/load-test.yml diff --git a/src/NET8MinimalAPI/template.yaml b/src/NET8MinimalAPI/template.yaml index e5501b8..abb40f5 100644 --- a/src/NET8MinimalAPI/template.yaml +++ b/src/NET8MinimalAPI/template.yaml @@ -40,6 +40,8 @@ Resources: - DynamoDBCrudPolicy: TableName: !Ref Table + Metadata: + BuildMethod: makefile MinimalApiArm64: Type: AWS::Serverless::Function Properties: @@ -60,6 +62,8 @@ Resources: - DynamoDBCrudPolicy: TableName: !Ref Table + Metadata: + BuildMethod: makefile Table: Type: AWS::DynamoDB::Table @@ -77,16 +81,16 @@ Resources: Outputs: ApiUrl: Description: "API Gateway endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" LambdaX86Name: Description: "Lambda X86 Name" Value: !Ref x86FunctionName ApiUrlX86: Description: "X86 API endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86/" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86" LambdaArm64Name: Description: "Lambda Arm64 Name" Value: !Ref arm64FunctionName ApiUrlArm64: Description: "Arm64 GateAPI endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64/" \ No newline at end of file + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64" \ No newline at end of file From d0a285ae30989522154d5b901a2e0a8eea0ef892 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Fri, 10 Nov 2023 22:34:11 +0100 Subject: [PATCH 12/24] saving NET8 load test report in artifacts --- loadtest/codebuild/load-test-buildspec.yml | 1 + .../DeleteProduct/DeleteProduct.csproj | 12 +- .../GenerateLoadTestResults/DateUtils.cs | 13 -- .../GenerateLoadTestResults/Function.cs | 146 --------------- .../GenerateLoadTestResults.csproj | 17 -- .../GenerateLoadTestResults/QueryResult.cs | 25 --- src/NET8Native/GetProduct/GetProduct.csproj | 12 +- src/NET8Native/GetProducts/GetProducts.csproj | 12 +- src/NET8Native/Makefile | 28 ++- src/NET8Native/PutProduct/PutProduct.csproj | 12 +- src/NET8Native/Shared/Shared.csproj | 8 +- src/NET8Native/deploy.sh | 43 +++++ src/NET8Native/run-loadtest.sh | 153 ++++++++++++++++ src/NET8Native/template.yaml | 166 ++++++++++++++++-- .../ApiBootstrap/ApiBootstrap.csproj | 8 +- 15 files changed, 401 insertions(+), 255 deletions(-) delete mode 100644 src/NET8Native/GenerateLoadTestResults/DateUtils.cs delete mode 100644 src/NET8Native/GenerateLoadTestResults/Function.cs delete mode 100644 src/NET8Native/GenerateLoadTestResults/GenerateLoadTestResults.csproj delete mode 100644 src/NET8Native/GenerateLoadTestResults/QueryResult.cs create mode 100755 src/NET8Native/deploy.sh create mode 100755 src/NET8Native/run-loadtest.sh diff --git a/loadtest/codebuild/load-test-buildspec.yml b/loadtest/codebuild/load-test-buildspec.yml index 1feec27..8e5a880 100644 --- a/loadtest/codebuild/load-test-buildspec.yml +++ b/loadtest/codebuild/load-test-buildspec.yml @@ -14,5 +14,6 @@ artifacts: files: - src/NET6MinimalAPI/Report/* - src/NET6MinimalAPIWebAdapter/Report/* + - src/NET8/Report/* - src/NET8MinimalAPI/Report/* name: loadtest-$(date +%Y-%m-%H-%M) \ No newline at end of file diff --git a/src/NET8Native/DeleteProduct/DeleteProduct.csproj b/src/NET8Native/DeleteProduct/DeleteProduct.csproj index 1be8350..f64c696 100644 --- a/src/NET8Native/DeleteProduct/DeleteProduct.csproj +++ b/src/NET8Native/DeleteProduct/DeleteProduct.csproj @@ -16,12 +16,12 @@ - - - - - - + + + + + + diff --git a/src/NET8Native/GenerateLoadTestResults/DateUtils.cs b/src/NET8Native/GenerateLoadTestResults/DateUtils.cs deleted file mode 100644 index c37c43d..0000000 --- a/src/NET8Native/GenerateLoadTestResults/DateUtils.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace GenerateLoadTestResults; - -public static class DateUtils -{ - public static long AsUnixTimestamp(this DateTime date) - { - DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); - TimeSpan diff = date.ToUniversalTime() - origin; - return (long)Math.Floor(diff.TotalSeconds); - } -} \ No newline at end of file diff --git a/src/NET8Native/GenerateLoadTestResults/Function.cs b/src/NET8Native/GenerateLoadTestResults/Function.cs deleted file mode 100644 index 21a57a8..0000000 --- a/src/NET8Native/GenerateLoadTestResults/Function.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text.Json; -using System.Threading.Tasks; -using Amazon.CloudWatchLogs; -using Amazon.CloudWatchLogs.Model; -using Amazon.Lambda.APIGatewayEvents; -using Amazon.Lambda.Core; - -[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] - -namespace GenerateLoadTestResults -{ - public class Function - { - private AmazonCloudWatchLogsClient _cloudWatchLogsClient; - - public Function() - { - this._cloudWatchLogsClient = new AmazonCloudWatchLogsClient(); - } - - public async Task FunctionHandler( - APIGatewayHttpApiV2ProxyRequest apigProxyEvent, - ILambdaContext context) - { - if (!apigProxyEvent.RequestContext.Http.Method.Equals(HttpMethod.Get.Method)) - { - return new APIGatewayHttpApiV2ProxyResponse - { - Body = "Only GET allowed", - StatusCode = (int) HttpStatusCode.MethodNotAllowed, - }; - } - - try - { - var resultRows = 0; - var queryCount = 0; - - List> finalResults = new List>(); - - while (resultRows < 2 || queryCount >= 3) - { - finalResults = await runQuery(context); - - resultRows = finalResults.Count; - queryCount++; - } - - var wrapper = new QueryResultWrapper() - { - LoadTestType = - $"{Environment.GetEnvironmentVariable("LOAD_TEST_TYPE")} ({Environment.GetEnvironmentVariable("LAMBDA_ARCHITECTURE")})", - WarmStart = new QueryResult() - { - Count = finalResults[0][1].Value, - P50 = finalResults[0][2].Value, - P90 = finalResults[0][3].Value, - P99 = finalResults[0][4].Value, - Max = finalResults[0][5].Value, - }, - ColdStart = new QueryResult() - { - Count = finalResults[1][1].Value, - P50 = finalResults[1][2].Value, - P90 = finalResults[1][3].Value, - P99 = finalResults[1][4].Value, - Max = finalResults[1][5].Value, - } - }; - - return new APIGatewayHttpApiV2ProxyResponse - { - StatusCode = (int) HttpStatusCode.OK, - Body = wrapper.AsMarkdownTableRow(), - Headers = new Dictionary {{"Content-Type", "text/html"}} - }; - } - catch (Exception e) - { - context.Logger.LogLine($"Error retrieving results {e.Message} {e.StackTrace}"); - - return new APIGatewayHttpApiV2ProxyResponse - { - Body = "Not Found", - StatusCode = (int) HttpStatusCode.InternalServerError, - }; - } - } - - private async Task>> runQuery(ILambdaContext context) - { - var logGroupNamePrefix = - $"{Environment.GetEnvironmentVariable("LOG_GROUP_PREFIX")}{Environment.GetEnvironmentVariable("LAMBDA_ARCHITECTURE")}" - .Replace("_", "-"); - - context.Logger.LogLine($"Retrieving log groups with prefix {logGroupNamePrefix}"); - - var logGroupList = await _cloudWatchLogsClient.DescribeLogGroupsAsync(new DescribeLogGroupsRequest() - { - LogGroupNamePrefix = logGroupNamePrefix, - }); - - context.Logger.LogLine($"Found {logGroupList.LogGroups.Count} log group(s)"); - - var queryRes = await _cloudWatchLogsClient.StartQueryAsync(new StartQueryRequest() - { - LogGroupNames = logGroupList.LogGroups.Select(p => p.LogGroupName).ToList(), - QueryString = - "filter @type=\"REPORT\" | fields greatest(@initDuration, 0) + @duration as duration, ispresent(@initDuration) as coldstart | stats count(*) as count, pct(duration, 50) as p50, pct(duration, 90) as p90, pct(duration, 99) as p99, max(duration) as max by coldstart", - StartTime = DateTime.Now.AddMinutes(-20).AsUnixTimestamp(), - EndTime = DateTime.Now.AsUnixTimestamp(), - }); - - context.Logger.LogLine($"Running query, query id is {queryRes.QueryId}"); - - QueryStatus currentQueryStatus = QueryStatus.Running; - List> finalResults = new List>(); - - while (currentQueryStatus == QueryStatus.Running || currentQueryStatus == QueryStatus.Scheduled) - { - context.Logger.LogLine("Retrieving query results"); - - var queryResults = await _cloudWatchLogsClient.GetQueryResultsAsync(new GetQueryResultsRequest() - { - QueryId = queryRes.QueryId - }); - - context.Logger.LogLine($"Query result status is {queryResults.Status}"); - - currentQueryStatus = queryResults.Status; - finalResults = queryResults.Results; - - await Task.Delay(TimeSpan.FromSeconds(5)); - } - - context.Logger.LogLine($"Final results: {finalResults.Count} row(s)"); - - return finalResults; - } - } -} \ No newline at end of file diff --git a/src/NET8Native/GenerateLoadTestResults/GenerateLoadTestResults.csproj b/src/NET8Native/GenerateLoadTestResults/GenerateLoadTestResults.csproj deleted file mode 100644 index 4a8d708..0000000 --- a/src/NET8Native/GenerateLoadTestResults/GenerateLoadTestResults.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - net6.0 - true - true - - - - - - - - - - - diff --git a/src/NET8Native/GenerateLoadTestResults/QueryResult.cs b/src/NET8Native/GenerateLoadTestResults/QueryResult.cs deleted file mode 100644 index 69b5a31..0000000 --- a/src/NET8Native/GenerateLoadTestResults/QueryResult.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace GenerateLoadTestResults; - -public record QueryResultWrapper -{ - public string LoadTestType { get; set; } - - public QueryResult ColdStart { get; set; } - - public QueryResult WarmStart { get; set; } - - public string AsMarkdownTableRow() => $"
Cold Start (ms)Warm Start (ms)
p50p90p99maxp50p90p99max
{LoadTestType}{ColdStart.P50}{ColdStart.P90}{ColdStart.P99}{ColdStart.Max}{WarmStart.P50}{WarmStart.P90}{WarmStart.P99}{WarmStart.Max}
"; -} - -public record QueryResult -{ - public string Count { get; set; } - - public string P50 { get; set; } - - public string P90 { get; set; } - - public string P99 { get; set; } - - public string Max { get; set; } -} \ No newline at end of file diff --git a/src/NET8Native/GetProduct/GetProduct.csproj b/src/NET8Native/GetProduct/GetProduct.csproj index 1354b30..e070d2e 100644 --- a/src/NET8Native/GetProduct/GetProduct.csproj +++ b/src/NET8Native/GetProduct/GetProduct.csproj @@ -18,12 +18,12 @@ Speed - - - - - - + + + + + + diff --git a/src/NET8Native/GetProducts/GetProducts.csproj b/src/NET8Native/GetProducts/GetProducts.csproj index 578c023..7f65871 100644 --- a/src/NET8Native/GetProducts/GetProducts.csproj +++ b/src/NET8Native/GetProducts/GetProducts.csproj @@ -15,12 +15,12 @@ Speed - - - - - - + + + + + + diff --git a/src/NET8Native/Makefile b/src/NET8Native/Makefile index 9cc4200..4850513 100644 --- a/src/NET8Native/Makefile +++ b/src/NET8Native/Makefile @@ -1,11 +1,23 @@ -build-GetProductsFunction: - dotnet publish -c Release -r linux-x64 ./GetProducts/GetProducts.csproj -o $(ARTIFACTS_DIR) +build-GetProductFunctionX86: + dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) -build-GetProductFunction: - dotnet publish -c Release -r linux-x64 ./GetProduct/GetProduct.csproj -o $(ARTIFACTS_DIR) +build-GetProductsFunctionX86: + dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) -build-DeleteProductFunction: - dotnet publish -c Release -r linux-x64 ./DeleteProduct/DeleteProduct.csproj -o $(ARTIFACTS_DIR) +build-PutProductFunctionX86: + dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) -build-PutProductFunction: - dotnet publish -c Release -r linux-x64 ./PutProduct/PutProduct.csproj -o $(ARTIFACTS_DIR) \ No newline at end of file +build-DeleteProductFunctionX86: + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) + +build-GetProductFunctionArm64: + dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + +build-GetProductsFunctionArm64: + dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + +build-PutProductFunctionArm64: + dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + +build-DeleteProductFunctionArm64: + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8Native/PutProduct/PutProduct.csproj b/src/NET8Native/PutProduct/PutProduct.csproj index 1be8350..f64c696 100644 --- a/src/NET8Native/PutProduct/PutProduct.csproj +++ b/src/NET8Native/PutProduct/PutProduct.csproj @@ -16,12 +16,12 @@ - - - - - - + + + + + + diff --git a/src/NET8Native/Shared/Shared.csproj b/src/NET8Native/Shared/Shared.csproj index a2b16db..cf01798 100644 --- a/src/NET8Native/Shared/Shared.csproj +++ b/src/NET8Native/Shared/Shared.csproj @@ -18,10 +18,10 @@ Speed - - - - + + + + diff --git a/src/NET8Native/deploy.sh b/src/NET8Native/deploy.sh new file mode 100755 index 0000000..9aae7f5 --- /dev/null +++ b/src/NET8Native/deploy.sh @@ -0,0 +1,43 @@ +#Arguments: +#$1 - delete stack formation to ensure that all test have same conditon and favour similar ammount of cold start events + +STACK_NAME=dotnet8 +DELETE_STACK=yes + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ "x$4" != x ]; +then + DELETE_STACK=$1 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DELETE_STACK: $DELETE_STACK +echo -------------------------------------------- +echo "${NO_COLOR}" + +if [ $DELETE_STACK == "yes" ]; +then + echo "${COLOR}" + echo -------------------------------------------- + echo DELETING STACK $STACK_NAME + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation delete-stack --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Waiting stack to be deleted + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Stack deleted + echo -------------------------------------------- + echo "${NO_COLOR}" +fi + +sam build +sam deploy --stack-name $STACK_NAME --resolve-s3 --s3-prefix $STACK_NAME --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file diff --git a/src/NET8Native/run-loadtest.sh b/src/NET8Native/run-loadtest.sh new file mode 100755 index 0000000..2391e84 --- /dev/null +++ b/src/NET8Native/run-loadtest.sh @@ -0,0 +1,153 @@ +#Arguments: +#$1 - load test duration in seconds +#$2 - log interval to be used in the cloudwatch query in minutes +#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat + +STACK_NAME=dotnet8 +TEST_DURATIOMN_SEC=60 +LOG_INTERVAL_MIN=20 +LOG_DELETE=yes + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ "x$1" != x ]; +then + TEST_DURATIOMN_SEC=$1 +fi + +if [ "x$2" != x ]; +then + LOG_INTERVAL_MIN=$2 +fi + +if [ "x$3" != x ]; +then + LOG_DELETE=$3 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DURATION:$TEST_DURATIOMN_SEC +echo LOG INTERVAL:$LOG_INTERVAL_MIN +echo LOG_DELETE: $LOG_DELETE +echo -------------------------------------------- +echo "${NO_COLOR}" + +mkdir -p Report + +function RunLoadTest() +{ + #Params: + #$1 - Architecture (x86 or arm64).Used for logging and naming report file + #$2 - Stack output name to get API Url + #$3 - Stack output name to get lambda name GetProducts + #$4 - Stack output name to get lambda name GetProduct + #$5 - Stack output name to get lambda name DeleteProduct + #$6 - Stack output name to get lambda name PutProduct + + #get test params from cloud formation output + echo "${COLOR}" + export API_URL=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$2'].OutputValue" \ + --output text) + echo API URL: $API_URL + + LAMBDA_GETPRODUCTS=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$3'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_GETPRODUCTS + + LAMBDA_GETPRODUCT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$4'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_GETPRODUCT + + LAMBDA_DELETEPRODUCT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$5'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_DELETEPRODUCT + + LAMBDA_PUTPRODUCT=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$6'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA_PUTPRODUCT + + if [ $LOG_DELETE == "yes" ]; + then + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_GETPRODUCTS + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_GETPRODUCTS + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_GETPRODUCT + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_GETPRODUCT + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_DELETEPRODUCT + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_DELETEPRODUCT + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA_PUTPRODUCT + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA_PUTPRODUCT + echo --------------------------------------------- + echo Waiting 10 sec. for deletion to complete + echo -------------------------------------------- + sleep 10 + fi + + #run load test with artillery + echo -------------------------------------------- + echo $1 RUNNING LOAD TEST $TEST_DURATIOMN_SEC sec $API_URL + echo -------------------------------------------- + echo "${NO_COLOR}" + artillery run \ + --overrides '{"config": { "phases": [{ "duration": '$TEST_DURATIOMN_SEC', "arrivalRate": 100 }] } }' \ + --quiet \ + ../../loadtest/codebuild/load-test.yml + + echo "${COLOR}" + echo -------------------------------------------- + echo Waiting 10 sec. for logs to consolidate + echo -------------------------------------------- + sleep 10 + + #get stats from cloudwatch + enddate=$(date "+%s") + startdate=$(($enddate-($LOG_INTERVAL_MIN*60))) + echo -------------------------------------------- + echo Log start:$startdate end:$enddate + echo -------------------------------------------- + + QUERY_ID=$(aws logs start-query \ + --log-group-names "/aws/lambda/$LAMBDA_GETPRODUCTS" "/aws/lambda/$LAMBDA_GETPRODUCT" "/aws/lambda/$LAMBDA_DELETEPRODUCT" "/aws/lambda/$LAMBDA_PUTPRODUCT" \ + --start-time $startdate \ + --end-time $enddate \ + --query-string 'filter @type="REPORT" | fields greatest(@initDuration, 0) + @duration as duration, ispresent(@initDuration) as coldstart | stats count(*) as count, pct(duration, 50) as p50, pct(duration, 90) as p90, pct(duration, 99) as p99, max(duration) as max by coldstart' \ + | jq -r '.queryId') + + echo -------------------------------------------- + echo Query started, id: $QUERY_ID + echo -------------------------------------------- + + echo --------------------------------------------- + echo Waiting 10 sec. for cloudwatch query to complete + echo -------------------------------------------- + sleep 10 + + echo -------------------------------------------- + echo RESULTS $1 + echo -------------------------------------------- + echo "${NO_COLOR}" + date > ./Report/load-test-report-$1.txt + echo $1 RESULTS >> ./Report/load-test-report-$1.txt + echo Test duration sec: $TEST_DURATIOMN_SEC >> ./Report/load-test-report-$1.txt + echo Log interval min: $LOG_INTERVAL_MIN >> ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt + cat ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json +} + +RunLoadTest x86 ApiUrlX86 LambdaX86NameGetProducts LambdaX86NameGetProduct LambdaX86NameDeleteProduct LambdaX86NamePutProduct +RunLoadTest arm64 ApiUrlArm64 LambdaArm64NameGetProducts LambdaArm64NameGetProduct LambdaArm64NameDeleteProduct LambdaArm64NamePutProduct \ No newline at end of file diff --git a/src/NET8Native/template.yaml b/src/NET8Native/template.yaml index 22dc554..0e49fe0 100644 --- a/src/NET8Native/template.yaml +++ b/src/NET8Native/template.yaml @@ -1,10 +1,17 @@ AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 +Parameters: + x86FunctionNamePrefix: + Type: String + Default: Net8-X86 + arm64FunctionNamePrefix: + Type: String + Default: Net8-Arm64 + Globals: Function: MemorySize: 1024 - Architectures: ["x86_64"] Runtime: provided.al2 Timeout: 30 Tracing: Active @@ -13,16 +20,107 @@ Globals: PRODUCT_TABLE_NAME: !Ref Table Resources: - GetProductsFunction: + #X86 + GetProductsFunctionX86: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,GetProducts]] + Architectures: [x86_64] + CodeUri: ./ + Handler: bootstrap + Events: + Api: + Type: HttpApi + Properties: + Path: /x86 + Method: GET + Policies: + - DynamoDBReadPolicy: + TableName: + !Ref Table + Metadata: + BuildMethod: makefile + + GetProductFunctionX86: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,GetProduct]] + Architectures: [x86_64] + CodeUri: ./ + Handler: GetProduct + Events: + Api: + Type: HttpApi + Properties: + Path: /x86/{id} + Method: GET + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: dynamodb:GetItem + Resource: !GetAtt Table.Arn + Metadata: + BuildMethod: makefile + + DeleteProductFunctionX86: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,DeleteProduct]] + Architectures: [x86_64] + CodeUri: ./ + Handler: DeleteProduct + Events: + Api: + Type: HttpApi + Properties: + Path: /x86/{id} + Method: DELETE + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - dynamodb:DeleteItem + - dynamodb:GetItem + Resource: !GetAtt Table.Arn + Metadata: + BuildMethod: makefile + + PutProductFunctionX86: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Join [ -,[!Ref x86FunctionNamePrefix,PutProduct]] + Architectures: [x86_64] + CodeUri: ./ + Handler: PutProduct + Events: + Api: + Type: HttpApi + Properties: + Path: /x86/{id} + Method: PUT + Policies: + - Version: "2012-10-17" + Statement: + - Effect: Allow + Action: dynamodb:PutItem + Resource: !GetAtt Table.Arn + Metadata: + BuildMethod: makefile + #ARM64 + GetProductsFunctionArm64: Type: AWS::Serverless::Function Properties: - CodeUri: . + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProducts]] + Architectures: [arm64] + CodeUri: ./ Handler: bootstrap Events: Api: Type: HttpApi Properties: - Path: / + Path: /arm64 Method: GET Policies: - DynamoDBReadPolicy: @@ -31,16 +129,18 @@ Resources: Metadata: BuildMethod: makefile - GetProductFunction: + GetProductFunctionArm64: Type: AWS::Serverless::Function Properties: - CodeUri: . + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProduct]] + Architectures: [arm64] + CodeUri: ./ Handler: GetProduct Events: Api: Type: HttpApi Properties: - Path: /{id} + Path: /arm64/{id} Method: GET Policies: - Version: "2012-10-17" @@ -51,16 +151,18 @@ Resources: Metadata: BuildMethod: makefile - DeleteProductFunction: + DeleteProductFunctionArm64: Type: AWS::Serverless::Function Properties: - CodeUri: . + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,DeleteProduct]] + Architectures: [arm64] + CodeUri: ./ Handler: DeleteProduct Events: Api: Type: HttpApi Properties: - Path: /{id} + Path: /arm64/{id} Method: DELETE Policies: - Version: "2012-10-17" @@ -73,16 +175,18 @@ Resources: Metadata: BuildMethod: makefile - PutProductFunction: + PutProductFunctionArm64: Type: AWS::Serverless::Function Properties: - CodeUri: . + FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,PutProduct]] + Architectures: [arm64] + CodeUri: ./ Handler: PutProduct Events: Api: Type: HttpApi Properties: - Path: /{id} + Path: /arm64/{id} Method: PUT Policies: - Version: "2012-10-17" @@ -107,4 +211,38 @@ Resources: Outputs: ApiUrl: Description: "API Gateway endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/" \ No newline at end of file + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" + ApiUrlX86: + Description: "X86 API endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86" + ApiUrlArm64: + Description: "Arm64 GateAPI endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64" + + #x86 + LambdaX86NameGetProducts: + Description: "Lambda X86 GetProducts" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,GetProducts]] + LambdaX86NameGetProduct: + Description: "Lambda X86 GetProduct" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,GetProduct]] + LambdaX86NameDeleteProduct: + Description: "Lambda X86 DeleteProduct" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,DeleteProduct]] + LambdaX86NamePutProduct: + Description: "Lambda X86 PutProduct" + Value: !Join [ -,[!Ref x86FunctionNamePrefix,PutProduct]] + + #arm64 + LambdaArm64NameGetProducts: + Description: "Lambda X86 GetProducts" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProducts]] + LambdaArm64NameGetProduct: + Description: "Lambda X86 GetProduct" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProduct]] + LambdaArm64NameDeleteProduct: + Description: "Lambda X86 DeleteProduct" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,DeleteProduct]] + LambdaArm64NamePutProduct: + Description: "Lambda X86 PutProduct" + Value: !Join [ -,[!Ref arm64FunctionNamePrefix,PutProduct]] \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj b/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj index 48bb4ef..7e0bdad 100644 --- a/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj +++ b/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj @@ -15,10 +15,10 @@ - - - - + + + + From d9a422eb71029e95efc2b9e60a6f0fc1702aa5ba Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Fri, 10 Nov 2023 23:06:51 +0100 Subject: [PATCH 13/24] updatin net 8 projects --- src/NET8/Report/load-test-report-.json | 0 src/NET8/Report/load-test-report-.txt | 2 - src/NET8/Report/load-test-report-arm64.json | 186 ------------- src/NET8/Report/load-test-report-arm64.txt | 18 -- src/NET8/Report/load-test-report-x86.json | 260 ------------------ src/NET8/Report/load-test-report-x86.txt | 18 -- src/NET8MinimalAPI/Makefile | 2 - src/NET8MinimalAPI/Shared/Shared.csproj | 2 +- src/NET8Native/Makefile | 16 +- .../ApiBootstrap/ApiBootstrap.csproj | 7 +- .../ApiBootstrap/Function.cs | 163 ++++++----- src/NET8NativeMinimalAPI/Makefile | 6 +- .../Shared/DataAccess/DynamoDbProducts.cs | 5 +- .../Shared/DataAccess/ProductMapper.cs | 4 +- .../Shared/DataAccess/ProductsDAO.cs | 3 +- .../Shared/Models/Product.cs | 11 +- .../Shared/Models/ProductWrapper.cs | 4 +- src/NET8NativeMinimalAPI/Shared/Shared.csproj | 4 +- src/NET8NativeMinimalAPI/Shared/Startup.cs | 7 +- src/NET8NativeMinimalAPI/deploy.sh | 43 +++ src/NET8NativeMinimalAPI/run-loadtest.sh | 123 +++++++++ src/NET8NativeMinimalAPI/template.yaml | 72 +++-- 22 files changed, 348 insertions(+), 608 deletions(-) delete mode 100644 src/NET8/Report/load-test-report-.json delete mode 100644 src/NET8/Report/load-test-report-.txt delete mode 100644 src/NET8/Report/load-test-report-arm64.json delete mode 100644 src/NET8/Report/load-test-report-arm64.txt delete mode 100644 src/NET8/Report/load-test-report-x86.json delete mode 100644 src/NET8/Report/load-test-report-x86.txt create mode 100755 src/NET8NativeMinimalAPI/deploy.sh create mode 100755 src/NET8NativeMinimalAPI/run-loadtest.sh diff --git a/src/NET8/Report/load-test-report-.json b/src/NET8/Report/load-test-report-.json deleted file mode 100644 index e69de29..0000000 diff --git a/src/NET8/Report/load-test-report-.txt b/src/NET8/Report/load-test-report-.txt deleted file mode 100644 index 183df41..0000000 --- a/src/NET8/Report/load-test-report-.txt +++ /dev/null @@ -1,2 +0,0 @@ -Test duration sec: 60 -Log interval min: 20 diff --git a/src/NET8/Report/load-test-report-arm64.json b/src/NET8/Report/load-test-report-arm64.json deleted file mode 100644 index a6c8a0a..0000000 --- a/src/NET8/Report/load-test-report-arm64.json +++ /dev/null @@ -1,186 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "806" - }, - { - "field": "p50", - "value": "9.5341" - }, - { - "field": "p90", - "value": "22.7017" - }, - { - "field": "p99", - "value": "42.4839" - }, - { - "field": "max", - "value": "107.71" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "146" - }, - { - "field": "p50", - "value": "1725.5032" - }, - { - "field": "p90", - "value": "1801.2795" - }, - { - "field": "p99", - "value": "1865.4079" - }, - { - "field": "max", - "value": "1961.07" - } - ] - ], - "statistics": { - "recordsMatched": 952.0, - "recordsScanned": 4680.0, - "bytesScanned": 1408784.0 - }, - "status": "Complete" -} -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "1968" - }, - { - "field": "p50", - "value": "9.7659" - }, - { - "field": "p90", - "value": "22.5459" - }, - { - "field": "p99", - "value": "38.4524" - }, - { - "field": "max", - "value": "113.03" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "334" - }, - { - "field": "p50", - "value": "1725.5032" - }, - { - "field": "p90", - "value": "1792.3" - }, - { - "field": "p99", - "value": "1835.8135" - }, - { - "field": "max", - "value": "1915.31" - } - ] - ], - "statistics": { - "recordsMatched": 2302.0, - "recordsScanned": 9347.0, - "bytesScanned": 3833050.0 - }, - "status": "Complete" -} -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "1736" - }, - { - "field": "p50", - "value": "9.0179" - }, - { - "field": "p90", - "value": "21.3228" - }, - { - "field": "p99", - "value": "36.6573" - }, - { - "field": "max", - "value": "57.18" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "123" - }, - { - "field": "p50", - "value": "1703.2279" - }, - { - "field": "p90", - "value": "1756.8276" - }, - { - "field": "p99", - "value": "1812.1142" - }, - { - "field": "max", - "value": "1845.97" - } - ] - ], - "statistics": { - "recordsMatched": 1859.0, - "recordsScanned": 7270.0, - "bytesScanned": 2523694.0 - }, - "status": "Complete" -} diff --git a/src/NET8/Report/load-test-report-arm64.txt b/src/NET8/Report/load-test-report-arm64.txt deleted file mode 100644 index 6cc0f30..0000000 --- a/src/NET8/Report/load-test-report-arm64.txt +++ /dev/null @@ -1,18 +0,0 @@ -Fri Nov 10 21:22:49 CET 2023 -arm64 RESULTS -Test duration sec: 60 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 1736 -RESULTS p50 9.0179 -RESULTS p90 21.3228 -RESULTS p99 36.6573 -RESULTS max 57.18 -RESULTS coldstart 1 -RESULTS count 123 -RESULTS p50 1703.2279 -RESULTS p90 1756.8276 -RESULTS p99 1812.1142 -RESULTS max 1845.97 -STATISTICS 2523694.0 1859.0 7270.0 diff --git a/src/NET8/Report/load-test-report-x86.json b/src/NET8/Report/load-test-report-x86.json deleted file mode 100644 index 317de0a..0000000 --- a/src/NET8/Report/load-test-report-x86.json +++ /dev/null @@ -1,260 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "3387" - }, - { - "field": "p50", - "value": "5.6355" - }, - { - "field": "p90", - "value": "11.0938" - }, - { - "field": "p99", - "value": "28.4069" - }, - { - "field": "max", - "value": "65.62" - } - ] - ], - "statistics": { - "recordsMatched": 3387.0, - "recordsScanned": 27649.0, - "bytesScanned": 6866946.0 - }, - "status": "Complete" -} - -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "2742" - }, - { - "field": "p50", - "value": "6.9328" - }, - { - "field": "p90", - "value": "14.4304" - }, - { - "field": "p99", - "value": "34.3935" - }, - { - "field": "max", - "value": "54.72" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "445" - }, - { - "field": "p50", - "value": "1452.9626" - }, - { - "field": "p90", - "value": "1509.209" - }, - { - "field": "p99", - "value": "1608.9048" - }, - { - "field": "max", - "value": "1730.88" - } - ] - ], - "statistics": { - "recordsMatched": 3187.0, - "recordsScanned": 12122.0, - "bytesScanned": 4277937.0 - }, - "status": "Complete" -} -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "1010" - }, - { - "field": "p50", - "value": "9.6115" - }, - { - "field": "p90", - "value": "19.072" - }, - { - "field": "p99", - "value": "38.1472" - }, - { - "field": "max", - "value": "56.86" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "141" - }, - { - "field": "p50", - "value": "1457.3259" - }, - { - "field": "p90", - "value": "1503.1872" - }, - { - "field": "p99", - "value": "1556.7031" - }, - { - "field": "max", - "value": "1609.72" - } - ] - ], - "statistics": { - "recordsMatched": 1151.0, - "recordsScanned": 4761.0, - "bytesScanned": 2021156.0 - }, - "status": "Complete" -} - -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "2137" - }, - { - "field": "p50", - "value": "7.3743" - }, - { - "field": "p90", - "value": "9.0232" - }, - { - "field": "p99", - "value": "15.8828" - }, - { - "field": "max", - "value": "30.14" - } - ] - ], - "statistics": { - "recordsMatched": 2137.0, - "recordsScanned": 18984.0, - "bytesScanned": 8138385.0 - }, - "status": "Complete" -} -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "2538" - }, - { - "field": "p50", - "value": "6.9328" - }, - { - "field": "p90", - "value": "14.3159" - }, - { - "field": "p99", - "value": "30.2766" - }, - { - "field": "max", - "value": "66.97" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "441" - }, - { - "field": "p50", - "value": "1471.9649" - }, - { - "field": "p90", - "value": "1527.4194" - }, - { - "field": "p99", - "value": "1701.5263" - }, - { - "field": "max", - "value": "1958.74" - } - ] - ], - "statistics": { - "recordsMatched": 2979.0, - "recordsScanned": 11840.0, - "bytesScanned": 3773751.0 - }, - "status": "Complete" -} diff --git a/src/NET8/Report/load-test-report-x86.txt b/src/NET8/Report/load-test-report-x86.txt deleted file mode 100644 index a772c6d..0000000 --- a/src/NET8/Report/load-test-report-x86.txt +++ /dev/null @@ -1,18 +0,0 @@ -Fri Nov 10 21:20:45 CET 2023 -x86 RESULTS -Test duration sec: 60 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 2538 -RESULTS p50 6.9328 -RESULTS p90 14.3159 -RESULTS p99 30.2766 -RESULTS max 66.97 -RESULTS coldstart 1 -RESULTS count 441 -RESULTS p50 1471.9649 -RESULTS p90 1527.4194 -RESULTS p99 1701.5263 -RESULTS max 1958.74 -STATISTICS 3773751.0 2979.0 11840.0 diff --git a/src/NET8MinimalAPI/Makefile b/src/NET8MinimalAPI/Makefile index 4ec8c4a..ae88de0 100644 --- a/src/NET8MinimalAPI/Makefile +++ b/src/NET8MinimalAPI/Makefile @@ -1,6 +1,4 @@ build-MinimalApiX86: - dotnet clean dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) build-MinimalApiArm64: - dotnet clean dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8MinimalAPI/Shared/Shared.csproj b/src/NET8MinimalAPI/Shared/Shared.csproj index 50accf7..7d6a8a2 100644 --- a/src/NET8MinimalAPI/Shared/Shared.csproj +++ b/src/NET8MinimalAPI/Shared/Shared.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0 enable enable diff --git a/src/NET8Native/Makefile b/src/NET8Native/Makefile index 4850513..1a83e83 100644 --- a/src/NET8Native/Makefile +++ b/src/NET8Native/Makefile @@ -1,23 +1,23 @@ build-GetProductFunctionX86: - dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) + dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-GetProductsFunctionX86: - dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) + dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-PutProductFunctionX86: - dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) + dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-DeleteProductFunctionX86: - dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-GetProductFunctionArm64: - dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) build-GetProductsFunctionArm64: - dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) build-PutProductFunctionArm64: - dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) + dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) build-DeleteProductFunctionArm64: - dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-arm64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj b/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj index 7e0bdad..facf661 100644 --- a/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj +++ b/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj @@ -14,13 +14,14 @@ - + - - + + + diff --git a/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs b/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs index 0462ff5..10a82a7 100644 --- a/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs +++ b/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs @@ -1,5 +1,9 @@ +using System; +using System.Collections.Generic; using System.Net; using System.Text.Json; +using Amazon.CloudWatchLogs; +using Amazon.CloudWatchLogs.Model; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -9,115 +13,122 @@ using Shared.Models; var app = Startup.Build(args); +var basePath=Environment.GetEnvironmentVariable("DEMO_BASE_PATH"); +if(String.IsNullOrEmpty(basePath)) + app.Logger.LogInformation($"No BASE PATH specified"); +else +{ + app.Logger.LogInformation($"Using BASE PATH:{basePath}"); + app.UsePathBase(basePath); + app.UseRouting(); +} -Handlers.DataAccess = app.Services.GetRequiredService(); -Handlers.Logger = app.Logger; +var dataAccess = app.Services.GetRequiredService(); -app.MapGet("/", Handlers.GetAllProducts); +var cloudWatchClient = new AmazonCloudWatchLogsClient(); -app.MapDelete("/{id}", Handlers.DeleteProduct); +app.MapGet("/", async (HttpContext context) => +{ + app.Logger.LogInformation("Received request to list all products"); -app.MapPut("/{id}", Handlers.PutProduct); + var products = await dataAccess.GetAllProducts(); -app.MapGet("/{id}", Handlers.GetProduct); + app.Logger.LogInformation($"Found {products.Products.Count} products(s)"); -app.Run(); + context.Response.StatusCode = (int) HttpStatusCode.OK; + await context.Response.WriteAsJsonAsync(products); +}); -static class Handlers +app.MapDelete("/{id}", async (HttpContext context) => { - internal static ProductsDAO DataAccess; - internal static ILogger Logger; - - public static async Task GetAllProducts(HttpContext context) + try { - Logger.LogInformation("Received request to list all products"); + var id = context.Request.RouteValues["id"].ToString(); - var products = await DataAccess.GetAllProducts(); + app.Logger.LogInformation($"Received request to delete {id} from the database"); - Logger.LogInformation($"Found {products.Products.Count} products(s)"); + var product = await dataAccess.GetProduct(id); - await context.WriteResponse(HttpStatusCode.OK, products); - } - - public static async Task DeleteProduct(HttpContext context) - { - try + if (product == null) { - var id = context.Request.RouteValues["id"].ToString(); - - Logger.LogInformation($"Received request to delete {id}"); - - var product = await DataAccess.GetProduct(id); + app.Logger.LogWarning($"Id {id} not found."); - if (product == null) - { - Logger.LogWarning($"Id {id} not found."); + context.Response.StatusCode = (int) HttpStatusCode.NotFound; + Results.NotFound(); + return; + } - await context.WriteResponse(HttpStatusCode.NotFound); - - return; - } + app.Logger.LogInformation($"Deleting {product.Name}"); - Logger.LogInformation($"Deleting {product.Name}"); + await dataAccess.DeleteProduct(product.Id); - await DataAccess.DeleteProduct(product.Id); + app.Logger.LogInformation("Delete complete"); - Logger.LogInformation("Delete complete"); - - await context.WriteResponse(HttpStatusCode.OK, $"Product with id {id} deleted"); - } - catch (Exception e) - { - Logger.LogError(e, "Failure deleting product"); + context.Response.StatusCode = (int) HttpStatusCode.OK; + await context.Response.WriteAsJsonAsync($"Product with id {id} deleted"); + } + catch (Exception e) + { + app.Logger.LogError(e, "Failure deleting product"); - await context.WriteResponse(HttpStatusCode.BadRequest); - } + context.Response.StatusCode = (int) HttpStatusCode.NotFound; } +}); - public static async Task GetProduct(HttpContext context) +app.MapPut("/{id}", async (HttpContext context) => +{ + try { var id = context.Request.RouteValues["id"].ToString(); - - Logger.LogInformation($"Received request to get {id}"); - var product = await DataAccess.GetProduct(id); + app.Logger.LogInformation($"Received request to put {id}"); - if (product == null) - { - Logger.LogWarning($"{id} not found"); - await context.WriteResponse(HttpStatusCode.NotFound, $"{id} not found"); - } + var product = await JsonSerializer.DeserializeAsync(context.Request.Body); - await context.WriteResponse(HttpStatusCode.OK, product); - } - - public static async Task PutProduct(HttpContext context) - { - var id = context.Request.RouteValues["id"].ToString(); - var product = await JsonSerializer.DeserializeAsync(context.Request.Body, ApiSerializerContext.Default.Product); - if (product == null || id != product.Id) { - await context.WriteResponse(HttpStatusCode.BadRequest, "Product ID in the body does not match path parameter"); + app.Logger.LogWarning("Product ID in the body does not match path parameter"); + + context.Response.StatusCode = (int) HttpStatusCode.BadRequest; + await context.Response.WriteAsJsonAsync("Product ID in the body does not match path parameter"); + return; } - await DataAccess.PutProduct(product); + app.Logger.LogInformation("Putting product"); - await context.WriteResponse(HttpStatusCode.OK, $"Created product with id {id}"); - } -} + await dataAccess.PutProduct(product); -static class ResponseWriter -{ - public static async Task WriteResponse(this HttpContext context, HttpStatusCode statusCode) + app.Logger.LogTrace("Done"); + + context.Response.StatusCode = (int) HttpStatusCode.OK; + await context.Response.WriteAsJsonAsync($"Created product with id {id}"); + } + catch (Exception e) { - await context.WriteResponse(statusCode, ""); + app.Logger.LogError(e, "Failure deleting product"); + + context.Response.StatusCode = (int) HttpStatusCode.BadRequest; } - - public static async Task WriteResponse(this HttpContext context, HttpStatusCode statusCode, TResponseType body) where TResponseType : class +}); + +app.MapGet("/{id}", async (HttpContext context) => +{ + var id = context.Request.RouteValues["id"].ToString(); + + app.Logger.LogInformation($"Received request to get {id}"); + + var product = await dataAccess.GetProduct(id); + + if (product == null) { - context.Response.StatusCode = (int)statusCode; - context.Response.ContentType = "application/json"; - await context.Response.WriteAsync(JsonSerializer.Serialize(body, typeof(TResponseType), ApiSerializerContext.Default)); + app.Logger.LogWarning($"{id} not found"); + context.Response.StatusCode = (int) HttpStatusCode.NotFound; + Results.NotFound(); + return; } -} \ No newline at end of file + + context.Response.StatusCode = (int) HttpStatusCode.OK; + await context.Response.WriteAsJsonAsync(product); +}); + +app.Run(); \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/Makefile b/src/NET8NativeMinimalAPI/Makefile index fc76f1e..79df09e 100644 --- a/src/NET8NativeMinimalAPI/Makefile +++ b/src/NET8NativeMinimalAPI/Makefile @@ -1,2 +1,4 @@ -build-ApiFunction: - dotnet publish -c Release -r linux-x64 ./ApiBootstrap/ApiBootstrap.csproj -o $(ARTIFACTS_DIR) \ No newline at end of file +build-MinimalApiX86: + dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) +build-MinimalApiArm64: + dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs b/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs index e41da85..5f85635 100644 --- a/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs +++ b/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs @@ -1,4 +1,7 @@ -using Amazon.DynamoDBv2; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.Model; using Shared.Models; diff --git a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs index 7abc616..8e073ed 100644 --- a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs +++ b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs @@ -1,4 +1,6 @@ -using System.Globalization; +using System; +using System.Collections.Generic; +using System.Globalization; using Amazon.DynamoDBv2.Model; using Shared.Models; diff --git a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs index c1e13a6..d09decd 100644 --- a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs +++ b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs @@ -1,4 +1,5 @@ -using Shared.Models; +using System.Threading.Tasks; +using Shared.Models; namespace Shared.DataAccess { diff --git a/src/NET8NativeMinimalAPI/Shared/Models/Product.cs b/src/NET8NativeMinimalAPI/Shared/Models/Product.cs index 88a62ca..93f9896 100644 --- a/src/NET8NativeMinimalAPI/Shared/Models/Product.cs +++ b/src/NET8NativeMinimalAPI/Shared/Models/Product.cs @@ -1,4 +1,6 @@ -namespace Shared.Models +using System; + +namespace Shared.Models { public class Product { @@ -17,7 +19,12 @@ public Product(string id, string name, decimal price) public string Name { get; set; } - public decimal Price { get; set; } + public decimal Price { get; private set; } + + public void SetPrice(decimal newPrice) + { + this.Price = Math.Round(newPrice, 2); + } public override string ToString() { diff --git a/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs b/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs index 47cc485..c89af93 100644 --- a/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs +++ b/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs @@ -1,4 +1,6 @@ -namespace Shared.Models +using System.Collections.Generic; + +namespace Shared.Models { public class ProductWrapper { diff --git a/src/NET8NativeMinimalAPI/Shared/Shared.csproj b/src/NET8NativeMinimalAPI/Shared/Shared.csproj index 8361c85..7d6a8a2 100644 --- a/src/NET8NativeMinimalAPI/Shared/Shared.csproj +++ b/src/NET8NativeMinimalAPI/Shared/Shared.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/NET8NativeMinimalAPI/Shared/Startup.cs b/src/NET8NativeMinimalAPI/Shared/Startup.cs index 3926dc3..ef2b0db 100644 --- a/src/NET8NativeMinimalAPI/Shared/Startup.cs +++ b/src/NET8NativeMinimalAPI/Shared/Startup.cs @@ -1,6 +1,7 @@ using System.Text.Json; using Amazon.Lambda.Serialization.SystemTextJson; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Shared.DataAccess; @@ -33,11 +34,7 @@ public static WebApplication Build(string[] args) options.TimestampFormat = "hh:mm:ss "; }); - var app = builder.Build(); - - // Add generic app configuration here. - - return app; + return builder.Build(); } } } \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/deploy.sh b/src/NET8NativeMinimalAPI/deploy.sh new file mode 100755 index 0000000..7da02c0 --- /dev/null +++ b/src/NET8NativeMinimalAPI/deploy.sh @@ -0,0 +1,43 @@ +#Arguments: +#$1 - delete stack formation to ensure that all test have same conditon and favour similar ammount of cold start events + +STACK_NAME=dotnet8-native-minimal-api +DELETE_STACK=yes + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ "x$4" != x ]; +then + DELETE_STACK=$1 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DELETE_STACK: $DELETE_STACK +echo -------------------------------------------- +echo "${NO_COLOR}" + +if [ $DELETE_STACK == "yes" ]; +then + echo "${COLOR}" + echo -------------------------------------------- + echo DELETING STACK $STACK_NAME + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation delete-stack --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Waiting stack to be deleted + echo -------------------------------------------- + echo "${NO_COLOR}" + aws cloudformation wait stack-delete-complete --stack-name $STACK_NAME + echo "${COLOR}" + echo --------------------------------------------- + echo Stack deleted + echo -------------------------------------------- + echo "${NO_COLOR}" +fi + +sam build +sam deploy --stack-name dotnet8-minimal-api --resolve-s3 --s3-prefix dotnet8-minimal-api --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/run-loadtest.sh b/src/NET8NativeMinimalAPI/run-loadtest.sh new file mode 100755 index 0000000..8e7408e --- /dev/null +++ b/src/NET8NativeMinimalAPI/run-loadtest.sh @@ -0,0 +1,123 @@ +#Arguments: +#$1 - load test duration in seconds +#$2 - log interval to be used in the cloudwatch query in minutes +#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat + +STACK_NAME=dotnet8-native-minimal-api +TEST_DURATIOMN_SEC=60 +LOG_INTERVAL_MIN=20 +LOG_DELETE=yes + +COLOR='\033[0;33m' +NO_COLOR='\033[0m' # No Color + +if [ "x$1" != x ]; +then + TEST_DURATIOMN_SEC=$1 +fi + +if [ "x$2" != x ]; +then + LOG_INTERVAL_MIN=$2 +fi + +if [ "x$3" != x ]; +then + LOG_DELETE=$3 +fi + +echo "${COLOR}" +echo -------------------------------------------- +echo DURATION:$TEST_DURATIOMN_SEC +echo LOG INTERVAL:$LOG_INTERVAL_MIN +echo LOG_DELETE: $LOG_DELETE +echo -------------------------------------------- +echo "${NO_COLOR}" + +mkdir -p Report + +function RunLoadTest() +{ + #Params: + #$1 - Architecture (x86 or arm64).Used for logging and naming report file + #$2 - Stack output name to get API Url + #$3 - Stack output name to get lambda name + + #get test params from cloud formation output + echo "${COLOR}" + export API_URL=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$2'].OutputValue" \ + --output text) + echo API URL: $API_URL + + LAMBDA=$(aws cloudformation describe-stacks --stack-name $STACK_NAME \ + --query "Stacks[0].Outputs[?OutputKey=='$3'].OutputValue" \ + --output text) + echo LAMBDA: $LAMBDA + + if [ $LOG_DELETE == "yes" ]; + then + echo -------------------------------------------- + echo DELETING CLOUDWATCH LOG GROUP /aws/lambda/$LAMBDA + echo -------------------------------------------- + aws logs delete-log-group --log-group-name /aws/lambda/$LAMBDA + echo --------------------------------------------- + echo Waiting 10 sec. for deletion to complete + echo -------------------------------------------- + sleep 10 + fi + + #run load test with artillery + echo -------------------------------------------- + echo $1 RUNNING LOAD TEST $TEST_DURATIOMN_SEC sec $LAMBDA: $API_URL + echo -------------------------------------------- + echo "${NO_COLOR}" + artillery run \ + --overrides '{"config": { "phases": [{ "duration": '$TEST_DURATIOMN_SEC', "arrivalRate": 100 }] } }' \ + --quiet \ + ../../loadtest/load-test.yml + + echo "${COLOR}" + echo -------------------------------------------- + echo Waiting 10 sec. for logs to consolidate + echo -------------------------------------------- + sleep 10 + + #get stats from cloudwatch + enddate=$(date "+%s") + startdate=$(($enddate-($LOG_INTERVAL_MIN*60))) + echo -------------------------------------------- + echo Log start:$startdate end:$enddate + echo -------------------------------------------- + + QUERY_ID=$(aws logs start-query \ + --log-group-name /aws/lambda/$LAMBDA \ + --start-time $startdate \ + --end-time $enddate \ + --query-string 'filter @type="REPORT" | fields greatest(@initDuration, 0) + @duration as duration, ispresent(@initDuration) as coldstart | stats count(*) as count, pct(duration, 50) as p50, pct(duration, 90) as p90, pct(duration, 99) as p99, max(duration) as max by coldstart' \ + | jq -r '.queryId') + + echo -------------------------------------------- + echo Query started, id: $QUERY_ID + echo -------------------------------------------- + + echo --------------------------------------------- + echo Waiting 10 sec. for cloudwatch query to complete + echo -------------------------------------------- + sleep 10 + + echo -------------------------------------------- + echo RESULTS $LAMBDA + echo -------------------------------------------- + echo "${NO_COLOR}" + date > ./Report/load-test-report-$1.txt + echo $1 RESULTS lambda: $LAMBDA >> ./Report/load-test-report-$1.txt + echo Test duration sec: $TEST_DURATIOMN_SEC >> ./Report/load-test-report-$1.txt + echo Log interval min: $LOG_INTERVAL_MIN >> ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt + cat ./Report/load-test-report-$1.txt + aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json +} + +RunLoadTest x86 ApiUrlX86 LambdaX86Name +RunLoadTest arm64 ApiUrlArm64 LambdaArm64Name \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/template.yaml b/src/NET8NativeMinimalAPI/template.yaml index db2eb8e..abb40f5 100644 --- a/src/NET8NativeMinimalAPI/template.yaml +++ b/src/NET8NativeMinimalAPI/template.yaml @@ -1,47 +1,67 @@ AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 +Parameters: + x86FunctionName: + Type: String + Default: Net8-MinimalApi-X86 + arm64FunctionName: + Type: String + Default: Net8-MinimalApi-Arm64 + Globals: Function: MemorySize: 1024 - Architectures: ["x86_64"] Runtime: provided.al2 Timeout: 30 Tracing: Active Environment: Variables: PRODUCT_TABLE_NAME: !Ref Table - LOG_GROUP_PREFIX: !Sub "/aws/lambda/net-8-aot-minimal-" - LOAD_TEST_TYPE: "NET 8 native AOT Minimal API" Resources: - ApiFunction: + MinimalApiX86: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Ref x86FunctionName + Architectures: [x86_64] + CodeUri: ./ + Handler: ApiBootstrap + Environment: + Variables: + DEMO_BASE_PATH: /x86 + Events: + Api: + Type: HttpApi + Properties: + Path: /x86/{proxy+} + Method: ANY + Policies: + - DynamoDBCrudPolicy: + TableName: + !Ref Table + Metadata: + BuildMethod: makefile + MinimalApiArm64: Type: AWS::Serverless::Function Properties: - CodeUri: . + FunctionName: !Ref arm64FunctionName + Architectures: [arm64] + CodeUri: ./ Handler: ApiBootstrap + Environment: + Variables: + DEMO_BASE_PATH: /arm64 Events: Api: Type: HttpApi Properties: - Path: /{proxy+} + Path: /arm64/{proxy+} Method: ANY Policies: - DynamoDBCrudPolicy: TableName: !Ref Table - - Version: "2012-10-17" - Statement: - - Sid: AllowStartQueries - Effect: Allow - Action: - - logs:DescribeLogGroups - - logs:StartQuery - Resource: "*" - - Sid: AllowGetQueryResults - Effect: Allow - Action: logs:GetQueryResults - Resource: "*" Metadata: BuildMethod: makefile @@ -55,8 +75,22 @@ Resources: KeySchema: - AttributeName: id KeyType: HASH + StreamSpecification: + StreamViewType: NEW_AND_OLD_IMAGES Outputs: ApiUrl: Description: "API Gateway endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/" \ No newline at end of file + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" + LambdaX86Name: + Description: "Lambda X86 Name" + Value: !Ref x86FunctionName + ApiUrlX86: + Description: "X86 API endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86" + LambdaArm64Name: + Description: "Lambda Arm64 Name" + Value: !Ref arm64FunctionName + ApiUrlArm64: + Description: "Arm64 GateAPI endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64" \ No newline at end of file From 34efac06240ce0a679e36ddc3af3cd18162d013c Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sat, 11 Nov 2023 09:10:44 +0100 Subject: [PATCH 14/24] testing net8native --- loadtest/codebuild/run-all-load-tests.sh | 11 +++++++++++ src/NET8Native/deploy.sh | 2 +- src/NET8Native/run-loadtest.sh | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index 0156363..ac3efce 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -71,3 +71,14 @@ else source ./deploy.sh $DELETE_STACK source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi + +#export LT_NET8_NATIVE=1 +if [ "$LT_NET8_NATIVE" != yes ]; +then + echo SKIPPING net8 native :$LT_NET8_NATIVE +else + echo "RUNNING load test for net8 native" + cd ../../src/NET8Native/ + source ./deploy.sh $DELETE_STACK + source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE +fi diff --git a/src/NET8Native/deploy.sh b/src/NET8Native/deploy.sh index 9aae7f5..924d77c 100755 --- a/src/NET8Native/deploy.sh +++ b/src/NET8Native/deploy.sh @@ -1,7 +1,7 @@ #Arguments: #$1 - delete stack formation to ensure that all test have same conditon and favour similar ammount of cold start events -STACK_NAME=dotnet8 +STACK_NAME=dotnet8-native DELETE_STACK=yes COLOR='\033[0;33m' diff --git a/src/NET8Native/run-loadtest.sh b/src/NET8Native/run-loadtest.sh index 2391e84..ab8f5a8 100755 --- a/src/NET8Native/run-loadtest.sh +++ b/src/NET8Native/run-loadtest.sh @@ -3,7 +3,7 @@ #$2 - log interval to be used in the cloudwatch query in minutes #$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat -STACK_NAME=dotnet8 +STACK_NAME=dotnet8-native TEST_DURATIOMN_SEC=60 LOG_INTERVAL_MIN=20 LOG_DELETE=yes From 197715b8ac6f9577ca4fb79f577125dbc4786bf2 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sat, 11 Nov 2023 09:19:08 +0100 Subject: [PATCH 15/24] . --- src/NET8Native/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NET8Native/Makefile b/src/NET8Native/Makefile index 1a83e83..655de9c 100644 --- a/src/NET8Native/Makefile +++ b/src/NET8Native/Makefile @@ -11,13 +11,13 @@ build-DeleteProductFunctionX86: dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-GetProductFunctionArm64: - dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) + dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-GetProductsFunctionArm64: - dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) + dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-PutProductFunctionArm64: - dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) + dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-DeleteProductFunctionArm64: - dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) \ No newline at end of file + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) \ No newline at end of file From ee76535409491a47c891604ce649a15c045e53c5 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sat, 11 Nov 2023 09:28:06 +0100 Subject: [PATCH 16/24] . --- loadtest/codebuild/run-all-load-tests.sh | 23 +++++++++++++++-------- src/NET8NativeMinimalAPI/Makefile | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index ac3efce..931176b 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -32,7 +32,7 @@ echo -------------------------------------------- if [ "$LT_NET6_MINIMAL_API" != yes ]; then - echo SKIPPING net6 minimal api :$LT_NET6_MINIMAL_API + echo SKIPPING net6 minimal api - LT_NET6_MINIMAL_API=$LT_NET6_MINIMAL_API else echo "RUNNING load test for net6 minimal api" cd ../../src/NET6MinimalAPI/ @@ -42,7 +42,7 @@ fi if [ "$LT_NET6_MINIMAL_API_WEB_ADAPTER" != yes ]; then - echo SKIPPING net6 minimal api web adapter :$LT_NET6_MINIMAL_API_WEB_ADAPTER + echo SKIPPING net6 minimal api web adapter - LT_NET6_MINIMAL_API_WEB_ADAPTER = $LT_NET6_MINIMAL_API_WEB_ADAPTER else echo "RUNNING load test for net6 minimal api web adapter" cd ../../src/NET6MinimalAPIWebAdapter/ @@ -50,10 +50,9 @@ else source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi -#export LT_NET8_MINIMAL_API=1 if [ "$LT_NET8" != yes ]; then - echo SKIPPING net8 :$LT_NET8 + echo SKIPPING net8 - LT_NET8=$LT_NET8 else echo "RUNNING load test for net8" cd ../../src/NET8/ @@ -61,10 +60,9 @@ else source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi -#export LT_NET8_MINIMAL_API=1 if [ "$LT_NET8_MINIMAL_API" != yes ]; then - echo SKIPPING net8 minimal api :$LT_NET8_MINIMAL_API + echo SKIPPING net8 minimal api - LT_NET8_MINIMAL_API=$LT_NET8_MINIMAL_API else echo "RUNNING load test for net8 minimal api" cd ../../src/NET8MinimalAPI/ @@ -72,13 +70,22 @@ else source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi -#export LT_NET8_NATIVE=1 if [ "$LT_NET8_NATIVE" != yes ]; then - echo SKIPPING net8 native :$LT_NET8_NATIVE + echo SKIPPING net8 native - LT_NET8_NATIVE=$LT_NET8_NATIVE else echo "RUNNING load test for net8 native" cd ../../src/NET8Native/ source ./deploy.sh $DELETE_STACK source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi + +if [ "$LT_NET8_NATIVE_MINIMAL_API" != yes ]; +then + echo SKIPPING net8 native minimal api LT_NET8_NATIVE_MINIMAL_API=$LT_NET8_NATIVE_MINIMAL_API +else + echo "RUNNING load test for net8 native minimal api" + cd ../../src/NET8NativeMinimalApi/ + source ./deploy.sh $DELETE_STACK + source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE +fi \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/Makefile b/src/NET8NativeMinimalAPI/Makefile index 79df09e..5b5c4f6 100644 --- a/src/NET8NativeMinimalAPI/Makefile +++ b/src/NET8NativeMinimalAPI/Makefile @@ -1,4 +1,4 @@ build-MinimalApiX86: dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) build-MinimalApiArm64: - dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-arm64 -o $(ARTIFACTS_DIR) \ No newline at end of file + dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) \ No newline at end of file From d7e6d1ad914738d99d40e6020af66f362e2cbc94 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sat, 11 Nov 2023 09:43:12 +0100 Subject: [PATCH 17/24] . --- src/NET8Native/template.yaml | 4 ++-- src/NET8NativeMinimalAPI/template.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NET8Native/template.yaml b/src/NET8Native/template.yaml index 0e49fe0..b439ecc 100644 --- a/src/NET8Native/template.yaml +++ b/src/NET8Native/template.yaml @@ -4,10 +4,10 @@ Transform: AWS::Serverless-2016-10-31 Parameters: x86FunctionNamePrefix: Type: String - Default: Net8-X86 + Default: Net8-Native-X86 arm64FunctionNamePrefix: Type: String - Default: Net8-Arm64 + Default: Net8-Native-Arm64 Globals: Function: diff --git a/src/NET8NativeMinimalAPI/template.yaml b/src/NET8NativeMinimalAPI/template.yaml index abb40f5..3dbb403 100644 --- a/src/NET8NativeMinimalAPI/template.yaml +++ b/src/NET8NativeMinimalAPI/template.yaml @@ -4,10 +4,10 @@ Transform: AWS::Serverless-2016-10-31 Parameters: x86FunctionName: Type: String - Default: Net8-MinimalApi-X86 + Default: Net8-Native-MinimalApi-X86 arm64FunctionName: Type: String - Default: Net8-MinimalApi-Arm64 + Default: Net8-Native-MinimalApi-Arm64 Globals: Function: From bb4c77072b57cbcc7609fd1c5f5dcad24b0c0756 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 12 Nov 2023 21:06:23 +0100 Subject: [PATCH 18/24] fixing NET8 Native --- .../aws-lambda-tools-defaults.json | 18 --- .../GetProduct/aws-lambda-tools-defaults.json | 18 --- .../aws-lambda-tools-defaults.json | 18 --- .../PutProduct/aws-lambda-tools-defaults.json | 15 --- .../Report/load-test-report-arm64.json | 62 ---------- .../Report/load-test-report-arm64.txt | 18 --- .../Report/load-test-report-x86.json | 62 ---------- .../Report/load-test-report-x86.txt | 18 --- .../Report/load-test-report-arm64.json | 62 ---------- .../Report/load-test-report-arm64.txt | 18 --- .../Report/load-test-report-x86.json | 62 ---------- .../Report/load-test-report-x86.txt | 18 --- .../aws-lambda-tools-defaults.json | 18 --- .../GetProduct/aws-lambda-tools-defaults.json | 18 --- .../aws-lambda-tools-defaults.json | 18 --- .../PutProduct/aws-lambda-tools-defaults.json | 18 --- .../aws-lambda-tools-defaults.json | 18 --- .../GetProduct/aws-lambda-tools-defaults.json | 18 --- .../aws-lambda-tools-defaults.json | 18 --- .../PutProduct/aws-lambda-tools-defaults.json | 15 --- .../Report/load-test-report-arm64.json | 62 ---------- .../Report/load-test-report-arm64.txt | 18 --- .../Report/load-test-report-x86.json | 62 ---------- .../Report/load-test-report-x86.txt | 18 --- .../DeleteProduct/DeleteProduct.csproj | 14 ++- .../aws-lambda-tools-defaults.json | 18 --- src/NET8Native/GetProduct/GetProduct.csproj | 16 +-- .../GetProduct/aws-lambda-tools-defaults.json | 18 --- src/NET8Native/GetProducts/GetProducts.csproj | 15 ++- .../aws-lambda-tools-defaults.json | 18 --- src/NET8Native/Makefile | 20 +--- src/NET8Native/PutProduct/PutProduct.csproj | 14 ++- .../PutProduct/aws-lambda-tools-defaults.json | 15 --- .../Shared/JsonSerializerContext.cs | 3 +- src/NET8Native/Shared/Shared.csproj | 17 ++- src/NET8Native/deploy.sh | 2 +- src/NET8Native/run-loadtest.sh | 3 +- src/NET8Native/template.yaml | 112 +----------------- 38 files changed, 53 insertions(+), 922 deletions(-) delete mode 100644 src/NET6CustomRuntime/DeleteProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET6CustomRuntime/GetProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET6CustomRuntime/GetProducts/aws-lambda-tools-defaults.json delete mode 100644 src/NET6CustomRuntime/PutProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET6MinimalAPI/Report/load-test-report-arm64.json delete mode 100644 src/NET6MinimalAPI/Report/load-test-report-arm64.txt delete mode 100644 src/NET6MinimalAPI/Report/load-test-report-x86.json delete mode 100644 src/NET6MinimalAPI/Report/load-test-report-x86.txt delete mode 100644 src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.json delete mode 100644 src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.txt delete mode 100644 src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.json delete mode 100644 src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.txt delete mode 100755 src/NET6Native/DeleteProduct/aws-lambda-tools-defaults.json delete mode 100755 src/NET6Native/GetProduct/aws-lambda-tools-defaults.json delete mode 100755 src/NET6Native/GetProducts/aws-lambda-tools-defaults.json delete mode 100755 src/NET6Native/PutProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET8/DeleteProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET8/GetProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET8/GetProducts/aws-lambda-tools-defaults.json delete mode 100644 src/NET8/PutProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.json delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-arm64.txt delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.json delete mode 100644 src/NET8MinimalAPI/Report/load-test-report-x86.txt delete mode 100644 src/NET8Native/DeleteProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET8Native/GetProduct/aws-lambda-tools-defaults.json delete mode 100644 src/NET8Native/GetProducts/aws-lambda-tools-defaults.json delete mode 100644 src/NET8Native/PutProduct/aws-lambda-tools-defaults.json diff --git a/src/NET6CustomRuntime/DeleteProduct/aws-lambda-tools-defaults.json b/src/NET6CustomRuntime/DeleteProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET6CustomRuntime/DeleteProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET6CustomRuntime/GetProduct/aws-lambda-tools-defaults.json b/src/NET6CustomRuntime/GetProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET6CustomRuntime/GetProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET6CustomRuntime/GetProducts/aws-lambda-tools-defaults.json b/src/NET6CustomRuntime/GetProducts/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET6CustomRuntime/GetProducts/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET6CustomRuntime/PutProduct/aws-lambda-tools-defaults.json b/src/NET6CustomRuntime/PutProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 7ed1688..0000000 --- a/src/NET6CustomRuntime/PutProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "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": "", - "region": "", - "configuration": "Release", - "function-runtime": "provided.al2", - "function-memory-size": 256, - "function-timeout": 30, - "function-handler": "bootstrap" -} \ No newline at end of file diff --git a/src/NET6MinimalAPI/Report/load-test-report-arm64.json b/src/NET6MinimalAPI/Report/load-test-report-arm64.json deleted file mode 100644 index 005bf4d..0000000 --- a/src/NET6MinimalAPI/Report/load-test-report-arm64.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "135963" - }, - { - "field": "p50", - "value": "6.2055" - }, - { - "field": "p90", - "value": "9.6783" - }, - { - "field": "p99", - "value": "20.0868" - }, - { - "field": "max", - "value": "528.13" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "246" - }, - { - "field": "p50", - "value": "2105.2185" - }, - { - "field": "p90", - "value": "2164.9673" - }, - { - "field": "p99", - "value": "2215.3132" - }, - { - "field": "max", - "value": "2228.18" - } - ] - ], - "statistics": { - "recordsMatched": 136209.0, - "recordsScanned": 1226110.0, - "bytesScanned": 900312482.0 - }, - "status": "Complete" -} diff --git a/src/NET6MinimalAPI/Report/load-test-report-arm64.txt b/src/NET6MinimalAPI/Report/load-test-report-arm64.txt deleted file mode 100644 index 4ae278b..0000000 --- a/src/NET6MinimalAPI/Report/load-test-report-arm64.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 18:51:08 UTC 2023 -arm64 RESULTS lambda: Net6-MinimalApi-Arm64 -Test duration sec: 600 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 135963 -RESULTS p50 6.2055 -RESULTS p90 9.6783 -RESULTS p99 20.0868 -RESULTS max 528.13 -RESULTS coldstart 1 -RESULTS count 246 -RESULTS p50 2105.2185 -RESULTS p90 2164.9673 -RESULTS p99 2215.3132 -RESULTS max 2228.18 -STATISTICS 900312482.0 136209.0 1226110.0 diff --git a/src/NET6MinimalAPI/Report/load-test-report-x86.json b/src/NET6MinimalAPI/Report/load-test-report-x86.json deleted file mode 100644 index d2d2920..0000000 --- a/src/NET6MinimalAPI/Report/load-test-report-x86.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "135861" - }, - { - "field": "p50", - "value": "5.9169" - }, - { - "field": "p90", - "value": "9.9905" - }, - { - "field": "p99", - "value": "21.746" - }, - { - "field": "max", - "value": "108.6" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "197" - }, - { - "field": "p50", - "value": "1742.8361" - }, - { - "field": "p90", - "value": "1966.8893" - }, - { - "field": "p99", - "value": "2411.7468" - }, - { - "field": "max", - "value": "2503.31" - } - ] - ], - "statistics": { - "recordsMatched": 136058.0, - "recordsScanned": 1224739.0, - "bytesScanned": 894477163.0 - }, - "status": "Complete" -} diff --git a/src/NET6MinimalAPI/Report/load-test-report-x86.txt b/src/NET6MinimalAPI/Report/load-test-report-x86.txt deleted file mode 100644 index 21b5798..0000000 --- a/src/NET6MinimalAPI/Report/load-test-report-x86.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 18:40:27 UTC 2023 -x86 RESULTS lambda: Net6-MinimalApi-X86 -Test duration sec: 600 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 135861 -RESULTS p50 5.9169 -RESULTS p90 9.9905 -RESULTS p99 21.746 -RESULTS max 108.6 -RESULTS coldstart 1 -RESULTS count 197 -RESULTS p50 1742.8361 -RESULTS p90 1966.8893 -RESULTS p99 2411.7468 -RESULTS max 2503.31 -STATISTICS 894477163.0 136058.0 1224739.0 diff --git a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.json b/src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.json deleted file mode 100644 index be65931..0000000 --- a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "138527" - }, - { - "field": "p50", - "value": "6.1078" - }, - { - "field": "p90", - "value": "9.3759" - }, - { - "field": "p99", - "value": "17.9744" - }, - { - "field": "max", - "value": "838.78" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "139" - }, - { - "field": "p50", - "value": "1277.1986" - }, - { - "field": "p90", - "value": "1326.6409" - }, - { - "field": "p99", - "value": "1358.8491" - }, - { - "field": "max", - "value": "1367.49" - } - ] - ], - "statistics": { - "recordsMatched": 138666.0, - "recordsScanned": 694392.0, - "bytesScanned": 268615241.0 - }, - "status": "Complete" -} diff --git a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.txt b/src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.txt deleted file mode 100644 index 6df5dbc..0000000 --- a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-arm64.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 19:14:52 UTC 2023 -arm64 RESULTS lambda: Net6-MinimalApi-WebadApter-Arm64 -Test duration sec: 600 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 138527 -RESULTS p50 6.1078 -RESULTS p90 9.3759 -RESULTS p99 17.9744 -RESULTS max 838.78 -RESULTS coldstart 1 -RESULTS count 139 -RESULTS p50 1277.1986 -RESULTS p90 1326.6409 -RESULTS p99 1358.8491 -RESULTS max 1367.49 -STATISTICS 268615241.0 138666.0 694392.0 diff --git a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.json b/src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.json deleted file mode 100644 index 60522ca..0000000 --- a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "140872" - }, - { - "field": "p50", - "value": "6.2055" - }, - { - "field": "p90", - "value": "10.3128" - }, - { - "field": "p99", - "value": "21.746" - }, - { - "field": "max", - "value": "154.62" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "112" - }, - { - "field": "p50", - "value": "1013.88" - }, - { - "field": "p90", - "value": "1102.6789" - }, - { - "field": "p99", - "value": "1330.6248" - }, - { - "field": "max", - "value": "1392.85" - } - ] - ], - "statistics": { - "recordsMatched": 140984.0, - "recordsScanned": 705687.0, - "bytesScanned": 272986184.0 - }, - "status": "Complete" -} diff --git a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.txt b/src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.txt deleted file mode 100644 index 1f5f629..0000000 --- a/src/NET6MinimalAPIWebAdapter/Report/load-test-report-x86.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 19:04:10 UTC 2023 -x86 RESULTS lambda: Net6-MinimalApi-WebadApter-X86 -Test duration sec: 600 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 140872 -RESULTS p50 6.2055 -RESULTS p90 10.3128 -RESULTS p99 21.746 -RESULTS max 154.62 -RESULTS coldstart 1 -RESULTS count 112 -RESULTS p50 1013.88 -RESULTS p90 1102.6789 -RESULTS p99 1330.6248 -RESULTS max 1392.85 -STATISTICS 272986184.0 140984.0 705687.0 diff --git a/src/NET6Native/DeleteProduct/aws-lambda-tools-defaults.json b/src/NET6Native/DeleteProduct/aws-lambda-tools-defaults.json deleted file mode 100755 index 1d112e0..0000000 --- a/src/NET6Native/DeleteProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET6Native/GetProduct/aws-lambda-tools-defaults.json b/src/NET6Native/GetProduct/aws-lambda-tools-defaults.json deleted file mode 100755 index 1d112e0..0000000 --- a/src/NET6Native/GetProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET6Native/GetProducts/aws-lambda-tools-defaults.json b/src/NET6Native/GetProducts/aws-lambda-tools-defaults.json deleted file mode 100755 index 1d112e0..0000000 --- a/src/NET6Native/GetProducts/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET6Native/PutProduct/aws-lambda-tools-defaults.json b/src/NET6Native/PutProduct/aws-lambda-tools-defaults.json deleted file mode 100755 index 1d112e0..0000000 --- a/src/NET6Native/PutProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET8/DeleteProduct/aws-lambda-tools-defaults.json b/src/NET8/DeleteProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET8/DeleteProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET8/GetProduct/aws-lambda-tools-defaults.json b/src/NET8/GetProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET8/GetProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET8/GetProducts/aws-lambda-tools-defaults.json b/src/NET8/GetProducts/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET8/GetProducts/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET8/PutProduct/aws-lambda-tools-defaults.json b/src/NET8/PutProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 7ed1688..0000000 --- a/src/NET8/PutProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "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": "", - "region": "", - "configuration": "Release", - "function-runtime": "provided.al2", - "function-memory-size": 256, - "function-timeout": 30, - "function-handler": "bootstrap" -} \ No newline at end of file diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.json b/src/NET8MinimalAPI/Report/load-test-report-arm64.json deleted file mode 100644 index 8a37bf2..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-arm64.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "136816" - }, - { - "field": "p50", - "value": "6.0116" - }, - { - "field": "p90", - "value": "9.3759" - }, - { - "field": "p99", - "value": "24.6905" - }, - { - "field": "max", - "value": "331.6" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "242" - }, - { - "field": "p50", - "value": "1972.7958" - }, - { - "field": "p90", - "value": "2049.1658" - }, - { - "field": "p99", - "value": "2107.3237" - }, - { - "field": "max", - "value": "2124.55" - } - ] - ], - "statistics": { - "recordsMatched": 137058.0, - "recordsScanned": 1233898.0, - "bytesScanned": 945917431.0 - }, - "status": "Complete" -} diff --git a/src/NET8MinimalAPI/Report/load-test-report-arm64.txt b/src/NET8MinimalAPI/Report/load-test-report-arm64.txt deleted file mode 100644 index e98f8f2..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-arm64.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 19:38:43 UTC 2023 -arm64 RESULTS lambda: Net8-MinimalApi-Arm64 -Test duration sec: 600 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 136816 -RESULTS p50 6.0116 -RESULTS p90 9.3759 -RESULTS p99 24.6905 -RESULTS max 331.6 -RESULTS coldstart 1 -RESULTS count 242 -RESULTS p50 1972.7958 -RESULTS p90 2049.1658 -RESULTS p99 2107.3237 -RESULTS max 2124.55 -STATISTICS 945917431.0 137058.0 1233898.0 diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.json b/src/NET8MinimalAPI/Report/load-test-report-x86.json deleted file mode 100644 index 6b47edc..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-x86.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "results": [ - [ - { - "field": "coldstart", - "value": "0" - }, - { - "field": "count", - "value": "136006" - }, - { - "field": "p50", - "value": "6.3048" - }, - { - "field": "p90", - "value": "10.9888" - }, - { - "field": "p99", - "value": "26.7299" - }, - { - "field": "max", - "value": "124.67" - } - ], - [ - { - "field": "coldstart", - "value": "1" - }, - { - "field": "count", - "value": "195" - }, - { - "field": "p50", - "value": "1672.8591" - }, - { - "field": "p90", - "value": "1737.618" - }, - { - "field": "p99", - "value": "1833.9796" - }, - { - "field": "max", - "value": "1889.15" - } - ] - ], - "statistics": { - "recordsMatched": 136201.0, - "recordsScanned": 1226041.0, - "bytesScanned": 935106143.0 - }, - "status": "Complete" -} diff --git a/src/NET8MinimalAPI/Report/load-test-report-x86.txt b/src/NET8MinimalAPI/Report/load-test-report-x86.txt deleted file mode 100644 index f57a52f..0000000 --- a/src/NET8MinimalAPI/Report/load-test-report-x86.txt +++ /dev/null @@ -1,18 +0,0 @@ -Sun Nov 5 19:28:01 UTC 2023 -x86 RESULTS lambda: Net8-MinimalApi-X86 -Test duration sec: 600 -Log interval min: 20 -Complete -RESULTS coldstart 0 -RESULTS count 136006 -RESULTS p50 6.3048 -RESULTS p90 10.9888 -RESULTS p99 26.7299 -RESULTS max 124.67 -RESULTS coldstart 1 -RESULTS count 195 -RESULTS p50 1672.8591 -RESULTS p90 1737.618 -RESULTS p99 1833.9796 -RESULTS max 1889.15 -STATISTICS 935106143.0 136201.0 1226041.0 diff --git a/src/NET8Native/DeleteProduct/DeleteProduct.csproj b/src/NET8Native/DeleteProduct/DeleteProduct.csproj index f64c696..9f5a81b 100644 --- a/src/NET8Native/DeleteProduct/DeleteProduct.csproj +++ b/src/NET8Native/DeleteProduct/DeleteProduct.csproj @@ -3,16 +3,20 @@ exe net8.0 - true - Lambda bootstrap + true - false - true - true + true + Lambda + true + skylake Speed + + false + true + true diff --git a/src/NET8Native/DeleteProduct/aws-lambda-tools-defaults.json b/src/NET8Native/DeleteProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET8Native/DeleteProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET8Native/GetProduct/GetProduct.csproj b/src/NET8Native/GetProduct/GetProduct.csproj index e070d2e..364daed 100644 --- a/src/NET8Native/GetProduct/GetProduct.csproj +++ b/src/NET8Native/GetProduct/GetProduct.csproj @@ -1,21 +1,21 @@  - exe net8.0 - true - Lambda bootstrap true - false - true - true - + true + Lambda + true + skylake Speed + + false + true + true diff --git a/src/NET8Native/GetProduct/aws-lambda-tools-defaults.json b/src/NET8Native/GetProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET8Native/GetProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET8Native/GetProducts/GetProducts.csproj b/src/NET8Native/GetProducts/GetProducts.csproj index 7f65871..364daed 100644 --- a/src/NET8Native/GetProducts/GetProducts.csproj +++ b/src/NET8Native/GetProducts/GetProducts.csproj @@ -1,18 +1,21 @@  - exe net8.0 - true - Lambda bootstrap + true - false - true - true + true + Lambda + true + skylake Speed + + false + true + true diff --git a/src/NET8Native/GetProducts/aws-lambda-tools-defaults.json b/src/NET8Native/GetProducts/aws-lambda-tools-defaults.json deleted file mode 100644 index 1d112e0..0000000 --- a/src/NET8Native/GetProducts/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "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":"", - "region" : "", - "configuration": "Release", - "function-runtime":"provided.al2", - "function-memory-size" : 256, - "function-timeout" : 30, - "function-handler" : "CancelBooking" -} diff --git a/src/NET8Native/Makefile b/src/NET8Native/Makefile index 655de9c..9993dc3 100644 --- a/src/NET8Native/Makefile +++ b/src/NET8Native/Makefile @@ -1,23 +1,11 @@ build-GetProductFunctionX86: - dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) + dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) build-GetProductsFunctionX86: - dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) + dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) build-PutProductFunctionX86: - dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) + dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) build-DeleteProductFunctionX86: - dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) - -build-GetProductFunctionArm64: - dotnet publish GetProduct/GetProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) - -build-GetProductsFunctionArm64: - dotnet publish GetProducts/GetProducts.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) - -build-PutProductFunctionArm64: - dotnet publish PutProduct/PutProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) - -build-DeleteProductFunctionArm64: - dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) \ No newline at end of file + dotnet publish DeleteProduct/DeleteProduct.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8Native/PutProduct/PutProduct.csproj b/src/NET8Native/PutProduct/PutProduct.csproj index f64c696..9f5a81b 100644 --- a/src/NET8Native/PutProduct/PutProduct.csproj +++ b/src/NET8Native/PutProduct/PutProduct.csproj @@ -3,16 +3,20 @@ exe net8.0 - true - Lambda bootstrap + true - false - true - true + true + Lambda + true + skylake Speed + + false + true + true diff --git a/src/NET8Native/PutProduct/aws-lambda-tools-defaults.json b/src/NET8Native/PutProduct/aws-lambda-tools-defaults.json deleted file mode 100644 index 7ed1688..0000000 --- a/src/NET8Native/PutProduct/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "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": "", - "region": "", - "configuration": "Release", - "function-runtime": "provided.al2", - "function-memory-size": 256, - "function-timeout": 30, - "function-handler": "bootstrap" -} \ No newline at end of file diff --git a/src/NET8Native/Shared/JsonSerializerContext.cs b/src/NET8Native/Shared/JsonSerializerContext.cs index 99f168f..f71528f 100644 --- a/src/NET8Native/Shared/JsonSerializerContext.cs +++ b/src/NET8Native/Shared/JsonSerializerContext.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System.Collections.Generic; +using System.Text.Json.Serialization; using Amazon.Lambda.APIGatewayEvents; using Shared.Models; diff --git a/src/NET8Native/Shared/Shared.csproj b/src/NET8Native/Shared/Shared.csproj index cf01798..84e7fb3 100644 --- a/src/NET8Native/Shared/Shared.csproj +++ b/src/NET8Native/Shared/Shared.csproj @@ -2,20 +2,19 @@ net8.0 - enable - enable - true - true - false - true - true - + true + Lambda + true + skylake Speed + + false + true + true diff --git a/src/NET8Native/deploy.sh b/src/NET8Native/deploy.sh index 924d77c..dda9b4d 100755 --- a/src/NET8Native/deploy.sh +++ b/src/NET8Native/deploy.sh @@ -39,5 +39,5 @@ then echo "${NO_COLOR}" fi -sam build +sam build --use-container --build-image plantpowerjames/dotnet-8-lambda-build:rc2 sam deploy --stack-name $STACK_NAME --resolve-s3 --s3-prefix $STACK_NAME --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file diff --git a/src/NET8Native/run-loadtest.sh b/src/NET8Native/run-loadtest.sh index ab8f5a8..dd87955 100755 --- a/src/NET8Native/run-loadtest.sh +++ b/src/NET8Native/run-loadtest.sh @@ -149,5 +149,4 @@ function RunLoadTest() aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json } -RunLoadTest x86 ApiUrlX86 LambdaX86NameGetProducts LambdaX86NameGetProduct LambdaX86NameDeleteProduct LambdaX86NamePutProduct -RunLoadTest arm64 ApiUrlArm64 LambdaArm64NameGetProducts LambdaArm64NameGetProduct LambdaArm64NameDeleteProduct LambdaArm64NamePutProduct \ No newline at end of file +RunLoadTest x86 ApiUrlX86 LambdaX86NameGetProducts LambdaX86NameGetProduct LambdaX86NameDeleteProduct LambdaX86NamePutProduct \ No newline at end of file diff --git a/src/NET8Native/template.yaml b/src/NET8Native/template.yaml index b439ecc..88b4d70 100644 --- a/src/NET8Native/template.yaml +++ b/src/NET8Native/template.yaml @@ -5,9 +5,6 @@ Parameters: x86FunctionNamePrefix: Type: String Default: Net8-Native-X86 - arm64FunctionNamePrefix: - Type: String - Default: Net8-Native-Arm64 Globals: Function: @@ -108,94 +105,6 @@ Resources: Resource: !GetAtt Table.Arn Metadata: BuildMethod: makefile - #ARM64 - GetProductsFunctionArm64: - Type: AWS::Serverless::Function - Properties: - FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProducts]] - Architectures: [arm64] - CodeUri: ./ - Handler: bootstrap - Events: - Api: - Type: HttpApi - Properties: - Path: /arm64 - Method: GET - Policies: - - DynamoDBReadPolicy: - TableName: - !Ref Table - Metadata: - BuildMethod: makefile - - GetProductFunctionArm64: - Type: AWS::Serverless::Function - Properties: - FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProduct]] - Architectures: [arm64] - CodeUri: ./ - Handler: GetProduct - Events: - Api: - Type: HttpApi - Properties: - Path: /arm64/{id} - Method: GET - Policies: - - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: dynamodb:GetItem - Resource: !GetAtt Table.Arn - Metadata: - BuildMethod: makefile - - DeleteProductFunctionArm64: - Type: AWS::Serverless::Function - Properties: - FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,DeleteProduct]] - Architectures: [arm64] - CodeUri: ./ - Handler: DeleteProduct - Events: - Api: - Type: HttpApi - Properties: - Path: /arm64/{id} - Method: DELETE - Policies: - - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - dynamodb:DeleteItem - - dynamodb:GetItem - Resource: !GetAtt Table.Arn - Metadata: - BuildMethod: makefile - - PutProductFunctionArm64: - Type: AWS::Serverless::Function - Properties: - FunctionName: !Join [ -,[!Ref arm64FunctionNamePrefix,PutProduct]] - Architectures: [arm64] - CodeUri: ./ - Handler: PutProduct - Events: - Api: - Type: HttpApi - Properties: - Path: /arm64/{id} - Method: PUT - Policies: - - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: dynamodb:PutItem - Resource: !GetAtt Table.Arn - Metadata: - BuildMethod: makefile Table: Type: AWS::DynamoDB::Table @@ -215,10 +124,7 @@ Outputs: ApiUrlX86: Description: "X86 API endpoint URL" Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86" - ApiUrlArm64: - Description: "Arm64 GateAPI endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64" - + #x86 LambdaX86NameGetProducts: Description: "Lambda X86 GetProducts" @@ -231,18 +137,4 @@ Outputs: Value: !Join [ -,[!Ref x86FunctionNamePrefix,DeleteProduct]] LambdaX86NamePutProduct: Description: "Lambda X86 PutProduct" - Value: !Join [ -,[!Ref x86FunctionNamePrefix,PutProduct]] - - #arm64 - LambdaArm64NameGetProducts: - Description: "Lambda X86 GetProducts" - Value: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProducts]] - LambdaArm64NameGetProduct: - Description: "Lambda X86 GetProduct" - Value: !Join [ -,[!Ref arm64FunctionNamePrefix,GetProduct]] - LambdaArm64NameDeleteProduct: - Description: "Lambda X86 DeleteProduct" - Value: !Join [ -,[!Ref arm64FunctionNamePrefix,DeleteProduct]] - LambdaArm64NamePutProduct: - Description: "Lambda X86 PutProduct" - Value: !Join [ -,[!Ref arm64FunctionNamePrefix,PutProduct]] \ No newline at end of file + Value: !Join [ -,[!Ref x86FunctionNamePrefix,PutProduct]] \ No newline at end of file From 7784f4efa12f95c6a43891ddda4a7581a157a41c Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 12 Nov 2023 21:28:06 +0100 Subject: [PATCH 19/24] fixing net8 native minimal api --- .../ApiBootstrap/ApiBootstrap.csproj | 11 +- .../ApiBootstrap/Function.cs | 163 ++++++++---------- src/NET8NativeMinimalAPI/Makefile | 4 +- .../Shared/DataAccess/DynamoDbProducts.cs | 5 +- .../Shared/DataAccess/ProductMapper.cs | 4 +- .../Shared/DataAccess/ProductsDAO.cs | 3 +- .../Shared/Models/Product.cs | 11 +- .../Shared/Models/ProductWrapper.cs | 4 +- src/NET8NativeMinimalAPI/Shared/Shared.csproj | 4 + src/NET8NativeMinimalAPI/Shared/Startup.cs | 7 +- src/NET8NativeMinimalAPI/deploy.sh | 4 +- src/NET8NativeMinimalAPI/run-loadtest.sh | 3 +- src/NET8NativeMinimalAPI/template.yaml | 38 +--- 13 files changed, 105 insertions(+), 156 deletions(-) diff --git a/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj b/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj index facf661..e2c8e51 100644 --- a/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj +++ b/src/NET8NativeMinimalAPI/ApiBootstrap/ApiBootstrap.csproj @@ -3,14 +3,17 @@ Exe net8.0 + bootstrap + + true + + true true enable enable GetProducts - true - bootstrap + full - true @@ -29,6 +32,8 @@ + + diff --git a/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs b/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs index 10a82a7..0462ff5 100644 --- a/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs +++ b/src/NET8NativeMinimalAPI/ApiBootstrap/Function.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; using System.Net; using System.Text.Json; -using Amazon.CloudWatchLogs; -using Amazon.CloudWatchLogs.Model; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -13,122 +9,115 @@ using Shared.Models; var app = Startup.Build(args); -var basePath=Environment.GetEnvironmentVariable("DEMO_BASE_PATH"); -if(String.IsNullOrEmpty(basePath)) - app.Logger.LogInformation($"No BASE PATH specified"); -else -{ - app.Logger.LogInformation($"Using BASE PATH:{basePath}"); - app.UsePathBase(basePath); - app.UseRouting(); -} -var dataAccess = app.Services.GetRequiredService(); +Handlers.DataAccess = app.Services.GetRequiredService(); +Handlers.Logger = app.Logger; -var cloudWatchClient = new AmazonCloudWatchLogsClient(); +app.MapGet("/", Handlers.GetAllProducts); -app.MapGet("/", async (HttpContext context) => -{ - app.Logger.LogInformation("Received request to list all products"); +app.MapDelete("/{id}", Handlers.DeleteProduct); - var products = await dataAccess.GetAllProducts(); +app.MapPut("/{id}", Handlers.PutProduct); - app.Logger.LogInformation($"Found {products.Products.Count} products(s)"); +app.MapGet("/{id}", Handlers.GetProduct); - context.Response.StatusCode = (int) HttpStatusCode.OK; - await context.Response.WriteAsJsonAsync(products); -}); +app.Run(); -app.MapDelete("/{id}", async (HttpContext context) => +static class Handlers { - try + internal static ProductsDAO DataAccess; + internal static ILogger Logger; + + public static async Task GetAllProducts(HttpContext context) { - var id = context.Request.RouteValues["id"].ToString(); + Logger.LogInformation("Received request to list all products"); - app.Logger.LogInformation($"Received request to delete {id} from the database"); + var products = await DataAccess.GetAllProducts(); - var product = await dataAccess.GetProduct(id); + Logger.LogInformation($"Found {products.Products.Count} products(s)"); - if (product == null) + await context.WriteResponse(HttpStatusCode.OK, products); + } + + public static async Task DeleteProduct(HttpContext context) + { + try { - app.Logger.LogWarning($"Id {id} not found."); + var id = context.Request.RouteValues["id"].ToString(); + + Logger.LogInformation($"Received request to delete {id}"); - context.Response.StatusCode = (int) HttpStatusCode.NotFound; - Results.NotFound(); - return; - } + var product = await DataAccess.GetProduct(id); - app.Logger.LogInformation($"Deleting {product.Name}"); + if (product == null) + { + Logger.LogWarning($"Id {id} not found."); - await dataAccess.DeleteProduct(product.Id); + await context.WriteResponse(HttpStatusCode.NotFound); + + return; + } - app.Logger.LogInformation("Delete complete"); + Logger.LogInformation($"Deleting {product.Name}"); - context.Response.StatusCode = (int) HttpStatusCode.OK; - await context.Response.WriteAsJsonAsync($"Product with id {id} deleted"); - } - catch (Exception e) - { - app.Logger.LogError(e, "Failure deleting product"); + await DataAccess.DeleteProduct(product.Id); + + Logger.LogInformation("Delete complete"); + + await context.WriteResponse(HttpStatusCode.OK, $"Product with id {id} deleted"); + } + catch (Exception e) + { + Logger.LogError(e, "Failure deleting product"); - context.Response.StatusCode = (int) HttpStatusCode.NotFound; + await context.WriteResponse(HttpStatusCode.BadRequest); + } } -}); -app.MapPut("/{id}", async (HttpContext context) => -{ - try + public static async Task GetProduct(HttpContext context) { var id = context.Request.RouteValues["id"].ToString(); + + Logger.LogInformation($"Received request to get {id}"); - app.Logger.LogInformation($"Received request to put {id}"); + var product = await DataAccess.GetProduct(id); - var product = await JsonSerializer.DeserializeAsync(context.Request.Body); - - if (product == null || id != product.Id) + if (product == null) { - app.Logger.LogWarning("Product ID in the body does not match path parameter"); - - context.Response.StatusCode = (int) HttpStatusCode.BadRequest; - await context.Response.WriteAsJsonAsync("Product ID in the body does not match path parameter"); - return; + Logger.LogWarning($"{id} not found"); + await context.WriteResponse(HttpStatusCode.NotFound, $"{id} not found"); } - app.Logger.LogInformation("Putting product"); - - await dataAccess.PutProduct(product); - - app.Logger.LogTrace("Done"); - - context.Response.StatusCode = (int) HttpStatusCode.OK; - await context.Response.WriteAsJsonAsync($"Created product with id {id}"); + await context.WriteResponse(HttpStatusCode.OK, product); } - catch (Exception e) + + public static async Task PutProduct(HttpContext context) { - app.Logger.LogError(e, "Failure deleting product"); + var id = context.Request.RouteValues["id"].ToString(); + var product = await JsonSerializer.DeserializeAsync(context.Request.Body, ApiSerializerContext.Default.Product); + + if (product == null || id != product.Id) + { + await context.WriteResponse(HttpStatusCode.BadRequest, "Product ID in the body does not match path parameter"); + } - context.Response.StatusCode = (int) HttpStatusCode.BadRequest; + await DataAccess.PutProduct(product); + + await context.WriteResponse(HttpStatusCode.OK, $"Created product with id {id}"); } -}); +} -app.MapGet("/{id}", async (HttpContext context) => +static class ResponseWriter { - var id = context.Request.RouteValues["id"].ToString(); - - app.Logger.LogInformation($"Received request to get {id}"); - - var product = await dataAccess.GetProduct(id); - - if (product == null) + public static async Task WriteResponse(this HttpContext context, HttpStatusCode statusCode) { - app.Logger.LogWarning($"{id} not found"); - context.Response.StatusCode = (int) HttpStatusCode.NotFound; - Results.NotFound(); - return; + await context.WriteResponse(statusCode, ""); } - - context.Response.StatusCode = (int) HttpStatusCode.OK; - await context.Response.WriteAsJsonAsync(product); -}); - -app.Run(); \ No newline at end of file + + public static async Task WriteResponse(this HttpContext context, HttpStatusCode statusCode, TResponseType body) where TResponseType : class + { + context.Response.StatusCode = (int)statusCode; + context.Response.ContentType = "application/json"; + await context.Response.WriteAsync(JsonSerializer.Serialize(body, typeof(TResponseType), ApiSerializerContext.Default)); + } +} \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/Makefile b/src/NET8NativeMinimalAPI/Makefile index 5b5c4f6..0e8e9c9 100644 --- a/src/NET8NativeMinimalAPI/Makefile +++ b/src/NET8NativeMinimalAPI/Makefile @@ -1,4 +1,2 @@ build-MinimalApiX86: - dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) -build-MinimalApiArm64: - dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 -o $(ARTIFACTS_DIR) \ No newline at end of file + dotnet publish ApiBootstrap/ApiBootstrap.csproj -c Release -r linux-x64 --self-contained -o $(ARTIFACTS_DIR) \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs b/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs index 5f85635..e41da85 100644 --- a/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs +++ b/src/NET8NativeMinimalAPI/Shared/DataAccess/DynamoDbProducts.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Amazon.DynamoDBv2; +using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.Model; using Shared.Models; diff --git a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs index 8e073ed..7abc616 100644 --- a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs +++ b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductMapper.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Globalization; +using System.Globalization; using Amazon.DynamoDBv2.Model; using Shared.Models; diff --git a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs index d09decd..c1e13a6 100644 --- a/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs +++ b/src/NET8NativeMinimalAPI/Shared/DataAccess/ProductsDAO.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using Shared.Models; +using Shared.Models; namespace Shared.DataAccess { diff --git a/src/NET8NativeMinimalAPI/Shared/Models/Product.cs b/src/NET8NativeMinimalAPI/Shared/Models/Product.cs index 93f9896..88a62ca 100644 --- a/src/NET8NativeMinimalAPI/Shared/Models/Product.cs +++ b/src/NET8NativeMinimalAPI/Shared/Models/Product.cs @@ -1,6 +1,4 @@ -using System; - -namespace Shared.Models +namespace Shared.Models { public class Product { @@ -19,12 +17,7 @@ public Product(string id, string name, decimal price) public string Name { get; set; } - public decimal Price { get; private set; } - - public void SetPrice(decimal newPrice) - { - this.Price = Math.Round(newPrice, 2); - } + public decimal Price { get; set; } public override string ToString() { diff --git a/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs b/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs index c89af93..47cc485 100644 --- a/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs +++ b/src/NET8NativeMinimalAPI/Shared/Models/ProductWrapper.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Shared.Models +namespace Shared.Models { public class ProductWrapper { diff --git a/src/NET8NativeMinimalAPI/Shared/Shared.csproj b/src/NET8NativeMinimalAPI/Shared/Shared.csproj index 7d6a8a2..466b824 100644 --- a/src/NET8NativeMinimalAPI/Shared/Shared.csproj +++ b/src/NET8NativeMinimalAPI/Shared/Shared.csproj @@ -2,6 +2,10 @@ net8.0 + + true + + true enable enable diff --git a/src/NET8NativeMinimalAPI/Shared/Startup.cs b/src/NET8NativeMinimalAPI/Shared/Startup.cs index ef2b0db..3926dc3 100644 --- a/src/NET8NativeMinimalAPI/Shared/Startup.cs +++ b/src/NET8NativeMinimalAPI/Shared/Startup.cs @@ -1,7 +1,6 @@ using System.Text.Json; using Amazon.Lambda.Serialization.SystemTextJson; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Shared.DataAccess; @@ -34,7 +33,11 @@ public static WebApplication Build(string[] args) options.TimestampFormat = "hh:mm:ss "; }); - return builder.Build(); + var app = builder.Build(); + + // Add generic app configuration here. + + return app; } } } \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/deploy.sh b/src/NET8NativeMinimalAPI/deploy.sh index 7da02c0..71a251b 100755 --- a/src/NET8NativeMinimalAPI/deploy.sh +++ b/src/NET8NativeMinimalAPI/deploy.sh @@ -39,5 +39,5 @@ then echo "${NO_COLOR}" fi -sam build -sam deploy --stack-name dotnet8-minimal-api --resolve-s3 --s3-prefix dotnet8-minimal-api --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file +sam build --use-container --build-image plantpowerjames/dotnet-8-lambda-build:rc2 +sam deploy --stack-name $STACK_NAME --resolve-s3 --s3-prefix $STACK_NAME --no-confirm-changeset --no-fail-on-empty-changeset --capabilities CAPABILITY_IAM \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/run-loadtest.sh b/src/NET8NativeMinimalAPI/run-loadtest.sh index 8e7408e..351288a 100755 --- a/src/NET8NativeMinimalAPI/run-loadtest.sh +++ b/src/NET8NativeMinimalAPI/run-loadtest.sh @@ -119,5 +119,4 @@ function RunLoadTest() aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json } -RunLoadTest x86 ApiUrlX86 LambdaX86Name -RunLoadTest arm64 ApiUrlArm64 LambdaArm64Name \ No newline at end of file +RunLoadTest x86 ApiUrlX86 LambdaX86Name \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/template.yaml b/src/NET8NativeMinimalAPI/template.yaml index 3dbb403..181d59b 100644 --- a/src/NET8NativeMinimalAPI/template.yaml +++ b/src/NET8NativeMinimalAPI/template.yaml @@ -5,9 +5,6 @@ Parameters: x86FunctionName: Type: String Default: Net8-Native-MinimalApi-X86 - arm64FunctionName: - Type: String - Default: Net8-Native-MinimalApi-Arm64 Globals: Function: @@ -27,36 +24,11 @@ Resources: Architectures: [x86_64] CodeUri: ./ Handler: ApiBootstrap - Environment: - Variables: - DEMO_BASE_PATH: /x86 - Events: - Api: - Type: HttpApi - Properties: - Path: /x86/{proxy+} - Method: ANY - Policies: - - DynamoDBCrudPolicy: - TableName: - !Ref Table - Metadata: - BuildMethod: makefile - MinimalApiArm64: - Type: AWS::Serverless::Function - Properties: - FunctionName: !Ref arm64FunctionName - Architectures: [arm64] - CodeUri: ./ - Handler: ApiBootstrap - Environment: - Variables: - DEMO_BASE_PATH: /arm64 Events: Api: Type: HttpApi Properties: - Path: /arm64/{proxy+} + Path: /{proxy+} Method: ANY Policies: - DynamoDBCrudPolicy: @@ -87,10 +59,4 @@ Outputs: Value: !Ref x86FunctionName ApiUrlX86: Description: "X86 API endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/x86" - LambdaArm64Name: - Description: "Lambda Arm64 Name" - Value: !Ref arm64FunctionName - ApiUrlArm64: - Description: "Arm64 GateAPI endpoint URL" - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/arm64" \ No newline at end of file + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" \ No newline at end of file From c664217fc0557c036a7571426f2ae0bc9cfcecf9 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 12 Nov 2023 21:34:40 +0100 Subject: [PATCH 20/24] adding ability to choose .netsdk to be used in codebuild --- loadtest/codebuild/load-test-buildspec.yml | 14 ++++++++++---- loadtest/codebuild/setup.sh | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100755 loadtest/codebuild/setup.sh diff --git a/loadtest/codebuild/load-test-buildspec.yml b/loadtest/codebuild/load-test-buildspec.yml index 8e5a880..b9f2a0b 100644 --- a/loadtest/codebuild/load-test-buildspec.yml +++ b/loadtest/codebuild/load-test-buildspec.yml @@ -3,17 +3,23 @@ version: 0.2 phases: install: commands: - - curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0 - - npm i artillery -g + - cd loadtest/codebuild + - ./setup.sh build: commands: - - export temp1=$(pwd);echo $temp1 - - cd loadtest/codebuild - ./run-all-load-tests.sh artifacts: files: + - src/NET6/Report/* + - src/NET6Containers/Report/* + - src/NET6CustomRuntime/Report/* - src/NET6MinimalAPI/Report/* - src/NET6MinimalAPIWebAdapter/Report/* + - src/NET6Native/Report/* + - src/NET6TopLevelStatements/Report/* + - src/NET6WithPowerTools/Report/* - src/NET8/Report/* - src/NET8MinimalAPI/Report/* + - src/NET8Native/Report/* + - src/NET8NativeMinimalApi/Report/* name: loadtest-$(date +%Y-%m-%H-%M) \ No newline at end of file diff --git a/loadtest/codebuild/setup.sh b/loadtest/codebuild/setup.sh new file mode 100755 index 0000000..ffa1a0b --- /dev/null +++ b/loadtest/codebuild/setup.sh @@ -0,0 +1,16 @@ +#LT_NET_SDK_CHANNEL +#Specifies the source channel for the installation. The possible values are: +# STS: The most recent Standard Term Support release. +# LTS: The most recent Long Term Support release. +# Two-part version in A.B format, representing a specific release (for example, 3.1 or 6.0). +# Three-part version in A.B.Cxx format, representing a specific SDK release (for example, 6.0.1xx or 6.0.2xx). Available since the 5.0 release. +echo -------------------------------------------- +echo Installing dotnet runtime version: $LT_NET_SDK_CHANNEL +echo -------------------------------------------- + +curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel $LT_NET_SDK_CHANNEL + +echo -------------------------------------------- +echo Installing artillery +echo -------------------------------------------- +npm i artillery -g \ No newline at end of file From 13103c69707bb548fe65f8f4b1f0463c7dd7a2a6 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 12 Nov 2023 22:24:49 +0100 Subject: [PATCH 21/24] . --- loadtest/codebuild/run-all-load-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loadtest/codebuild/run-all-load-tests.sh b/loadtest/codebuild/run-all-load-tests.sh index 931176b..2febd69 100755 --- a/loadtest/codebuild/run-all-load-tests.sh +++ b/loadtest/codebuild/run-all-load-tests.sh @@ -85,7 +85,7 @@ then echo SKIPPING net8 native minimal api LT_NET8_NATIVE_MINIMAL_API=$LT_NET8_NATIVE_MINIMAL_API else echo "RUNNING load test for net8 native minimal api" - cd ../../src/NET8NativeMinimalApi/ + cd ../../src/NET8NativeMinimalAPI/ source ./deploy.sh $DELETE_STACK source ./run-loadtest.sh $TEST_DURATIOMN_SEC $LOG_INTERVAL_MIN $LOG_DELETE fi \ No newline at end of file From befff93308cf3cbee260cea033a0f698383d6ab6 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Sun, 12 Nov 2023 22:36:04 +0100 Subject: [PATCH 22/24] . --- loadtest/codebuild/load-test-buildspec.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loadtest/codebuild/load-test-buildspec.yml b/loadtest/codebuild/load-test-buildspec.yml index b9f2a0b..84bccfb 100644 --- a/loadtest/codebuild/load-test-buildspec.yml +++ b/loadtest/codebuild/load-test-buildspec.yml @@ -21,5 +21,5 @@ artifacts: - src/NET8/Report/* - src/NET8MinimalAPI/Report/* - src/NET8Native/Report/* - - src/NET8NativeMinimalApi/Report/* + - src/NET8NativeMinimalAPI/Report/* name: loadtest-$(date +%Y-%m-%H-%M) \ No newline at end of file From 893391b7f67d2f220cbdc53cb15d202dd2560708 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Mon, 13 Nov 2023 08:09:03 +0100 Subject: [PATCH 23/24] . --- src/NET8/deploy.sh | 2 +- src/NET8MinimalAPI/deploy.sh | 2 +- src/NET8Native/deploy.sh | 2 +- src/NET8NativeMinimalAPI/deploy.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NET8/deploy.sh b/src/NET8/deploy.sh index 9aae7f5..814ecb5 100755 --- a/src/NET8/deploy.sh +++ b/src/NET8/deploy.sh @@ -7,7 +7,7 @@ DELETE_STACK=yes COLOR='\033[0;33m' NO_COLOR='\033[0m' # No Color -if [ "x$4" != x ]; +if [ "x$1" != x ]; then DELETE_STACK=$1 fi diff --git a/src/NET8MinimalAPI/deploy.sh b/src/NET8MinimalAPI/deploy.sh index 80e0ccd..1caf08f 100755 --- a/src/NET8MinimalAPI/deploy.sh +++ b/src/NET8MinimalAPI/deploy.sh @@ -7,7 +7,7 @@ DELETE_STACK=yes COLOR='\033[0;33m' NO_COLOR='\033[0m' # No Color -if [ "x$4" != x ]; +if [ "x$1" != x ]; then DELETE_STACK=$1 fi diff --git a/src/NET8Native/deploy.sh b/src/NET8Native/deploy.sh index dda9b4d..a6d0c85 100755 --- a/src/NET8Native/deploy.sh +++ b/src/NET8Native/deploy.sh @@ -7,7 +7,7 @@ DELETE_STACK=yes COLOR='\033[0;33m' NO_COLOR='\033[0m' # No Color -if [ "x$4" != x ]; +if [ "x$1" != x ]; then DELETE_STACK=$1 fi diff --git a/src/NET8NativeMinimalAPI/deploy.sh b/src/NET8NativeMinimalAPI/deploy.sh index 71a251b..d6da858 100755 --- a/src/NET8NativeMinimalAPI/deploy.sh +++ b/src/NET8NativeMinimalAPI/deploy.sh @@ -7,7 +7,7 @@ DELETE_STACK=yes COLOR='\033[0;33m' NO_COLOR='\033[0m' # No Color -if [ "x$4" != x ]; +if [ "x$1" != x ]; then DELETE_STACK=$1 fi From 8c4093afdeb975755883e835d3d42437d2291261 Mon Sep 17 00:00:00 2001 From: Riccardo Venturi Date: Wed, 15 Nov 2023 20:46:39 +0100 Subject: [PATCH 24/24] updating load test scripts --- src/NET8/run-loadtest.sh | 31 +++++++++++++++++++++- src/NET8MinimalAPI/run-loadtest.sh | 33 +++++++++++++++++++++--- src/NET8Native/run-loadtest.sh | 31 +++++++++++++++++++++- src/NET8NativeMinimalAPI/run-loadtest.sh | 29 ++++++++++++++++++++- 4 files changed, 118 insertions(+), 6 deletions(-) diff --git a/src/NET8/run-loadtest.sh b/src/NET8/run-loadtest.sh index 2391e84..58d219a 100755 --- a/src/NET8/run-loadtest.sh +++ b/src/NET8/run-loadtest.sh @@ -1,7 +1,8 @@ #Arguments: #$1 - load test duration in seconds #$2 - log interval to be used in the cloudwatch query in minutes -#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$3 - when equal to yes cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$4 - ARN of sns topic to notify test results STACK_NAME=dotnet8 TEST_DURATIOMN_SEC=60 @@ -26,11 +27,17 @@ then LOG_DELETE=$3 fi +if [ "x$4" != x ]; +then + SNS_TOPIC_ARN=$4 +fi + echo "${COLOR}" echo -------------------------------------------- echo DURATION:$TEST_DURATIOMN_SEC echo LOG INTERVAL:$LOG_INTERVAL_MIN echo LOG_DELETE: $LOG_DELETE +echo SNS_TOPIC_ARN: $SNS_TOPIC_ARN echo -------------------------------------------- echo "${NO_COLOR}" @@ -120,6 +127,18 @@ function RunLoadTest() echo Log start:$startdate end:$enddate echo -------------------------------------------- + echo -------------------------------------------- + echo GET ERROR METRICS $1 + echo -------------------------------------------- + aws cloudwatch get-metric-statistics \ + --namespace AWS/Lambda \ + --metric-name Errors \ + --dimensions Name=FunctionName,Value=$LAMBDA_GETPRODUCTS Name=FunctionName,Value=$LAMBDA_GETPRODUCT Name=FunctionName,Value=$LAMBDA_DELETEPRODUCT Name=FunctionName,Value=$LAMBDA_PUTPRODUCT \ + --statistics Sum --period 43200 \ + --start-time $startdate --end-time $enddate > ./Report/load-test-errors-$1.json + + cat ./Report/load-test-errors-$1.json + QUERY_ID=$(aws logs start-query \ --log-group-names "/aws/lambda/$LAMBDA_GETPRODUCTS" "/aws/lambda/$LAMBDA_GETPRODUCT" "/aws/lambda/$LAMBDA_DELETEPRODUCT" "/aws/lambda/$LAMBDA_PUTPRODUCT" \ --start-time $startdate \ @@ -147,6 +166,16 @@ function RunLoadTest() aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt cat ./Report/load-test-report-$1.txt aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json + + if [ "x$SNS_TOPIC_ARN" != x ]; + then + echo -------------------------------------------- + echo Sending message to sns topic: $SNS_TOPIC_ARN + echo -------------------------------------------- + msg=$(<./Report/load-test-report-$1.txt)\n\n$(<./Report/load-test-errors-$1.json) + subject="serverless dotnet demo load test result for $LAMBDA_GETPRODUCTS" + aws sns publish --topic-arn $SNS_TOPIC_ARN --subject "$subject" --message "$msg" + fi } RunLoadTest x86 ApiUrlX86 LambdaX86NameGetProducts LambdaX86NameGetProduct LambdaX86NameDeleteProduct LambdaX86NamePutProduct diff --git a/src/NET8MinimalAPI/run-loadtest.sh b/src/NET8MinimalAPI/run-loadtest.sh index 4c69913..c8ee870 100755 --- a/src/NET8MinimalAPI/run-loadtest.sh +++ b/src/NET8MinimalAPI/run-loadtest.sh @@ -1,7 +1,8 @@ #Arguments: #$1 - load test duration in seconds #$2 - log interval to be used in the cloudwatch query in minutes -#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$3 - when equal to yes cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$4 - ARN of sns topic to notify test results STACK_NAME=dotnet8-minimal-api TEST_DURATIOMN_SEC=60 @@ -26,11 +27,17 @@ then LOG_DELETE=$3 fi +if [ "x$4" != x ]; +then + SNS_TOPIC_ARN=$4 +fi + echo "${COLOR}" echo -------------------------------------------- echo DURATION:$TEST_DURATIOMN_SEC echo LOG INTERVAL:$LOG_INTERVAL_MIN echo LOG_DELETE: $LOG_DELETE +echo SNS_TOPIC_ARN: $SNS_TOPIC_ARN echo -------------------------------------------- echo "${NO_COLOR}" @@ -75,8 +82,8 @@ function RunLoadTest() artillery run \ --overrides '{"config": { "phases": [{ "duration": '$TEST_DURATIOMN_SEC', "arrivalRate": 100 }] } }' \ --quiet \ - ../../loadtest/load-test.yml - + ../../loadtest/codebuild/load-test.yml + echo "${COLOR}" echo -------------------------------------------- echo Waiting 10 sec. for logs to consolidate @@ -90,6 +97,16 @@ function RunLoadTest() echo Log start:$startdate end:$enddate echo -------------------------------------------- + echo -------------------------------------------- + echo GET ERROR METRICS $1 + echo -------------------------------------------- + aws cloudwatch get-metric-statistics \ + --namespace AWS/Lambda \ + --metric-name Errors \ + --dimensions Name=FunctionName,Value=$LAMBDA \ + --statistics Sum --period 43200 \ + --start-time $startdate --end-time $enddate > ./Report/load-test-errors-$1.json + QUERY_ID=$(aws logs start-query \ --log-group-name /aws/lambda/$LAMBDA \ --start-time $startdate \ @@ -117,6 +134,16 @@ function RunLoadTest() aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt cat ./Report/load-test-report-$1.txt aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json + + if [ "x$SNS_TOPIC_ARN" != x ]; + then + echo -------------------------------------------- + echo Sending message to sns topic: $SNS_TOPIC_ARN + echo -------------------------------------------- + msg=$(<./Report/load-test-report-$1.txt)\n\n$(<./Report/load-test-errors-$1.json) + subject="serverless dotnet demo load test result for $LAMBDA" + aws sns publish --topic-arn $SNS_TOPIC_ARN --subject "$subject" --message "$msg" + fi } RunLoadTest x86 ApiUrlX86 LambdaX86Name diff --git a/src/NET8Native/run-loadtest.sh b/src/NET8Native/run-loadtest.sh index dd87955..48bc775 100755 --- a/src/NET8Native/run-loadtest.sh +++ b/src/NET8Native/run-loadtest.sh @@ -1,7 +1,8 @@ #Arguments: #$1 - load test duration in seconds #$2 - log interval to be used in the cloudwatch query in minutes -#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$3 - when equal to yes cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$4 - ARN of sns topic to notify test results STACK_NAME=dotnet8-native TEST_DURATIOMN_SEC=60 @@ -26,11 +27,17 @@ then LOG_DELETE=$3 fi +if [ "x$4" != x ]; +then + SNS_TOPIC_ARN=$4 +fi + echo "${COLOR}" echo -------------------------------------------- echo DURATION:$TEST_DURATIOMN_SEC echo LOG INTERVAL:$LOG_INTERVAL_MIN echo LOG_DELETE: $LOG_DELETE +echo SNS_TOPIC_ARN: $SNS_TOPIC_ARN echo -------------------------------------------- echo "${NO_COLOR}" @@ -120,6 +127,18 @@ function RunLoadTest() echo Log start:$startdate end:$enddate echo -------------------------------------------- + echo -------------------------------------------- + echo GET ERROR METRICS $1 + echo -------------------------------------------- + aws cloudwatch get-metric-statistics \ + --namespace AWS/Lambda \ + --metric-name Errors \ + --dimensions Name=FunctionName,Value=$LAMBDA_GETPRODUCTS Name=FunctionName,Value=$LAMBDA_GETPRODUCT Name=FunctionName,Value=$LAMBDA_DELETEPRODUCT Name=FunctionName,Value=$LAMBDA_PUTPRODUCT \ + --statistics Sum --period 43200 \ + --start-time $startdate --end-time $enddate > ./Report/load-test-errors-$1.json + + cat ./Report/load-test-errors-$1.json + QUERY_ID=$(aws logs start-query \ --log-group-names "/aws/lambda/$LAMBDA_GETPRODUCTS" "/aws/lambda/$LAMBDA_GETPRODUCT" "/aws/lambda/$LAMBDA_DELETEPRODUCT" "/aws/lambda/$LAMBDA_PUTPRODUCT" \ --start-time $startdate \ @@ -147,6 +166,16 @@ function RunLoadTest() aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt cat ./Report/load-test-report-$1.txt aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json + + if [ "x$SNS_TOPIC_ARN" != x ]; + then + echo -------------------------------------------- + echo Sending message to sns topic: $SNS_TOPIC_ARN + echo -------------------------------------------- + msg=$(<./Report/load-test-report-$1.txt)\n\n$(<./Report/load-test-errors-$1.json) + subject="serverless dotnet demo load test result for $LAMBDA_GETPRODUCTS" + aws sns publish --topic-arn $SNS_TOPIC_ARN --subject "$subject" --message "$msg" + fi } RunLoadTest x86 ApiUrlX86 LambdaX86NameGetProducts LambdaX86NameGetProduct LambdaX86NameDeleteProduct LambdaX86NamePutProduct \ No newline at end of file diff --git a/src/NET8NativeMinimalAPI/run-loadtest.sh b/src/NET8NativeMinimalAPI/run-loadtest.sh index 351288a..c4cd293 100755 --- a/src/NET8NativeMinimalAPI/run-loadtest.sh +++ b/src/NET8NativeMinimalAPI/run-loadtest.sh @@ -1,7 +1,8 @@ #Arguments: #$1 - load test duration in seconds #$2 - log interval to be used in the cloudwatch query in minutes -#$3 - when equal to 1 cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$3 - when equal to yes cloudwatch log group will be deleted to ensure that only logs of the load test will be evaluated for stat +#$4 - ARN of sns topic to notify test results STACK_NAME=dotnet8-native-minimal-api TEST_DURATIOMN_SEC=60 @@ -26,11 +27,17 @@ then LOG_DELETE=$3 fi +if [ "x$4" != x ]; +then + SNS_TOPIC_ARN=$4 +fi + echo "${COLOR}" echo -------------------------------------------- echo DURATION:$TEST_DURATIOMN_SEC echo LOG INTERVAL:$LOG_INTERVAL_MIN echo LOG_DELETE: $LOG_DELETE +echo SNS_TOPIC_ARN: $SNS_TOPIC_ARN echo -------------------------------------------- echo "${NO_COLOR}" @@ -90,6 +97,16 @@ function RunLoadTest() echo Log start:$startdate end:$enddate echo -------------------------------------------- + echo -------------------------------------------- + echo GET ERROR METRICS $1 + echo -------------------------------------------- + aws cloudwatch get-metric-statistics \ + --namespace AWS/Lambda \ + --metric-name Errors \ + --dimensions Name=FunctionName,Value=$LAMBDA \ + --statistics Sum --period 43200 \ + --start-time $startdate --end-time $enddate > ./Report/load-test-errors-$1.json + QUERY_ID=$(aws logs start-query \ --log-group-name /aws/lambda/$LAMBDA \ --start-time $startdate \ @@ -117,6 +134,16 @@ function RunLoadTest() aws logs get-query-results --query-id $QUERY_ID --output text >> ./Report/load-test-report-$1.txt cat ./Report/load-test-report-$1.txt aws logs get-query-results --query-id $QUERY_ID --output json >> ./Report/load-test-report-$1.json + + if [ "x$SNS_TOPIC_ARN" != x ]; + then + echo -------------------------------------------- + echo Sending message to sns topic: $SNS_TOPIC_ARN + echo -------------------------------------------- + msg=$(<./Report/load-test-report-$1.txt)\n\n$(<./Report/load-test-errors-$1.json) + subject="serverless dotnet demo load test result for $LAMBDA" + aws sns publish --topic-arn $SNS_TOPIC_ARN --subject "$subject" --message "$msg" + fi } RunLoadTest x86 ApiUrlX86 LambdaX86Name \ No newline at end of file