From 603f3dd18e8f8e4f8625e0d342e61270993ab4f2 Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Wed, 7 Jun 2023 15:21:42 -0700 Subject: [PATCH 01/16] feat: Add DynamoLambda example --- examples/DynamoLambdaExample/.gitignore | 342 ++++++++++++++++++ .../DynamoLambdaExampleHandler.csproj | 19 + .../DynamoLambdaExampleHandler/Function.cs | 52 +++ .../src/DynamoLambdaExampleHandler/Readme.md | 49 +++ .../aws-lambda-tools-defaults.json | 16 + .../DynamoLambdaExampleHandler.Tests.csproj | 17 + .../FunctionTest.cs | 20 + .../DynamoLambdaExampleHandler1.csproj | 19 + .../DynamoLambdaExampleHandler1/Function.cs | 83 +++++ .../src/DynamoLambdaExampleHandler1/Readme.md | 49 +++ .../aws-lambda-tools-defaults.json | 16 + .../DynamoLambdaExampleHandler1.Tests.csproj | 17 + .../FunctionTest.cs | 20 + examples/DynamoLambdaExample/README.md | 14 + examples/DynamoLambdaExample/cdk.json | 52 +++ .../src/DynamoLambdaExample.sln | 34 ++ .../DynamoLambdaExample.csproj | 20 + .../DynamoLambdaExampleStack.cs | 20 + .../DynamoLambdaExample/GlobalSuppressions.cs | 1 + .../src/DynamoLambdaExample/Program.cs | 18 + 20 files changed, 878 insertions(+) create mode 100644 examples/DynamoLambdaExample/.gitignore create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj create mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs create mode 100644 examples/DynamoLambdaExample/README.md create mode 100644 examples/DynamoLambdaExample/cdk.json create mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample.sln create mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj create mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs create mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs create mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs diff --git a/examples/DynamoLambdaExample/.gitignore b/examples/DynamoLambdaExample/.gitignore new file mode 100644 index 00000000..a4609e75 --- /dev/null +++ b/examples/DynamoLambdaExample/.gitignore @@ -0,0 +1,342 @@ +# CDK asset staging directory +.cdk.staging +cdk.out + +# Created by https://www.gitignore.io/api/csharp + +### Csharp ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + + +# End of https://www.gitignore.io/api/csharp \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj new file mode 100644 index 00000000..66ae5758 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj @@ -0,0 +1,19 @@ + + + net6.0 + enable + enable + true + Lambda + + true + + true + + + + + + + + \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs new file mode 100644 index 00000000..63fc4860 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs @@ -0,0 +1,52 @@ +using Amazon; +using Amazon.DynamoDBv2; +using Amazon.DynamoDBv2.Model; +using Amazon.Lambda.Core; +using Amazon.Runtime; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace DynamoLambdaExampleHandler +{ + public class Function + { + public async Task FunctionHandler(ILambdaContext context) + { + var client = new AmazonDynamoDBClient(); + + // Set up the item details + string tableName = "TacoBellInvestigator"; + string keyAttributeName = "key"; + string valueAttributeName = "value"; + + string keyAttributeBase = "test-key"; + string valueAttributeBase = "test-value"; + + for (int i = 1; i <= 20; i++) + { + string keyAttributeValue = $"{keyAttributeBase}-{i}"; + string valueAttributeValue = $"{valueAttributeBase}-{i}"; + + // Create the item request + var request = new PutItemRequest + { + TableName = tableName, + Item = new Dictionary + { + { keyAttributeName, new AttributeValue { S = keyAttributeValue } }, + { valueAttributeName, new AttributeValue { S = valueAttributeValue } }, + } + }; + + // Put the item in the table + await client.PutItemAsync(request); + } + + client.Dispose(); + return "Item created successfully"; + } + } +} diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md new file mode 100644 index 00000000..b74f212b --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md @@ -0,0 +1,49 @@ +# AWS Lambda Empty Function Project + +This starter project consists of: +* Function.cs - class file containing a class with a single function handler method +* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS + +You may also have a test project depending on the options selected. + +The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. + +## Here are some steps to follow from Visual Studio: + +To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. + +To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. + +To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. + +To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. + +To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. + +To view execution logs of invocations of your function use the Logs tab in the opened Function View window. + +## Here are some steps to follow to get started from the command line: + +Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. + +Install Amazon.Lambda.Tools Global Tools if not already installed. +``` + dotnet tool install -g Amazon.Lambda.Tools +``` + +If already installed check if new version is available. +``` + dotnet tool update -g Amazon.Lambda.Tools +``` + +Execute unit tests +``` + cd "DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests" + dotnet test +``` + +Deploy function to AWS Lambda +``` + cd "DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler" + dotnet lambda deploy-function +``` diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json new file mode 100644 index 00000000..10049ef6 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json @@ -0,0 +1,16 @@ +{ + "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-architecture": "x86_64", + "function-runtime": "dotnet6", + "function-memory-size": 256, + "function-timeout": 30, + "function-handler": "DynamoLambdaExampleHandler::DynamoLambdaExampleHandler.Function::FunctionHandler" +} \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj new file mode 100644 index 00000000..4c27001e --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj @@ -0,0 +1,17 @@ + + + net6.0 + enable + enable + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs new file mode 100644 index 00000000..1c6fe2eb --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs @@ -0,0 +1,20 @@ +using Xunit; +using Amazon.Lambda.Core; +using Amazon.Lambda.TestUtilities; + +namespace DynamoLambdaExampleHandler.Tests; + +public class FunctionTest +{ + [Fact] + public void TestToUpperFunction() + { + + // Invoke the lambda function and confirm the string was upper cased. + var function = new Function(); + var context = new TestLambdaContext(); + var upperCase = function.FunctionHandler("hello world", context); + + Assert.Equal("HELLO WORLD", upperCase); + } +} diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj new file mode 100644 index 00000000..8a08fe52 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj @@ -0,0 +1,19 @@ + + + net6.0 + Exe + enable + enable + true + Lambda + + true + + true + + + + + + + \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs new file mode 100644 index 00000000..c08e606e --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs @@ -0,0 +1,83 @@ +using Amazon; +using Amazon.DynamoDBv2; +using Amazon.DynamoDBv2.Model; +using Amazon.Lambda.Core; +using Amazon.Runtime; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace DynamoLambdaExampleHandler1; + +public class Function +{ + public async Task FunctionHandler(ILambdaContext context) + { + DoStuff(); + return "Task completed"; + } + + public void DoStuff() { + + var client = new AmazonDynamoDBClient(); + + var numRequests = 10; + // var tasks = new Task[numRequests]; + var tasks = new Dictionary, System.Diagnostics.Stopwatch>(); + + string tableName = "TacoBellInvestigator"; + string keyAttributeName = "key"; + string keyAttributeBase = "test-key"; + + for (int i = 1; i <= numRequests; i++) { + Console.WriteLine("getting inside the loop"); + string keyAttributeValue = $"{keyAttributeBase}-{i}"; + var request = new GetItemRequest + { + TableName = tableName, + Key = new Dictionary + { + {keyAttributeName, new AttributeValue { S = keyAttributeValue}} + } + }; + + Console.WriteLine("request created"); + var startTime = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine("starting the timer"); + var response = client.GetItemAsync(request); + Console.WriteLine(response); + + tasks[response] = startTime; + response.ContinueWith( + (r) => { + tasks[response].Stop(); + return r; + } + ); + Console.WriteLine("continue with done"); + } + + Console.WriteLine("Awaiting for the tasks"); + Task.WaitAll(tasks.Keys.ToArray()); + Console.WriteLine("done awaiting"); + + foreach(var entry in tasks) + { + Console.WriteLine(entry.Value.ElapsedMilliseconds); + } + } + + + static void Main(string[] args) { + try { + new Function().DoStuff(); + } catch(Exception ex) { + Console.WriteLine("Caught Exception"); + Console.WriteLine(ex); + } + } + +} diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md new file mode 100644 index 00000000..dbec4177 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md @@ -0,0 +1,49 @@ +# AWS Lambda Empty Function Project + +This starter project consists of: +* Function.cs - class file containing a class with a single function handler method +* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS + +You may also have a test project depending on the options selected. + +The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. + +## Here are some steps to follow from Visual Studio: + +To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. + +To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. + +To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. + +To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. + +To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. + +To view execution logs of invocations of your function use the Logs tab in the opened Function View window. + +## Here are some steps to follow to get started from the command line: + +Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. + +Install Amazon.Lambda.Tools Global Tools if not already installed. +``` + dotnet tool install -g Amazon.Lambda.Tools +``` + +If already installed check if new version is available. +``` + dotnet tool update -g Amazon.Lambda.Tools +``` + +Execute unit tests +``` + cd "DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests" + dotnet test +``` + +Deploy function to AWS Lambda +``` + cd "DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1" + dotnet lambda deploy-function +``` diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json new file mode 100644 index 00000000..2d65c0b4 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json @@ -0,0 +1,16 @@ +{ + "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-architecture": "x86_64", + "function-runtime": "dotnet6", + "function-memory-size": 256, + "function-timeout": 30, + "function-handler": "DynamoLambdaExampleHandler1::DynamoLambdaExampleHandler1.Function::FunctionHandler" +} \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj new file mode 100644 index 00000000..892efe76 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj @@ -0,0 +1,17 @@ + + + net6.0 + enable + enable + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs new file mode 100644 index 00000000..333b9983 --- /dev/null +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs @@ -0,0 +1,20 @@ +using Xunit; +using Amazon.Lambda.Core; +using Amazon.Lambda.TestUtilities; + +namespace DynamoLambdaExampleHandler1.Tests; + +public class FunctionTest +{ + [Fact] + public void TestToUpperFunction() + { + + // Invoke the lambda function and confirm the string was upper cased. + var function = new Function(); + var context = new TestLambdaContext(); + var upperCase = function.FunctionHandler("hello world", context); + + Assert.Equal("HELLO WORLD", upperCase); + } +} diff --git a/examples/DynamoLambdaExample/README.md b/examples/DynamoLambdaExample/README.md new file mode 100644 index 00000000..f28e4d55 --- /dev/null +++ b/examples/DynamoLambdaExample/README.md @@ -0,0 +1,14 @@ +# Welcome to your CDK C# project! + +This is a blank project for CDK development with C#. + +The `cdk.json` file tells the CDK Toolkit how to execute your app. + +It uses the [.NET CLI](https://docs.microsoft.com/dotnet/articles/core/) to compile and execute your project. + +## Useful commands + +* `dotnet build src` compile this app +* `cdk deploy` deploy this stack to your default AWS account/region +* `cdk diff` compare deployed stack with current state +* `cdk synth` emits the synthesized CloudFormation template \ No newline at end of file diff --git a/examples/DynamoLambdaExample/cdk.json b/examples/DynamoLambdaExample/cdk.json new file mode 100644 index 00000000..c38ed0e6 --- /dev/null +++ b/examples/DynamoLambdaExample/cdk.json @@ -0,0 +1,52 @@ +{ + "app": "dotnet run --project src/DynamoLambdaExample/DynamoLambdaExample.csproj", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "src/*/obj", + "src/*/bin", + "src/*.sln", + "src/*/GlobalSuppressions.cs", + "src/*/*.csproj" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true + } +} diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample.sln b/examples/DynamoLambdaExample/src/DynamoLambdaExample.sln new file mode 100644 index 00000000..3fcc8d61 --- /dev/null +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamoLambdaExample", "DynamoLambdaExample\DynamoLambdaExample.csproj", "{ED03731A-32CF-436F-93B6-7BD16EDB667B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x64.ActiveCfg = Debug|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x64.Build.0 = Debug|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x86.ActiveCfg = Debug|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x86.Build.0 = Debug|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|Any CPU.Build.0 = Release|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x64.ActiveCfg = Release|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x64.Build.0 = Release|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x86.ActiveCfg = Release|Any CPU + {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj new file mode 100644 index 00000000..dad278f5 --- /dev/null +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj @@ -0,0 +1,20 @@ + + + + Exe + net6.0 + + Major + + + + + + + + + + + diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs new file mode 100644 index 00000000..bafd2292 --- /dev/null +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs @@ -0,0 +1,20 @@ +using Amazon.CDK; +using Amazon.CDK.AWS.Lambda; +using Constructs; +using Amazon.CDK.AWS.IAM; + +namespace DynamoLambdaExample +{ + public class DynamoLambdaExampleStack : Stack + { + internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) + { + Function fn = new Function(this, "DynamoLambdaExampleHandler", new FunctionProps + { + Runtime = Runtime.DOTNET_6, + Code = Code.FromAsset("./DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/bin/Release/net6.0/publish"), + Handler = "DynamoLambdaExampleHandler::DynamoLambdaExampleHandler.Function::FunctionHandler" + }); + } + } +} diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs new file mode 100644 index 00000000..26233fcb --- /dev/null +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs @@ -0,0 +1 @@ +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "Constructs add themselves to the scope in which they are created")] diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs new file mode 100644 index 00000000..9417b10d --- /dev/null +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs @@ -0,0 +1,18 @@ +using Amazon.CDK; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DynamoLambdaExample +{ + sealed class Program + { + public static void Main(string[] args) + { + var app = new App(); + new DynamoLambdaExampleStack(app, "DynamoLambdaExampleStack"); + + app.Synth(); + } + } +} From cdff4c38303e43fa5a43656c04305186f569c2b0 Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Wed, 7 Jun 2023 15:45:06 -0700 Subject: [PATCH 02/16] feat: Add cdk code for get and put handlers --- .../src/DynamoLambdaExampleHandler1/Function.cs | 12 ++++++------ .../DynamoLambdaExampleStack.cs | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs index c08e606e..fa1b2d19 100644 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs @@ -33,7 +33,7 @@ public void DoStuff() { string keyAttributeBase = "test-key"; for (int i = 1; i <= numRequests; i++) { - Console.WriteLine("getting inside the loop"); + Console.WriteLine("Getting inside the loop"); string keyAttributeValue = $"{keyAttributeBase}-{i}"; var request = new GetItemRequest { @@ -44,9 +44,9 @@ public void DoStuff() { } }; - Console.WriteLine("request created"); + Console.WriteLine("GetRequest created"); var startTime = System.Diagnostics.Stopwatch.StartNew(); - Console.WriteLine("starting the timer"); + Console.WriteLine("Starting the stopwatch"); var response = client.GetItemAsync(request); Console.WriteLine(response); @@ -57,12 +57,12 @@ public void DoStuff() { return r; } ); - Console.WriteLine("continue with done"); + Console.WriteLine("Stopped stopwatch"); } - Console.WriteLine("Awaiting for the tasks"); + Console.WriteLine("Awaiting pending tasks..."); Task.WaitAll(tasks.Keys.ToArray()); - Console.WriteLine("done awaiting"); + Console.WriteLine("Done awaiting tasks"); foreach(var entry in tasks) { diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs index bafd2292..51cc5304 100644 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs @@ -13,7 +13,20 @@ internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props { Runtime = Runtime.DOTNET_6, Code = Code.FromAsset("./DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/bin/Release/net6.0/publish"), - Handler = "DynamoLambdaExampleHandler::DynamoLambdaExampleHandler.Function::FunctionHandler" + Handler = "DynamoLambdaExampleHandler::DynamoLambdaExampleHandler.Function::FunctionHandler", + FunctionName = "PutItemHandler", + MemorySize = 1024, + Timeout = Duration.Seconds(300) + }); + + Function fn1 = new Function(this, "DynamoLambdaExampleHandler1", new FunctionProps + { + Runtime = Runtime.DOTNET_6, + Code = Code.FromAsset("./DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/bin/Release/net6.0/publish"), + Handler = "DynamoLambdaExampleHandler1::DynamoLambdaExampleHandler1.Function::FunctionHandler", + FunctionName = "GetItemHandler", + MemorySize = 1024, + Timeout = Duration.Seconds(300) }); } } From bef73016eb68db057b498104238b8022b249eecc Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Wed, 7 Jun 2023 16:18:31 -0700 Subject: [PATCH 03/16] feat: Add lambda execution role via cdk --- .../DynamoLambdaExampleStack.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs index 51cc5304..35b49ee3 100644 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs @@ -9,6 +9,18 @@ public class DynamoLambdaExampleStack : Stack { internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { + // Create the IAM role for the Lambda function + Role lambdaRole = new Role(this, "LambdaRole", new RoleProps + { + AssumedBy = new ServicePrincipal("lambda.amazonaws.com"), + RoleName = "LambdaDynamoDBRole" + }); + + // Attach the managed policies + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")); + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonDynamoDBFullAccess")); + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AWSLambdaInvocation-DynamoDB")); + Function fn = new Function(this, "DynamoLambdaExampleHandler", new FunctionProps { Runtime = Runtime.DOTNET_6, @@ -16,7 +28,8 @@ internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props Handler = "DynamoLambdaExampleHandler::DynamoLambdaExampleHandler.Function::FunctionHandler", FunctionName = "PutItemHandler", MemorySize = 1024, - Timeout = Duration.Seconds(300) + Timeout = Duration.Seconds(300), + Role = lambdaRole }); Function fn1 = new Function(this, "DynamoLambdaExampleHandler1", new FunctionProps @@ -26,7 +39,8 @@ internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props Handler = "DynamoLambdaExampleHandler1::DynamoLambdaExampleHandler1.Function::FunctionHandler", FunctionName = "GetItemHandler", MemorySize = 1024, - Timeout = Duration.Seconds(300) + Timeout = Duration.Seconds(300), + Role = lambdaRole }); } } From 0d6bb687fdd8085eba223f63e321f8cc444f92d0 Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Thu, 8 Jun 2023 10:36:35 -0700 Subject: [PATCH 04/16] feat: trying redis client --- .../DynamoLambdaExampleHandler1.csproj | 1 + .../DynamoLambdaExampleHandler1/Function.cs | 130 +++++++++++------- 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj index 8a08fe52..e7105231 100644 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj @@ -15,5 +15,6 @@ + \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs index fa1b2d19..eb98069c 100644 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs @@ -1,11 +1,12 @@ -using Amazon; -using Amazon.DynamoDBv2; -using Amazon.DynamoDBv2.Model; +// using Amazon; +// using Amazon.DynamoDBv2; +// using Amazon.DynamoDBv2.Model; using Amazon.Lambda.Core; -using Amazon.Runtime; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; +// using Amazon.Runtime; +// using System; +// using System.Collections.Generic; +// using System.Threading.Tasks; +// using StackExchange.Redis; // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] @@ -20,59 +21,84 @@ public async Task FunctionHandler(ILambdaContext context) return "Task completed"; } - public void DoStuff() { - - var client = new AmazonDynamoDBClient(); - - var numRequests = 10; - // var tasks = new Task[numRequests]; - var tasks = new Dictionary, System.Diagnostics.Stopwatch>(); - - string tableName = "TacoBellInvestigator"; - string keyAttributeName = "key"; - string keyAttributeBase = "test-key"; - - for (int i = 1; i <= numRequests; i++) { - Console.WriteLine("Getting inside the loop"); - string keyAttributeValue = $"{keyAttributeBase}-{i}"; - var request = new GetItemRequest - { - TableName = tableName, - Key = new Dictionary - { - {keyAttributeName, new AttributeValue { S = keyAttributeValue}} - } - }; - - Console.WriteLine("GetRequest created"); - var startTime = System.Diagnostics.Stopwatch.StartNew(); - Console.WriteLine("Starting the stopwatch"); - var response = client.GetItemAsync(request); - Console.WriteLine(response); + public async void DoStuff() { + + // Create a Redis connection + // Console.WriteLine("Creating redis client"); + // ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); + + // // Get a Redis database + // Console.WriteLine("Fetching db"); + // IDatabase db = redis.GetDatabase(); + + // // Ping the redis server + // Console.WriteLine("Pinging db"); + // string pong = await db.Ping(); + // Console.WriteLine(pong); + + // // Check the response + // if (pong == "PONG") + // { + // Console.WriteLine("Redis server is running"); + // } + // else + // { + // Console.WriteLine("Unable to connect to Redis server"); + // } + + return "Task completed"; + // var client = new AmazonDynamoDBClient(); + + // var numRequests = 10; + // // var tasks = new Task[numRequests]; + // var tasks = new Dictionary, System.Diagnostics.Stopwatch>(); + + // string tableName = "TacoBellInvestigator"; + // string keyAttributeName = "key"; + // string keyAttributeBase = "test-key"; + + // for (int i = 1; i <= numRequests; i++) { + // Console.WriteLine("Getting inside the loop"); + // string keyAttributeValue = $"{keyAttributeBase}-{i}"; + // var request = new GetItemRequest + // { + // TableName = tableName, + // Key = new Dictionary + // { + // {keyAttributeName, new AttributeValue { S = keyAttributeValue}} + // } + // }; + + // Console.WriteLine("GetRequest created"); + // var startTime = System.Diagnostics.Stopwatch.StartNew(); + // Console.WriteLine("Starting the stopwatch"); + // var response = client.GetItemAsync(request); + // Console.WriteLine(response); - tasks[response] = startTime; - response.ContinueWith( - (r) => { - tasks[response].Stop(); - return r; - } - ); - Console.WriteLine("Stopped stopwatch"); - } + // tasks[response] = startTime; + // response.ContinueWith( + // (r) => { + // tasks[response].Stop(); + // return r; + // } + // ); + // Console.WriteLine("Stopped stopwatch"); + // } - Console.WriteLine("Awaiting pending tasks..."); - Task.WaitAll(tasks.Keys.ToArray()); - Console.WriteLine("Done awaiting tasks"); + // Console.WriteLine("Awaiting pending tasks..."); + // Task.WaitAll(tasks.Keys.ToArray()); + // Console.WriteLine("Done awaiting tasks"); - foreach(var entry in tasks) - { - Console.WriteLine(entry.Value.ElapsedMilliseconds); - } + // foreach(var entry in tasks) + // { + // Console.WriteLine(entry.Value.ElapsedMilliseconds); + // } } static void Main(string[] args) { try { + Console.WriteLine("Calling DoStuff"); new Function().DoStuff(); } catch(Exception ex) { Console.WriteLine("Caught Exception"); From 3dad2d3d54908720cb064ebe7dd443b266ac7fe0 Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Thu, 8 Jun 2023 11:00:04 -0700 Subject: [PATCH 05/16] feat: ping redis client --- .../DynamoLambdaExampleHandler1/Function.cs | 99 +++++-------------- 1 file changed, 25 insertions(+), 74 deletions(-) diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs index eb98069c..436358dd 100644 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs @@ -3,10 +3,10 @@ // using Amazon.DynamoDBv2.Model; using Amazon.Lambda.Core; // using Amazon.Runtime; -// using System; -// using System.Collections.Generic; -// using System.Threading.Tasks; -// using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using StackExchange.Redis; // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] @@ -24,81 +24,32 @@ public async Task FunctionHandler(ILambdaContext context) public async void DoStuff() { // Create a Redis connection - // Console.WriteLine("Creating redis client"); - // ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); - - // // Get a Redis database - // Console.WriteLine("Fetching db"); - // IDatabase db = redis.GetDatabase(); - - // // Ping the redis server - // Console.WriteLine("Pinging db"); - // string pong = await db.Ping(); - // Console.WriteLine(pong); - - // // Check the response - // if (pong == "PONG") - // { - // Console.WriteLine("Redis server is running"); - // } - // else - // { - // Console.WriteLine("Unable to connect to Redis server"); - // } - - return "Task completed"; - // var client = new AmazonDynamoDBClient(); - - // var numRequests = 10; - // // var tasks = new Task[numRequests]; - // var tasks = new Dictionary, System.Diagnostics.Stopwatch>(); - - // string tableName = "TacoBellInvestigator"; - // string keyAttributeName = "key"; - // string keyAttributeBase = "test-key"; - - // for (int i = 1; i <= numRequests; i++) { - // Console.WriteLine("Getting inside the loop"); - // string keyAttributeValue = $"{keyAttributeBase}-{i}"; - // var request = new GetItemRequest - // { - // TableName = tableName, - // Key = new Dictionary - // { - // {keyAttributeName, new AttributeValue { S = keyAttributeValue}} - // } - // }; - - // Console.WriteLine("GetRequest created"); - // var startTime = System.Diagnostics.Stopwatch.StartNew(); - // Console.WriteLine("Starting the stopwatch"); - // var response = client.GetItemAsync(request); - // Console.WriteLine(response); - - // tasks[response] = startTime; - // response.ContinueWith( - // (r) => { - // tasks[response].Stop(); - // return r; - // } - // ); - // Console.WriteLine("Stopped stopwatch"); - // } - - // Console.WriteLine("Awaiting pending tasks..."); - // Task.WaitAll(tasks.Keys.ToArray()); - // Console.WriteLine("Done awaiting tasks"); - - // foreach(var entry in tasks) - // { - // Console.WriteLine(entry.Value.ElapsedMilliseconds); - // } + Console.WriteLine("Creating redis client"); + ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); + + // Get a Redis database + Console.WriteLine("Fetching db"); + IDatabase db = redis.GetDatabase(); + + // Ping the redis server + Console.WriteLine("Pinging db"); + string pong = db.Ping(); + Console.WriteLine(pong); + + // Check the response + if (pong == "PONG") + { + Console.WriteLine("Redis server is running"); + } + else + { + Console.WriteLine("Unable to connect to Redis server"); + } } static void Main(string[] args) { try { - Console.WriteLine("Calling DoStuff"); new Function().DoStuff(); } catch(Exception ex) { Console.WriteLine("Caught Exception"); From e89c918236c6b8f63ad37b1527dabfa36e67502b Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Thu, 8 Jun 2023 16:11:52 -0700 Subject: [PATCH 06/16] fix: deploy lambda that connects to redis cluster --- .../DynamoLambdaExampleHandler1/Function.cs | 83 +++++++++++++++---- examples/DynamoLambdaExample/cdk.context.json | 40 +++++++++ .../DynamoLambdaExampleStack.cs | 21 ++++- .../src/DynamoLambdaExample/Program.cs | 9 +- 4 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 examples/DynamoLambdaExample/cdk.context.json diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs index 436358dd..78a30f59 100644 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs +++ b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs @@ -1,11 +1,4 @@ -// using Amazon; -// using Amazon.DynamoDBv2; -// using Amazon.DynamoDBv2.Model; using Amazon.Lambda.Core; -// using Amazon.Runtime; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using StackExchange.Redis; // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. @@ -17,15 +10,26 @@ public class Function { public async Task FunctionHandler(ILambdaContext context) { - DoStuff(); + await new Function().DoStuff(); return "Task completed"; } - public async void DoStuff() { + static byte[] GenerateLargeValue(int sizeInBytes) + { + byte[] value = new byte[sizeInBytes]; + new Random().NextBytes(value); + return value; + } + + public async Task DoStuff() { // Create a Redis connection Console.WriteLine("Creating redis client"); - ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); + var configurationOptions = new ConfigurationOptions + { + EndPoints = { "tacobellrediscluster.exmof5.ng.0001.usw2.cache.amazonaws.com:6379" } + }; + ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); // Get a Redis database Console.WriteLine("Fetching db"); @@ -33,23 +37,68 @@ public async void DoStuff() { // Ping the redis server Console.WriteLine("Pinging db"); - string pong = db.Ping(); + var pong = db.Ping(); Console.WriteLine(pong); - // Check the response - if (pong == "PONG") + // Set 20 string keys with string values + for (int i = 1; i <= 20; i++) { - Console.WriteLine("Redis server is running"); + string key = "key" + i; + // string value = "value" + i; + byte[] value = GenerateLargeValue(1 * 1024 * 1024); // 1MB + bool success = db.StringSet(key, value); + + if (success) + { + Console.WriteLine($"Key '{key}' set with a value of 1MB"); + + } + else + { + Console.WriteLine($"Failed to set key '{key}'"); + } } - else + + var tasks = new Dictionary, System.Diagnostics.Stopwatch>(); + + // Get values of 10 keys asynchronously + for (int i = 1; i <= 10; i++) { - Console.WriteLine("Unable to connect to Redis server"); + string key = "key" + i; + + Console.WriteLine("Starting the stopwatch"); + var startTime = System.Diagnostics.Stopwatch.StartNew(); + var response = db.StringGetAsync(key); + + tasks[response] = startTime; + response.ContinueWith( + (r) => { + tasks[response].Stop(); + return r; + } + ); + Console.WriteLine("Stopping stopwatch"); } + + Console.WriteLine("Awaiting pending tasks..."); + Task.WaitAll(tasks.Keys.ToArray()); + Console.WriteLine("Done awaiting tasks"); + + foreach(var entry in tasks) + { + Console.WriteLine(entry.Value.ElapsedMilliseconds); + } + + // Close the connection + redis.Close(); + + return "Task completed!"; } static void Main(string[] args) { try { + Console.WriteLine("Calling DoStuff"); new Function().DoStuff(); } catch(Exception ex) { Console.WriteLine("Caught Exception"); @@ -57,4 +106,4 @@ static void Main(string[] args) { } } -} +} \ No newline at end of file diff --git a/examples/DynamoLambdaExample/cdk.context.json b/examples/DynamoLambdaExample/cdk.context.json new file mode 100644 index 00000000..0b991cb9 --- /dev/null +++ b/examples/DynamoLambdaExample/cdk.context.json @@ -0,0 +1,40 @@ +{ + "vpc-provider:account=287427698164:filter.vpc-id=vpc-00e94e9613dde8d21:region=us-west-2:returnAsymmetricSubnets=true": { + "vpcId": "vpc-00e94e9613dde8d21", + "vpcCidrBlock": "172.31.0.0/16", + "ownerAccountId": "287427698164", + "availabilityZones": [], + "subnetGroups": [ + { + "name": "Public", + "type": "Public", + "subnets": [ + { + "subnetId": "subnet-04b581aed6af02515", + "cidr": "172.31.32.0/20", + "availabilityZone": "us-west-2a", + "routeTableId": "rtb-0a2470cafd0b7bd73" + }, + { + "subnetId": "subnet-09e0ce2f2c6b2faac", + "cidr": "172.31.16.0/20", + "availabilityZone": "us-west-2b", + "routeTableId": "rtb-0a2470cafd0b7bd73" + }, + { + "subnetId": "subnet-00482a2a73a2a56de", + "cidr": "172.31.0.0/20", + "availabilityZone": "us-west-2c", + "routeTableId": "rtb-0a2470cafd0b7bd73" + }, + { + "subnetId": "subnet-0c5efae5cc62020bc", + "cidr": "172.31.48.0/20", + "availabilityZone": "us-west-2d", + "routeTableId": "rtb-0a2470cafd0b7bd73" + } + ] + } + ] + } +} diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs index 35b49ee3..87f44444 100644 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs @@ -2,6 +2,7 @@ using Amazon.CDK.AWS.Lambda; using Constructs; using Amazon.CDK.AWS.IAM; +using Amazon.CDK.AWS.EC2; namespace DynamoLambdaExample { @@ -9,6 +10,14 @@ public class DynamoLambdaExampleStack : Stack { internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { + // Existing VPC configuration + var vpc = Vpc.FromLookup(this, "DefaultVpc", new VpcLookupOptions + { + VpcId = "vpc-00e94e9613dde8d21" + }); + + var existingSubnet = Subnet.FromSubnetId(this, "ExistingSubnet", "subnet-09e0ce2f2c6b2faac"); + // Create the IAM role for the Lambda function Role lambdaRole = new Role(this, "LambdaRole", new RoleProps { @@ -19,6 +28,8 @@ internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props // Attach the managed policies lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")); lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonDynamoDBFullAccess")); + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonEC2FullAccess")); + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonElastiCacheFullAccess")); lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AWSLambdaInvocation-DynamoDB")); Function fn = new Function(this, "DynamoLambdaExampleHandler", new FunctionProps @@ -29,7 +40,10 @@ internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props FunctionName = "PutItemHandler", MemorySize = 1024, Timeout = Duration.Seconds(300), - Role = lambdaRole + Role = lambdaRole, + Vpc = vpc, + VpcSubnets = new SubnetSelection { Subnets = new[] { existingSubnet } }, + AllowPublicSubnet = true }); Function fn1 = new Function(this, "DynamoLambdaExampleHandler1", new FunctionProps @@ -40,7 +54,10 @@ internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props FunctionName = "GetItemHandler", MemorySize = 1024, Timeout = Duration.Seconds(300), - Role = lambdaRole + Role = lambdaRole, + Vpc = vpc, + VpcSubnets = new SubnetSelection { Subnets = new[] { existingSubnet } }, + AllowPublicSubnet = true }); } } diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs index 9417b10d..1c44aaf4 100644 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs +++ b/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs @@ -10,7 +10,14 @@ sealed class Program public static void Main(string[] args) { var app = new App(); - new DynamoLambdaExampleStack(app, "DynamoLambdaExampleStack"); + new DynamoLambdaExampleStack(app, "DynamoLambdaExampleStack", new StackProps + { + Env = new Amazon.CDK.Environment + { + Account = "287427698164", + Region = "us-west-2" + } + }); app.Synth(); } From 02fbc13c2f851deb30779cd0340d08b26faa972f Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Mon, 12 Jun 2023 12:07:21 -0700 Subject: [PATCH 07/16] feat: wip -> compression/decompression for momento requests --- examples/MomentoRedisLambdaExample/.gitignore | 342 ++++++++++++++++++ .../Function.cs | 341 +++++++++++++++++ .../MomentoRedisExampleLambdaHandler.csproj | 20 + .../Readme.md | 49 +++ .../aws-lambda-tools-defaults.json | 16 + .../FunctionTest.cs | 20 + ...entoRedisExampleLambdaHandler.Tests.csproj | 17 + examples/MomentoRedisLambdaExample/README.md | 14 + .../cdk.context.json | 46 +++ examples/MomentoRedisLambdaExample/cdk.json | 52 +++ .../src/MomentoRedisLambdaExample.sln | 34 ++ .../GlobalSuppressions.cs | 1 + .../MomentoRedisLambdaExample.csproj | 20 + .../MomentoRedisLambdaExampleStack.cs | 79 ++++ .../src/MomentoRedisLambdaExample/Program.cs | 24 ++ 15 files changed, 1075 insertions(+) create mode 100644 examples/MomentoRedisLambdaExample/.gitignore create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj create mode 100644 examples/MomentoRedisLambdaExample/README.md create mode 100644 examples/MomentoRedisLambdaExample/cdk.context.json create mode 100644 examples/MomentoRedisLambdaExample/cdk.json create mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln create mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs create mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj create mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs create mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs diff --git a/examples/MomentoRedisLambdaExample/.gitignore b/examples/MomentoRedisLambdaExample/.gitignore new file mode 100644 index 00000000..a4609e75 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/.gitignore @@ -0,0 +1,342 @@ +# CDK asset staging directory +.cdk.staging +cdk.out + +# Created by https://www.gitignore.io/api/csharp + +### Csharp ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + + +# End of https://www.gitignore.io/api/csharp \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs new file mode 100644 index 00000000..0089de2e --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs @@ -0,0 +1,341 @@ +using Amazon.Lambda.Core; +using StackExchange.Redis; +using Momento.Sdk; +using Momento.Sdk.Auth; +using Momento.Sdk.Config; +using Momento.Sdk.Responses; +using System; +using System.IO; +using System.IO.Compression; +using Momento.Sdk.Responses; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace MomentoRedisExampleLambdaHandler; + +public class Function +{ + const string CACHE_NAME = "MomentoLambda"; + const string REDIS_CLUSTER_ENDPOINT = "momentoredisexamplecluster.exmof5.ng.0001.usw2.cache.amazonaws.com:6379"; + public string bigString = new string('x', 1024*1024/2); + + public bool COMPRESS_VALUES = true; + public int numMomentoGetRequests = 10; + public int numMomentoSetRequests = 10; + public int numRedisGetRequests = 10; + public int numRedisSetRequests = 10; + // public Dictionary, System.Diagnostics.Stopwatch> momentoSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + // public Dictionary, System.Diagnostics.Stopwatch> momentoGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + public Dictionary, System.Diagnostics.Stopwatch> redisSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + public Dictionary, System.Diagnostics.Stopwatch> redisGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + + public async Task FunctionHandler(ILambdaContext context) + { + await new Function().DoStuff(); + return "Task completed"; + } + + public async Task DoStuff() { + + Console.WriteLine("Start executing DoStuff"); + // var lambdaStartTime = System.Diagnostics.Stopwatch.StartNew(); + + // Create Momento client + ICredentialProvider authProvider = new EnvMomentoTokenProvider("MOMENTO_AUTH_TOKEN"); + var momentoClient = new CacheClient( + Configurations.InRegion.Lambda.Latest().WithClientTimeout(TimeSpan.FromSeconds(3000)), + authProvider, + TimeSpan.FromSeconds(30) + ); + + // Create cache if not already exists + createMomentoCache(momentoClient); + + // Create a Redis connection + // Console.WriteLine("Creating redis client"); + // var configurationOptions = new ConfigurationOptions + // { + // EndPoints = { REDIS_CLUSTER_ENDPOINT } + // }; + // ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + + // Get a Redis database + // Console.WriteLine("Fetching db"); + // IDatabase db = redis.GetDatabase(); + + // var startKeyId = 1; + + // while (lambdaStartTime.Elapsed.TotalMinutes < 4) { + // Fire momento and redis requests + var momentoSetTasks = await DoMomentoSets(momentoClient); + Console.WriteLine("momentoSetTasks.Count " + momentoSetTasks.Count); + var momentoGetTasks = DoMomentoGets(momentoClient); + Console.WriteLine("momentoGetTasks.Count " + momentoGetTasks.Count); + // DoRedisSets(db, startKeyId); + // DoRedisGets(db, startKeyId); + + Console.WriteLine("Awaiting pending tasks..."); + Task.WaitAll(momentoSetTasks.Keys.ToArray()); + Task.WaitAll(momentoGetTasks.Keys.ToArray()); + // Task.WaitAll(redisSetTasks.Keys.ToArray()); + // Task.WaitAll(redisGetTasks.Keys.ToArray()); + Console.WriteLine("Done awaiting tasks"); + + // print momento set tasks + Console.WriteLine("------- MOMENTO SET RESULT -------"); + foreach(var entry in momentoSetTasks) { + var key = await entry.Key; + if (key is CacheSetResponse.Error err) { + Console.WriteLine("ERROR: " + err.Message); + } else if (key is CacheSetResponse.Success hit) { + Console.WriteLine("Set in " + entry.Value.ElapsedMilliseconds); + } + } + + // print momento get tasks + Console.WriteLine("------- MOMENTO GET RESULT -------"); + foreach(var entry in momentoGetTasks) + { + var key = await entry.Key; + if (key is CacheGetResponse.Miss) { + Console.WriteLine("Unexpected MISS in " + entry.Value.ElapsedMilliseconds); + } else if (key is CacheGetResponse.Error err) { + Console.WriteLine("ERROR: " + err.Message); + } else if (key is CacheGetResponse.Hit hit) { + Console.WriteLine("Got " + hit.ValueString.Length + " in " + entry.Value.ElapsedMilliseconds); + } + } + + // print redis set tasks + // Console.WriteLine("------- REDIS SET RESULT -------"); + // foreach(var entry in redisSetTasks) + // { + // Console.WriteLine(entry.Value.ElapsedMilliseconds); + // } + + // print redis get tasks + // Console.WriteLine("------- REDIS GET RESULT -------"); + // foreach(var entry in redisGetTasks) + // { + // Console.WriteLine(entry.Value.ElapsedMilliseconds); + // } + + // startKeyId = startKeyId + numRedisSetRequests; + // } + + // Close the connection + // redis.Close(); + + Console.WriteLine("End executing DoStuff"); + + return "Task completed!"; + } + + private async Task createMomentoCache(CacheClient client) { + var response = await client.CreateCacheAsync(CACHE_NAME); + } + + private async Task, System.Diagnostics.Stopwatch>> DoMomentoSets(CacheClient client) { + try { + + Dictionary, System.Diagnostics.Stopwatch> momentoSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + + Console.WriteLine("Executing MomentoSets"); + string compressedString = Compress(); + + for (int i = 1; i <= numMomentoSetRequests; i++) { + Console.WriteLine("Setting inside the loop"); + string key = $"key-{i}"; + + Console.WriteLine("Starting the stopwatch"); + var stopWatch = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine("Setting key " + key); + Task response = client.SetAsync(CACHE_NAME, key, compressedString, TimeSpan.FromSeconds(600)); + // momentoSetTasks[response] = startTime; + var continued = await response.ContinueWith( + (r) => { + try { + stopWatch.Stop(); + Console.WriteLine("Stopped stopwatch"); + return r; + } catch(Exception e) { + Console.WriteLine("Exception in set continuedWith " + e); + throw e; + } + + } + ); + momentoSetTasks[continued] = stopWatch; + } + return momentoSetTasks; + } catch (Exception e) { + Console.WriteLine("Exception in set " + e); + throw e; + } + + } + + private Dictionary, System.Diagnostics.Stopwatch> DoMomentoGets(CacheClient client) { + Dictionary, System.Diagnostics.Stopwatch> momentoGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + + for (int i = 1; i <= numMomentoGetRequests; i++) { + Console.WriteLine("Getting inside the loop"); + string key = $"key-{i}"; + + Console.WriteLine("Starting the stopwatch"); + var stopWatch = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine("Getting key " + key); + Task response = client.GetAsync(CACHE_NAME, key); + + // momentoGetTasks[response] = startTime; + response.ContinueWith( + async (r) => { + try { + Console.WriteLine("In ContinueWith"); + var result = await r; + stopWatch.Stop(); + momentoGetTasks[r] = stopWatch; + + var hitResult = (CacheGetResponse.Hit)result; + Console.WriteLine("hitResult " + hitResult.GetType() + hitResult); + string hitValue = hitResult.ValueString; + + string decompressedString = await DecompressAsync(hitValue); + Console.WriteLine("decompressedString " + decompressedString); + // await LogDecompressedStringAsync(decompressedString); + return r; + } catch(Exception e) { + Console.WriteLine(e.Message); + throw e; + } + + } + ); + Console.WriteLine("Stopped stopwatch"); + } + return momentoGetTasks; + } + + // private async Task LogDecompressedStringAsync(string decompressedString) + // { + // Console.WriteLine("Decompressed string: " + decompressedString); + // } + + private string Compress() { + string compressedString; + // Convert the string to bytes + byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(bigString); + + // Create a memory stream to hold the compressed data + using (MemoryStream outputMemoryStream = new MemoryStream()) + { + // Create a GZip stream and specify CompressionMode.Compress + using (GZipStream compressionStream = new GZipStream(outputMemoryStream, CompressionMode.Compress)) + { + // Compress the input string bytes + compressionStream.Write(inputBytes, 0, inputBytes.Length); + } + + // Get the compressed bytes from the memory stream + byte[] compressedBytes = outputMemoryStream.ToArray(); + + // Convert the compressed bytes to a Base64 string + compressedString = Convert.ToBase64String(compressedBytes); + } + + return compressedString; + } + + private async Task DecompressAsync(string valueString) +{ + byte[] compressedBytes = Convert.FromBase64String(valueString); + + using (MemoryStream compressedStream = new MemoryStream(compressedBytes)) + { + using (MemoryStream decompressedStream = new MemoryStream()) + { + using (GZipStream gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress)) + { + await gzipStream.CopyToAsync(decompressedStream); + } + + byte[] decompressedBytes = decompressedStream.ToArray(); + string decompressedString = System.Text.Encoding.UTF8.GetString(decompressedBytes); + + Console.WriteLine(decompressedString); + return decompressedString; + } + } +} + + + private void DoRedisSets(IDatabase db, int startKeyId) { + // Set string keys with string values + for (int i = startKeyId; i <= numRedisSetRequests; i++) + { + string key = "key" + i; + byte[] value = GenerateLargeValue(1 * 1024 * 1024); // 1MB + Console.WriteLine("Starting the stopwatch"); + var startTime = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine("Setting key " + key); + Task response = db.StringSetAsync(key, value); + redisSetTasks[response] = startTime; + + response.ContinueWith( + (r) => { + redisSetTasks[response].Stop(); + return r; + } + ); + Console.WriteLine("Stopped stopwatch"); + } + } + + private void DoRedisGets(IDatabase db, int startKeyId) { + // Get values of keys asynchronously + for (int i = startKeyId; i <= 10; i++) + { + string key = "key" + i; + + Console.WriteLine("Starting the stopwatch"); + var startTime = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine("Getting key " + key); + var response = db.StringGetAsync(key); + + redisGetTasks[response] = startTime; + response.ContinueWith( + (r) => { + redisGetTasks[response].Stop(); + return r; + } + ); + Console.WriteLine("Stopping stopwatch"); + } + } + + private void pingRedis(IDatabase db) { + // Chceck/Ping the redis server + Console.WriteLine("Pinging db"); + var pong = db.Ping(); + Console.WriteLine(pong); + } + + private static byte[] GenerateLargeValue(int sizeInBytes) + { + byte[] value = new byte[sizeInBytes]; + new Random().NextBytes(value); + return value; + } + + static void Main(string[] args) { + try { + Console.WriteLine("Calling DoStuff"); + new Function().DoStuff(); + } catch(Exception ex) { + Console.WriteLine("Caught Exception"); + Console.WriteLine(ex); + } + } + +} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj new file mode 100644 index 00000000..629dcce1 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj @@ -0,0 +1,20 @@ + + + net6.0 + Exe + enable + enable + true + Lambda + + true + + true + + + + + + + + \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md new file mode 100644 index 00000000..4ed9e5a8 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md @@ -0,0 +1,49 @@ +# AWS Lambda Empty Function Project + +This starter project consists of: +* Function.cs - class file containing a class with a single function handler method +* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS + +You may also have a test project depending on the options selected. + +The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. + +## Here are some steps to follow from Visual Studio: + +To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. + +To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. + +To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. + +To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. + +To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. + +To view execution logs of invocations of your function use the Logs tab in the opened Function View window. + +## Here are some steps to follow to get started from the command line: + +Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. + +Install Amazon.Lambda.Tools Global Tools if not already installed. +``` + dotnet tool install -g Amazon.Lambda.Tools +``` + +If already installed check if new version is available. +``` + dotnet tool update -g Amazon.Lambda.Tools +``` + +Execute unit tests +``` + cd "MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests" + dotnet test +``` + +Deploy function to AWS Lambda +``` + cd "MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler" + dotnet lambda deploy-function +``` diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json new file mode 100644 index 00000000..df66d700 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json @@ -0,0 +1,16 @@ +{ + "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-architecture": "x86_64", + "function-runtime": "dotnet6", + "function-memory-size": 256, + "function-timeout": 30, + "function-handler": "MomentoRedisExampleLambdaHandler::MomentoRedisExampleLambdaHandler.Function::FunctionHandler" +} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs new file mode 100644 index 00000000..3d32e68b --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs @@ -0,0 +1,20 @@ +using Xunit; +using Amazon.Lambda.Core; +using Amazon.Lambda.TestUtilities; + +namespace MomentoRedisExampleLambdaHandler.Tests; + +public class FunctionTest +{ + [Fact] + public void TestToUpperFunction() + { + + // Invoke the lambda function and confirm the string was upper cased. + var function = new Function(); + var context = new TestLambdaContext(); + var upperCase = function.FunctionHandler("hello world", context); + + Assert.Equal("HELLO WORLD", upperCase); + } +} diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj new file mode 100644 index 00000000..f53e8d6e --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj @@ -0,0 +1,17 @@ + + + net6.0 + enable + enable + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/README.md b/examples/MomentoRedisLambdaExample/README.md new file mode 100644 index 00000000..f28e4d55 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/README.md @@ -0,0 +1,14 @@ +# Welcome to your CDK C# project! + +This is a blank project for CDK development with C#. + +The `cdk.json` file tells the CDK Toolkit how to execute your app. + +It uses the [.NET CLI](https://docs.microsoft.com/dotnet/articles/core/) to compile and execute your project. + +## Useful commands + +* `dotnet build src` compile this app +* `cdk deploy` deploy this stack to your default AWS account/region +* `cdk diff` compare deployed stack with current state +* `cdk synth` emits the synthesized CloudFormation template \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/cdk.context.json b/examples/MomentoRedisLambdaExample/cdk.context.json new file mode 100644 index 00000000..07322898 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/cdk.context.json @@ -0,0 +1,46 @@ +{ + "vpc-provider:account=287427698164:filter.vpc-id=vpc-00e94e9613dde8d21:region=us-west-2:returnAsymmetricSubnets=true": { + "vpcId": "vpc-00e94e9613dde8d21", + "vpcCidrBlock": "172.31.0.0/16", + "ownerAccountId": "287427698164", + "availabilityZones": [], + "subnetGroups": [ + { + "name": "Public", + "type": "Public", + "subnets": [ + { + "subnetId": "subnet-04b581aed6af02515", + "cidr": "172.31.32.0/20", + "availabilityZone": "us-west-2a", + "routeTableId": "rtb-0a2470cafd0b7bd73" + }, + { + "subnetId": "subnet-09e0ce2f2c6b2faac", + "cidr": "172.31.16.0/20", + "availabilityZone": "us-west-2b", + "routeTableId": "rtb-0a2470cafd0b7bd73" + }, + { + "subnetId": "subnet-00482a2a73a2a56de", + "cidr": "172.31.0.0/20", + "availabilityZone": "us-west-2c", + "routeTableId": "rtb-0a2470cafd0b7bd73" + }, + { + "subnetId": "subnet-0c5efae5cc62020bc", + "cidr": "172.31.48.0/20", + "availabilityZone": "us-west-2d", + "routeTableId": "rtb-0a2470cafd0b7bd73" + } + ] + } + ] + }, + "availability-zones:account=287427698164:region=us-west-2": [ + "us-west-2a", + "us-west-2b", + "us-west-2c", + "us-west-2d" + ] +} diff --git a/examples/MomentoRedisLambdaExample/cdk.json b/examples/MomentoRedisLambdaExample/cdk.json new file mode 100644 index 00000000..27f865c3 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/cdk.json @@ -0,0 +1,52 @@ +{ + "app": "dotnet run --project src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "src/*/obj", + "src/*/bin", + "src/*.sln", + "src/*/GlobalSuppressions.cs", + "src/*/*.csproj" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true + } +} diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln new file mode 100644 index 00000000..ca600f61 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MomentoRedisLambdaExample", "MomentoRedisLambdaExample\MomentoRedisLambdaExample.csproj", "{156AEF6B-F9DA-42DB-806A-CDC179673456}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|Any CPU.Build.0 = Debug|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x64.ActiveCfg = Debug|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x64.Build.0 = Debug|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x86.ActiveCfg = Debug|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x86.Build.0 = Debug|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|Any CPU.ActiveCfg = Release|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|Any CPU.Build.0 = Release|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x64.ActiveCfg = Release|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x64.Build.0 = Release|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x86.ActiveCfg = Release|Any CPU + {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs new file mode 100644 index 00000000..26233fcb --- /dev/null +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs @@ -0,0 +1 @@ +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "Constructs add themselves to the scope in which they are created")] diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj new file mode 100644 index 00000000..dad278f5 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj @@ -0,0 +1,20 @@ + + + + Exe + net6.0 + + Major + + + + + + + + + + + diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs new file mode 100644 index 00000000..5e602887 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs @@ -0,0 +1,79 @@ +using Amazon.CDK; +using Amazon.CDK.AWS.Lambda; +using Constructs; +using Amazon.CDK.AWS.IAM; +using Amazon.CDK.AWS.EC2; +using Amazon.CDK.AWS.Events; +using Amazon.CDK.AWS.Events.Targets; + +namespace MomentoRedisLambdaExample +{ + public class MomentoRedisLambdaExampleStack : Stack + { + internal MomentoRedisLambdaExampleStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) + { + var vpc = new Vpc(this, "VPC", new VpcProps + { + SubnetConfiguration = new ISubnetConfiguration[] { + new SubnetConfiguration{ + Name = "public-subnet", + SubnetType = SubnetType.PUBLIC, + CidrMask = 24, + }, + new SubnetConfiguration{ + Name = "private-subnet", + SubnetType = SubnetType.PRIVATE_WITH_EGRESS, + CidrMask = 24, + }, + } + // maxAzs: 2, + // natGateways: 2, + }); + + var privateSubnet = Subnet.FromSubnetId(this, "PrivateSubnet", "subnet-07fff86b0e418963c"); // Specify the desired private subnet ID + + // Create the IAM role for the Lambda function + Role lambdaRole = new Role(this, "LambdaRole", new RoleProps + { + AssumedBy = new ServicePrincipal("lambda.amazonaws.com"), + RoleName = "MomentoRedisExampleLambdaRole" + }); + + // Attach the managed policies + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")); + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonEC2FullAccess")); + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonElastiCacheFullAccess")); + + var MOMENTO_AUTH_TOKEN = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJyaXNodGlAbW9tZW50b2hxLmNvbSIsImNwIjoiY29udHJvbC5jZWxsLTQtdXMtd2VzdC0yLTEucHJvZC5hLm1vbWVudG9ocS5jb20iLCJjIjoiY2FjaGUuY2VsbC00LXVzLXdlc3QtMi0xLnByb2QuYS5tb21lbnRvaHEuY29tIn0.eGgz9D7-R_6T9TVL-zsE8rnNf6TaVG6qKh7G0PmuaOBkWDC61hVOvZPwvu-n43Ld5NV5-sfTFQwY5BL0iL9Dpw"; + + Function fn1 = new Function(this, "MomentoRedisLambdaExampleHandler", new FunctionProps + { + Runtime = Runtime.DOTNET_6, + Code = Code.FromAsset("./MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/bin/Release/net6.0/publish"), + Handler = "MomentoRedisExampleLambdaHandler::MomentoRedisExampleLambdaHandler.Function::FunctionHandler", + FunctionName = "MomentoRedisLambdaExampleHandler", + MemorySize = 1024, + Timeout = Duration.Seconds(300), + Role = lambdaRole, + Vpc = vpc, + VpcSubnets = new SubnetSelection { Subnets = new[] { privateSubnet } }, + Environment = new System.Collections.Generic.Dictionary + { + { "MOMENTO_AUTH_TOKEN", MOMENTO_AUTH_TOKEN} + } + }); + + // Create an event rule with a schedule expression for every 5 minutes + // var rule = new Rule(this, "MomentoRedisExampleLambdaTriggerRule", new RuleProps + // { + // Schedule = Schedule.Cron(new CronOptions + // { + // Minute = "*/5" // Run every 5 minutes + // }) + // }); + + // Add the Lambda function as a target for the event rule + // rule.AddTarget(new LambdaFunction(fn1)); + } + } +} diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs new file mode 100644 index 00000000..50370fa1 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs @@ -0,0 +1,24 @@ +using Amazon.CDK; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MomentoRedisLambdaExample +{ + sealed class Program + { + public static void Main(string[] args) + { + var app = new App(); + new MomentoRedisLambdaExampleStack(app, "MomentoRedisLambdaExampleStack", new StackProps + { + Env = new Amazon.CDK.Environment + { + Account = "287427698164", + Region = "us-west-2" + } + }); + app.Synth(); + } + } +} From fac57d1c60b45a0c46b1287de1af53ecc78ccb9a Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Mon, 12 Jun 2023 13:33:53 -0700 Subject: [PATCH 08/16] feat: wip -> using (response, stopwatch) tuples for set/get requests --- .../Function.cs | 105 +++++++++--------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs index 0089de2e..5d733fd5 100644 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs @@ -7,7 +7,6 @@ using System; using System.IO; using System.IO.Compression; -using Momento.Sdk.Responses; // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] @@ -50,7 +49,7 @@ public async Task DoStuff() { ); // Create cache if not already exists - createMomentoCache(momentoClient); + await createMomentoCache(momentoClient); // Create a Redis connection // Console.WriteLine("Creating redis client"); @@ -69,9 +68,7 @@ public async Task DoStuff() { // while (lambdaStartTime.Elapsed.TotalMinutes < 4) { // Fire momento and redis requests var momentoSetTasks = await DoMomentoSets(momentoClient); - Console.WriteLine("momentoSetTasks.Count " + momentoSetTasks.Count); - var momentoGetTasks = DoMomentoGets(momentoClient); - Console.WriteLine("momentoGetTasks.Count " + momentoGetTasks.Count); + var momentoGetTasks = await DoMomentoGets(momentoClient); // DoRedisSets(db, startKeyId); // DoRedisGets(db, startKeyId); @@ -86,10 +83,10 @@ public async Task DoStuff() { Console.WriteLine("------- MOMENTO SET RESULT -------"); foreach(var entry in momentoSetTasks) { var key = await entry.Key; - if (key is CacheSetResponse.Error err) { + if (key.Item1 is CacheSetResponse.Error err) { Console.WriteLine("ERROR: " + err.Message); - } else if (key is CacheSetResponse.Success hit) { - Console.WriteLine("Set in " + entry.Value.ElapsedMilliseconds); + } else if (key.Item1 is CacheSetResponse.Success hit) { + Console.WriteLine("Set in " + key.Item2.ElapsedMilliseconds); } } @@ -98,12 +95,12 @@ public async Task DoStuff() { foreach(var entry in momentoGetTasks) { var key = await entry.Key; - if (key is CacheGetResponse.Miss) { - Console.WriteLine("Unexpected MISS in " + entry.Value.ElapsedMilliseconds); - } else if (key is CacheGetResponse.Error err) { + if (key.Item1 is CacheGetResponse.Miss) { + Console.WriteLine("Unexpected MISS in " + key.Item2.ElapsedMilliseconds); + } else if (key.Item1 is CacheGetResponse.Error err) { Console.WriteLine("ERROR: " + err.Message); - } else if (key is CacheGetResponse.Hit hit) { - Console.WriteLine("Got " + hit.ValueString.Length + " in " + entry.Value.ElapsedMilliseconds); + } else if (key.Item1 is CacheGetResponse.Hit hit) { + Console.WriteLine("Got " + hit.ValueString.Length + " in " + key.Item2.ElapsedMilliseconds); } } @@ -136,10 +133,10 @@ private async Task createMomentoCache(CacheClient client) { var response = await client.CreateCacheAsync(CACHE_NAME); } - private async Task, System.Diagnostics.Stopwatch>> DoMomentoSets(CacheClient client) { + private async Task, System.Diagnostics.Stopwatch>> DoMomentoSets(CacheClient client) { try { - Dictionary, System.Diagnostics.Stopwatch> momentoSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + Dictionary, System.Diagnostics.Stopwatch> momentoSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); Console.WriteLine("Executing MomentoSets"); string compressedString = Compress(); @@ -148,79 +145,78 @@ private async Task createMomentoCache(CacheClient client) { Console.WriteLine("Setting inside the loop"); string key = $"key-{i}"; - Console.WriteLine("Starting the stopwatch"); - var stopWatch = System.Diagnostics.Stopwatch.StartNew(); Console.WriteLine("Setting key " + key); - Task response = client.SetAsync(CACHE_NAME, key, compressedString, TimeSpan.FromSeconds(600)); - // momentoSetTasks[response] = startTime; - var continued = await response.ContinueWith( + var responseWithStopwatch = SetAsyncWithStopwatch(client, CACHE_NAME, key, compressedString, TimeSpan.FromSeconds(600)); + + // Task response = client.SetAsync(CACHE_NAME, key, compressedString, TimeSpan.FromSeconds(600)); + var continued = await responseWithStopwatch.ContinueWith( (r) => { - try { - stopWatch.Stop(); - Console.WriteLine("Stopped stopwatch"); - return r; - } catch(Exception e) { - Console.WriteLine("Exception in set continuedWith " + e); - throw e; - } - + var (response, stopwatch) = r.Result; + stopwatch.Stop(); + Console.WriteLine("Stopwatch stopped for key " + key); + return r; } ); - momentoSetTasks[continued] = stopWatch; + momentoSetTasks[continued] = continued.Result.Item2; } return momentoSetTasks; } catch (Exception e) { Console.WriteLine("Exception in set " + e); - throw e; + throw new Exception(); } - } - private Dictionary, System.Diagnostics.Stopwatch> DoMomentoGets(CacheClient client) { - Dictionary, System.Diagnostics.Stopwatch> momentoGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); + private async Task<(CacheSetResponse, System.Diagnostics.Stopwatch)> SetAsyncWithStopwatch(CacheClient client, string cacheName, string key, string value, TimeSpan expirationTime) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + var response = await client.SetAsync(cacheName, key, value, expirationTime); + return (response, stopwatch); + } + + private async Task, System.Diagnostics.Stopwatch>> DoMomentoGets(CacheClient client) { + Dictionary, System.Diagnostics.Stopwatch> momentoGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); for (int i = 1; i <= numMomentoGetRequests; i++) { Console.WriteLine("Getting inside the loop"); string key = $"key-{i}"; - Console.WriteLine("Starting the stopwatch"); - var stopWatch = System.Diagnostics.Stopwatch.StartNew(); Console.WriteLine("Getting key " + key); - Task response = client.GetAsync(CACHE_NAME, key); + var responseWithStopwatch = GetAsyncWithStopwatch(client, CACHE_NAME, key); // momentoGetTasks[response] = startTime; - response.ContinueWith( + var continuedTask = responseWithStopwatch.ContinueWith( async (r) => { try { Console.WriteLine("In ContinueWith"); - var result = await r; - stopWatch.Stop(); - momentoGetTasks[r] = stopWatch; + var (response, stopwatch) = r.Result; + stopwatch.Stop(); + Console.WriteLine("Stopwatch stopped for key " + key); + momentoGetTasks[r] = stopwatch; - var hitResult = (CacheGetResponse.Hit)result; - Console.WriteLine("hitResult " + hitResult.GetType() + hitResult); + var hitResult = (CacheGetResponse.Hit)response; string hitValue = hitResult.ValueString; + // Decompressing compressed strings string decompressedString = await DecompressAsync(hitValue); - Console.WriteLine("decompressedString " + decompressedString); - // await LogDecompressedStringAsync(decompressedString); return r; } catch(Exception e) { Console.WriteLine(e.Message); - throw e; + throw new Exception(); } - } ); - Console.WriteLine("Stopped stopwatch"); + + await continuedTask; } return momentoGetTasks; } - // private async Task LogDecompressedStringAsync(string decompressedString) - // { - // Console.WriteLine("Decompressed string: " + decompressedString); - // } + private async Task<(CacheGetResponse, System.Diagnostics.Stopwatch)> GetAsyncWithStopwatch(CacheClient client, string cacheName, string key) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + var response = await client.GetAsync(cacheName, key); + return (response, stopwatch); + } private string Compress() { string compressedString; @@ -263,7 +259,6 @@ private async Task DecompressAsync(string valueString) byte[] decompressedBytes = decompressedStream.ToArray(); string decompressedString = System.Text.Encoding.UTF8.GetString(decompressedBytes); - Console.WriteLine(decompressedString); return decompressedString; } } @@ -331,7 +326,9 @@ private static byte[] GenerateLargeValue(int sizeInBytes) static void Main(string[] args) { try { Console.WriteLine("Calling DoStuff"); - new Function().DoStuff(); + var task = new Function().DoStuff(); + Console.WriteLine("Waiting for task via task.Result"); + Console.WriteLine($"RESULT: {task.Result}"); } catch(Exception ex) { Console.WriteLine("Caught Exception"); Console.WriteLine(ex); From fee245cda2680d8175e6cdf9189389898756897a Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Tue, 13 Jun 2023 13:42:10 -0700 Subject: [PATCH 09/16] feat: remove dynamo lambda example, add momento/redis lambda example --- .gitignore | 1 + examples/.gitignore | 3 +- examples/DynamoLambdaExample/.gitignore | 342 ------------ .../DynamoLambdaExampleHandler.csproj | 19 - .../DynamoLambdaExampleHandler/Function.cs | 52 -- .../src/DynamoLambdaExampleHandler/Readme.md | 49 -- .../aws-lambda-tools-defaults.json | 16 - .../DynamoLambdaExampleHandler.Tests.csproj | 17 - .../FunctionTest.cs | 20 - .../DynamoLambdaExampleHandler1.csproj | 20 - .../DynamoLambdaExampleHandler1/Function.cs | 109 ---- .../src/DynamoLambdaExampleHandler1/Readme.md | 49 -- .../aws-lambda-tools-defaults.json | 16 - .../DynamoLambdaExampleHandler1.Tests.csproj | 17 - .../FunctionTest.cs | 20 - examples/DynamoLambdaExample/README.md | 14 - examples/DynamoLambdaExample/cdk.context.json | 40 -- examples/DynamoLambdaExample/cdk.json | 52 -- .../src/DynamoLambdaExample.sln | 34 -- .../DynamoLambdaExample.csproj | 20 - .../DynamoLambdaExampleStack.cs | 64 --- .../DynamoLambdaExample/GlobalSuppressions.cs | 1 - .../src/DynamoLambdaExample/Program.cs | 25 - .../Compression.cs | 29 + .../Function.cs | 510 ++++++++---------- .../MomentoCache.cs | 188 +++++++ .../MomentoRedisExampleLambdaHandler.csproj | 1 + .../RedisCache.cs | 143 +++++ .../MomentoRedisExampleLambdaHandler/Utils.cs | 42 ++ .../MomentoRedisLambdaExampleStack.cs | 16 +- 30 files changed, 645 insertions(+), 1284 deletions(-) delete mode 100644 examples/DynamoLambdaExample/.gitignore delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj delete mode 100644 examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs delete mode 100644 examples/DynamoLambdaExample/README.md delete mode 100644 examples/DynamoLambdaExample/cdk.context.json delete mode 100644 examples/DynamoLambdaExample/cdk.json delete mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample.sln delete mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj delete mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs delete mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs delete mode 100644 examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs create mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs diff --git a/.gitignore b/.gitignore index 1172d3ac..eef872d5 100644 --- a/.gitignore +++ b/.gitignore @@ -406,3 +406,4 @@ ASALocalRun/ # VS Code .vscode +/exportToHTML/ diff --git a/examples/.gitignore b/examples/.gitignore index 92275dbc..2ce902f6 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -402,4 +402,5 @@ ASALocalRun/ .mfractor/ # Local History for Visual Studio -.localhistory/ \ No newline at end of file +.localhistory/ +/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/super-secret-source-data.json diff --git a/examples/DynamoLambdaExample/.gitignore b/examples/DynamoLambdaExample/.gitignore deleted file mode 100644 index a4609e75..00000000 --- a/examples/DynamoLambdaExample/.gitignore +++ /dev/null @@ -1,342 +0,0 @@ -# CDK asset staging directory -.cdk.staging -cdk.out - -# Created by https://www.gitignore.io/api/csharp - -### Csharp ### -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - - -# End of https://www.gitignore.io/api/csharp \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj deleted file mode 100644 index 66ae5758..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/DynamoLambdaExampleHandler.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - net6.0 - enable - enable - true - Lambda - - true - - true - - - - - - - - \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs deleted file mode 100644 index 63fc4860..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Function.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Amazon; -using Amazon.DynamoDBv2; -using Amazon.DynamoDBv2.Model; -using Amazon.Lambda.Core; -using Amazon.Runtime; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] - -namespace DynamoLambdaExampleHandler -{ - public class Function - { - public async Task FunctionHandler(ILambdaContext context) - { - var client = new AmazonDynamoDBClient(); - - // Set up the item details - string tableName = "TacoBellInvestigator"; - string keyAttributeName = "key"; - string valueAttributeName = "value"; - - string keyAttributeBase = "test-key"; - string valueAttributeBase = "test-value"; - - for (int i = 1; i <= 20; i++) - { - string keyAttributeValue = $"{keyAttributeBase}-{i}"; - string valueAttributeValue = $"{valueAttributeBase}-{i}"; - - // Create the item request - var request = new PutItemRequest - { - TableName = tableName, - Item = new Dictionary - { - { keyAttributeName, new AttributeValue { S = keyAttributeValue } }, - { valueAttributeName, new AttributeValue { S = valueAttributeValue } }, - } - }; - - // Put the item in the table - await client.PutItemAsync(request); - } - - client.Dispose(); - return "Item created successfully"; - } - } -} diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md deleted file mode 100644 index b74f212b..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/Readme.md +++ /dev/null @@ -1,49 +0,0 @@ -# AWS Lambda Empty Function Project - -This starter project consists of: -* Function.cs - class file containing a class with a single function handler method -* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS - -You may also have a test project depending on the options selected. - -The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. - -## Here are some steps to follow from Visual Studio: - -To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. - -To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. - -To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. - -To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. - -To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. - -To view execution logs of invocations of your function use the Logs tab in the opened Function View window. - -## Here are some steps to follow to get started from the command line: - -Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. - -Install Amazon.Lambda.Tools Global Tools if not already installed. -``` - dotnet tool install -g Amazon.Lambda.Tools -``` - -If already installed check if new version is available. -``` - dotnet tool update -g Amazon.Lambda.Tools -``` - -Execute unit tests -``` - cd "DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests" - dotnet test -``` - -Deploy function to AWS Lambda -``` - cd "DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler" - dotnet lambda deploy-function -``` diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json deleted file mode 100644 index 10049ef6..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,16 +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-architecture": "x86_64", - "function-runtime": "dotnet6", - "function-memory-size": 256, - "function-timeout": 30, - "function-handler": "DynamoLambdaExampleHandler::DynamoLambdaExampleHandler.Function::FunctionHandler" -} \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj deleted file mode 100644 index 4c27001e..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/DynamoLambdaExampleHandler.Tests.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - net6.0 - enable - enable - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs deleted file mode 100644 index 1c6fe2eb..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler/test/DynamoLambdaExampleHandler.Tests/FunctionTest.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Xunit; -using Amazon.Lambda.Core; -using Amazon.Lambda.TestUtilities; - -namespace DynamoLambdaExampleHandler.Tests; - -public class FunctionTest -{ - [Fact] - public void TestToUpperFunction() - { - - // Invoke the lambda function and confirm the string was upper cased. - var function = new Function(); - var context = new TestLambdaContext(); - var upperCase = function.FunctionHandler("hello world", context); - - Assert.Equal("HELLO WORLD", upperCase); - } -} diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj deleted file mode 100644 index e7105231..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/DynamoLambdaExampleHandler1.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - net6.0 - Exe - enable - enable - true - Lambda - - true - - true - - - - - - - - \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs deleted file mode 100644 index 78a30f59..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Function.cs +++ /dev/null @@ -1,109 +0,0 @@ -using Amazon.Lambda.Core; -using StackExchange.Redis; - -// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. -[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] - -namespace DynamoLambdaExampleHandler1; - -public class Function -{ - public async Task FunctionHandler(ILambdaContext context) - { - await new Function().DoStuff(); - return "Task completed"; - } - - static byte[] GenerateLargeValue(int sizeInBytes) - { - byte[] value = new byte[sizeInBytes]; - new Random().NextBytes(value); - return value; - } - - public async Task DoStuff() { - - // Create a Redis connection - Console.WriteLine("Creating redis client"); - var configurationOptions = new ConfigurationOptions - { - EndPoints = { "tacobellrediscluster.exmof5.ng.0001.usw2.cache.amazonaws.com:6379" } - }; - ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - - // Get a Redis database - Console.WriteLine("Fetching db"); - IDatabase db = redis.GetDatabase(); - - // Ping the redis server - Console.WriteLine("Pinging db"); - var pong = db.Ping(); - Console.WriteLine(pong); - - // Set 20 string keys with string values - for (int i = 1; i <= 20; i++) - { - string key = "key" + i; - // string value = "value" + i; - byte[] value = GenerateLargeValue(1 * 1024 * 1024); // 1MB - bool success = db.StringSet(key, value); - - if (success) - { - Console.WriteLine($"Key '{key}' set with a value of 1MB"); - - } - else - { - Console.WriteLine($"Failed to set key '{key}'"); - } - } - - var tasks = new Dictionary, System.Diagnostics.Stopwatch>(); - - // Get values of 10 keys asynchronously - for (int i = 1; i <= 10; i++) - { - string key = "key" + i; - - Console.WriteLine("Starting the stopwatch"); - var startTime = System.Diagnostics.Stopwatch.StartNew(); - var response = db.StringGetAsync(key); - - tasks[response] = startTime; - response.ContinueWith( - (r) => { - tasks[response].Stop(); - return r; - } - ); - Console.WriteLine("Stopping stopwatch"); - } - - Console.WriteLine("Awaiting pending tasks..."); - Task.WaitAll(tasks.Keys.ToArray()); - Console.WriteLine("Done awaiting tasks"); - - foreach(var entry in tasks) - { - Console.WriteLine(entry.Value.ElapsedMilliseconds); - } - - // Close the connection - redis.Close(); - - return "Task completed!"; - } - - - static void Main(string[] args) { - try { - Console.WriteLine("Calling DoStuff"); - new Function().DoStuff(); - } catch(Exception ex) { - Console.WriteLine("Caught Exception"); - Console.WriteLine(ex); - } - } - -} \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md deleted file mode 100644 index dbec4177..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/Readme.md +++ /dev/null @@ -1,49 +0,0 @@ -# AWS Lambda Empty Function Project - -This starter project consists of: -* Function.cs - class file containing a class with a single function handler method -* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS - -You may also have a test project depending on the options selected. - -The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. - -## Here are some steps to follow from Visual Studio: - -To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. - -To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. - -To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. - -To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. - -To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. - -To view execution logs of invocations of your function use the Logs tab in the opened Function View window. - -## Here are some steps to follow to get started from the command line: - -Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. - -Install Amazon.Lambda.Tools Global Tools if not already installed. -``` - dotnet tool install -g Amazon.Lambda.Tools -``` - -If already installed check if new version is available. -``` - dotnet tool update -g Amazon.Lambda.Tools -``` - -Execute unit tests -``` - cd "DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests" - dotnet test -``` - -Deploy function to AWS Lambda -``` - cd "DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1" - dotnet lambda deploy-function -``` diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json deleted file mode 100644 index 2d65c0b4..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,16 +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-architecture": "x86_64", - "function-runtime": "dotnet6", - "function-memory-size": 256, - "function-timeout": 30, - "function-handler": "DynamoLambdaExampleHandler1::DynamoLambdaExampleHandler1.Function::FunctionHandler" -} \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj deleted file mode 100644 index 892efe76..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/DynamoLambdaExampleHandler1.Tests.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - net6.0 - enable - enable - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs b/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs deleted file mode 100644 index 333b9983..00000000 --- a/examples/DynamoLambdaExample/DynamoLambdaExampleHandler1/test/DynamoLambdaExampleHandler1.Tests/FunctionTest.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Xunit; -using Amazon.Lambda.Core; -using Amazon.Lambda.TestUtilities; - -namespace DynamoLambdaExampleHandler1.Tests; - -public class FunctionTest -{ - [Fact] - public void TestToUpperFunction() - { - - // Invoke the lambda function and confirm the string was upper cased. - var function = new Function(); - var context = new TestLambdaContext(); - var upperCase = function.FunctionHandler("hello world", context); - - Assert.Equal("HELLO WORLD", upperCase); - } -} diff --git a/examples/DynamoLambdaExample/README.md b/examples/DynamoLambdaExample/README.md deleted file mode 100644 index f28e4d55..00000000 --- a/examples/DynamoLambdaExample/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Welcome to your CDK C# project! - -This is a blank project for CDK development with C#. - -The `cdk.json` file tells the CDK Toolkit how to execute your app. - -It uses the [.NET CLI](https://docs.microsoft.com/dotnet/articles/core/) to compile and execute your project. - -## Useful commands - -* `dotnet build src` compile this app -* `cdk deploy` deploy this stack to your default AWS account/region -* `cdk diff` compare deployed stack with current state -* `cdk synth` emits the synthesized CloudFormation template \ No newline at end of file diff --git a/examples/DynamoLambdaExample/cdk.context.json b/examples/DynamoLambdaExample/cdk.context.json deleted file mode 100644 index 0b991cb9..00000000 --- a/examples/DynamoLambdaExample/cdk.context.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "vpc-provider:account=287427698164:filter.vpc-id=vpc-00e94e9613dde8d21:region=us-west-2:returnAsymmetricSubnets=true": { - "vpcId": "vpc-00e94e9613dde8d21", - "vpcCidrBlock": "172.31.0.0/16", - "ownerAccountId": "287427698164", - "availabilityZones": [], - "subnetGroups": [ - { - "name": "Public", - "type": "Public", - "subnets": [ - { - "subnetId": "subnet-04b581aed6af02515", - "cidr": "172.31.32.0/20", - "availabilityZone": "us-west-2a", - "routeTableId": "rtb-0a2470cafd0b7bd73" - }, - { - "subnetId": "subnet-09e0ce2f2c6b2faac", - "cidr": "172.31.16.0/20", - "availabilityZone": "us-west-2b", - "routeTableId": "rtb-0a2470cafd0b7bd73" - }, - { - "subnetId": "subnet-00482a2a73a2a56de", - "cidr": "172.31.0.0/20", - "availabilityZone": "us-west-2c", - "routeTableId": "rtb-0a2470cafd0b7bd73" - }, - { - "subnetId": "subnet-0c5efae5cc62020bc", - "cidr": "172.31.48.0/20", - "availabilityZone": "us-west-2d", - "routeTableId": "rtb-0a2470cafd0b7bd73" - } - ] - } - ] - } -} diff --git a/examples/DynamoLambdaExample/cdk.json b/examples/DynamoLambdaExample/cdk.json deleted file mode 100644 index c38ed0e6..00000000 --- a/examples/DynamoLambdaExample/cdk.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "app": "dotnet run --project src/DynamoLambdaExample/DynamoLambdaExample.csproj", - "watch": { - "include": [ - "**" - ], - "exclude": [ - "README.md", - "cdk*.json", - "src/*/obj", - "src/*/bin", - "src/*.sln", - "src/*/GlobalSuppressions.cs", - "src/*/*.csproj" - ] - }, - "context": { - "@aws-cdk/aws-lambda:recognizeLayerVersion": true, - "@aws-cdk/core:checkSecretUsage": true, - "@aws-cdk/core:target-partitions": [ - "aws", - "aws-cn" - ], - "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, - "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, - "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, - "@aws-cdk/aws-iam:minimizePolicies": true, - "@aws-cdk/core:validateSnapshotRemovalPolicy": true, - "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, - "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, - "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, - "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, - "@aws-cdk/core:enablePartitionLiterals": true, - "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, - "@aws-cdk/aws-iam:standardizedServicePrincipals": true, - "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, - "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, - "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, - "@aws-cdk/aws-route53-patters:useCertificate": true, - "@aws-cdk/customresources:installLatestAwsSdkDefault": false, - "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, - "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, - "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, - "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, - "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, - "@aws-cdk/aws-redshift:columnId": true, - "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, - "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, - "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, - "@aws-cdk/aws-kms:aliasNameRef": true - } -} diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample.sln b/examples/DynamoLambdaExample/src/DynamoLambdaExample.sln deleted file mode 100644 index 3fcc8d61..00000000 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample.sln +++ /dev/null @@ -1,34 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 -MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamoLambdaExample", "DynamoLambdaExample\DynamoLambdaExample.csproj", "{ED03731A-32CF-436F-93B6-7BD16EDB667B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x64.ActiveCfg = Debug|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x64.Build.0 = Debug|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x86.ActiveCfg = Debug|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Debug|x86.Build.0 = Debug|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|Any CPU.Build.0 = Release|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x64.ActiveCfg = Release|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x64.Build.0 = Release|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x86.ActiveCfg = Release|Any CPU - {ED03731A-32CF-436F-93B6-7BD16EDB667B}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj deleted file mode 100644 index dad278f5..00000000 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExample.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - Exe - net6.0 - - Major - - - - - - - - - - - diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs deleted file mode 100644 index 87f44444..00000000 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/DynamoLambdaExampleStack.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Amazon.CDK; -using Amazon.CDK.AWS.Lambda; -using Constructs; -using Amazon.CDK.AWS.IAM; -using Amazon.CDK.AWS.EC2; - -namespace DynamoLambdaExample -{ - public class DynamoLambdaExampleStack : Stack - { - internal DynamoLambdaExampleStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) - { - // Existing VPC configuration - var vpc = Vpc.FromLookup(this, "DefaultVpc", new VpcLookupOptions - { - VpcId = "vpc-00e94e9613dde8d21" - }); - - var existingSubnet = Subnet.FromSubnetId(this, "ExistingSubnet", "subnet-09e0ce2f2c6b2faac"); - - // Create the IAM role for the Lambda function - Role lambdaRole = new Role(this, "LambdaRole", new RoleProps - { - AssumedBy = new ServicePrincipal("lambda.amazonaws.com"), - RoleName = "LambdaDynamoDBRole" - }); - - // Attach the managed policies - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")); - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonDynamoDBFullAccess")); - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonEC2FullAccess")); - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonElastiCacheFullAccess")); - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AWSLambdaInvocation-DynamoDB")); - - Function fn = new Function(this, "DynamoLambdaExampleHandler", new FunctionProps - { - Runtime = Runtime.DOTNET_6, - Code = Code.FromAsset("./DynamoLambdaExampleHandler/src/DynamoLambdaExampleHandler/bin/Release/net6.0/publish"), - Handler = "DynamoLambdaExampleHandler::DynamoLambdaExampleHandler.Function::FunctionHandler", - FunctionName = "PutItemHandler", - MemorySize = 1024, - Timeout = Duration.Seconds(300), - Role = lambdaRole, - Vpc = vpc, - VpcSubnets = new SubnetSelection { Subnets = new[] { existingSubnet } }, - AllowPublicSubnet = true - }); - - Function fn1 = new Function(this, "DynamoLambdaExampleHandler1", new FunctionProps - { - Runtime = Runtime.DOTNET_6, - Code = Code.FromAsset("./DynamoLambdaExampleHandler1/src/DynamoLambdaExampleHandler1/bin/Release/net6.0/publish"), - Handler = "DynamoLambdaExampleHandler1::DynamoLambdaExampleHandler1.Function::FunctionHandler", - FunctionName = "GetItemHandler", - MemorySize = 1024, - Timeout = Duration.Seconds(300), - Role = lambdaRole, - Vpc = vpc, - VpcSubnets = new SubnetSelection { Subnets = new[] { existingSubnet } }, - AllowPublicSubnet = true - }); - } - } -} diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs deleted file mode 100644 index 26233fcb..00000000 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/GlobalSuppressions.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "Constructs add themselves to the scope in which they are created")] diff --git a/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs b/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs deleted file mode 100644 index 1c44aaf4..00000000 --- a/examples/DynamoLambdaExample/src/DynamoLambdaExample/Program.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Amazon.CDK; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace DynamoLambdaExample -{ - sealed class Program - { - public static void Main(string[] args) - { - var app = new App(); - new DynamoLambdaExampleStack(app, "DynamoLambdaExampleStack", new StackProps - { - Env = new Amazon.CDK.Environment - { - Account = "287427698164", - Region = "us-west-2" - } - }); - - app.Synth(); - } - } -} diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs new file mode 100644 index 00000000..495e3bca --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs @@ -0,0 +1,29 @@ +using System.IO.Compression; +using System.Text; + +namespace MomentoRedisExampleLambdaHandler; + +public static class Compression +{ + public static string Decompress(byte[] value) + { + using var gzipStream = new GZipStream(new MemoryStream(value), CompressionMode.Decompress); + using (StreamReader reader = new StreamReader(gzipStream)) + { + return reader.ReadToEnd(); + } + } + + public static byte[] Compress(string value) + { + using var stream = new MemoryStream(); + //using var gzipStream = new GZipStream(stream, CompressionLevel.SmallestSize); + using var gzipStream = new GZipStream(stream, CompressionLevel.Fastest); + var buffer = Encoding.UTF8.GetBytes(value); + gzipStream.Write(buffer, 0, buffer.Length); + gzipStream.Flush(); + stream.Seek(0, SeekOrigin.Begin); + return stream.ToArray(); + } +} + diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs index 5d733fd5..7cd3fa80 100644 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs @@ -4,41 +4,60 @@ using Momento.Sdk.Auth; using Momento.Sdk.Config; using Momento.Sdk.Responses; -using System; -using System.IO; -using System.IO.Compression; // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] namespace MomentoRedisExampleLambdaHandler; -public class Function +public class Input { - const string CACHE_NAME = "MomentoLambda"; - const string REDIS_CLUSTER_ENDPOINT = "momentoredisexamplecluster.exmof5.ng.0001.usw2.cache.amazonaws.com:6379"; - public string bigString = new string('x', 1024*1024/2); + public bool RunMomentoWithCompression { get; set; } + public bool RunMomentoCompressionWithSleep { get; set; } + public bool RunMomentoWithoutCompression { get; set; } + public bool RunRedisWithCompression { get; set; } + public bool RunRedisWithoutCompression { get; set; } +} + +public record struct GetResult( + CacheGetResponse Response, + long ResponseSize, + long DecompressedResponseSize, + long ElapsedMillis, + long ElapsedMillisWithDecompression +); + +public record struct SetResult(CacheSetResponse Response, long ElapsedMillis); + +public record struct RedisGetResult(RedisValue Response, long ElapsedMillis, long ElapsedMillisWithDecompression); - public bool COMPRESS_VALUES = true; - public int numMomentoGetRequests = 10; - public int numMomentoSetRequests = 10; - public int numRedisGetRequests = 10; - public int numRedisSetRequests = 10; - // public Dictionary, System.Diagnostics.Stopwatch> momentoSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); - // public Dictionary, System.Diagnostics.Stopwatch> momentoGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); - public Dictionary, System.Diagnostics.Stopwatch> redisSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); - public Dictionary, System.Diagnostics.Stopwatch> redisGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); +public record struct RedisSetResult(bool Response, long ElapsedMillis); - public async Task FunctionHandler(ILambdaContext context) +public class Function +{ + const string CacheName = "MomentoLambda"; + const string RedisClusterEndpoint = "momentoredisexamplecluster.exmof5.ng.0001.usw2.cache.amazonaws.com:6379"; + private int _numMomentoGetRequests = 10; + private int _numMomentoSetRequests = 10; + private int _numRedisGetRequests = 10; + private int _numRedisSetRequests = 10; + + /// + /// Function Handler for running Momento Requests + /// + /// + /// + /// + public async Task FunctionHandler(Input input, ILambdaContext context) { - await new Function().DoStuff(); + await new Function().DoStuff(input); + return "Task completed"; } - public async Task DoStuff() { + private async Task DoStuff(Input input) { - Console.WriteLine("Start executing DoStuff"); - // var lambdaStartTime = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine("Start executing DoStuff...."); // Create Momento client ICredentialProvider authProvider = new EnvMomentoTokenProvider("MOMENTO_AUTH_TOKEN"); @@ -47,286 +66,229 @@ public async Task DoStuff() { authProvider, TimeSpan.FromSeconds(30) ); - - // Create cache if not already exists - await createMomentoCache(momentoClient); - - // Create a Redis connection - // Console.WriteLine("Creating redis client"); - // var configurationOptions = new ConfigurationOptions - // { - // EndPoints = { REDIS_CLUSTER_ENDPOINT } - // }; - // ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - - // Get a Redis database - // Console.WriteLine("Fetching db"); - // IDatabase db = redis.GetDatabase(); - - // var startKeyId = 1; - // while (lambdaStartTime.Elapsed.TotalMinutes < 4) { - // Fire momento and redis requests - var momentoSetTasks = await DoMomentoSets(momentoClient); - var momentoGetTasks = await DoMomentoGets(momentoClient); - // DoRedisSets(db, startKeyId); - // DoRedisGets(db, startKeyId); - - Console.WriteLine("Awaiting pending tasks..."); - Task.WaitAll(momentoSetTasks.Keys.ToArray()); - Task.WaitAll(momentoGetTasks.Keys.ToArray()); - // Task.WaitAll(redisSetTasks.Keys.ToArray()); - // Task.WaitAll(redisGetTasks.Keys.ToArray()); - Console.WriteLine("Done awaiting tasks"); - - // print momento set tasks - Console.WriteLine("------- MOMENTO SET RESULT -------"); - foreach(var entry in momentoSetTasks) { - var key = await entry.Key; - if (key.Item1 is CacheSetResponse.Error err) { - Console.WriteLine("ERROR: " + err.Message); - } else if (key.Item1 is CacheSetResponse.Success hit) { - Console.WriteLine("Set in " + key.Item2.ElapsedMilliseconds); - } - } - - // print momento get tasks - Console.WriteLine("------- MOMENTO GET RESULT -------"); - foreach(var entry in momentoGetTasks) - { - var key = await entry.Key; - if (key.Item1 is CacheGetResponse.Miss) { - Console.WriteLine("Unexpected MISS in " + key.Item2.ElapsedMilliseconds); - } else if (key.Item1 is CacheGetResponse.Error err) { - Console.WriteLine("ERROR: " + err.Message); - } else if (key.Item1 is CacheGetResponse.Hit hit) { - Console.WriteLine("Got " + hit.ValueString.Length + " in " + key.Item2.ElapsedMilliseconds); - } - } - - // print redis set tasks - // Console.WriteLine("------- REDIS SET RESULT -------"); - // foreach(var entry in redisSetTasks) - // { - // Console.WriteLine(entry.Value.ElapsedMilliseconds); - // } - - // print redis get tasks - // Console.WriteLine("------- REDIS GET RESULT -------"); - // foreach(var entry in redisGetTasks) - // { - // Console.WriteLine(entry.Value.ElapsedMilliseconds); - // } + // Create a Redis client + Console.WriteLine("Creating redis client"); + var configurationOptions = new ConfigurationOptions + { + EndPoints = { RedisClusterEndpoint } + }; + ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + + // Instantiate MomentoCache and RedisCache + MomentoCache momentoCache = new MomentoCache(momentoClient, CacheName); + RedisCache redisCache = new RedisCache(redis); - // startKeyId = startKeyId + numRedisSetRequests; - // } + // Create momento cache if not already exists + await momentoCache.CreateMomentoCache(); + + // Ping redis client + redisCache.PingRedis(); + + await ExecuteLambda(input, momentoCache, redisCache); - // Close the connection - // redis.Close(); + // Close the redis connection + await redis.CloseAsync(); Console.WriteLine("End executing DoStuff"); return "Task completed!"; } - private async Task createMomentoCache(CacheClient client) { - var response = await client.CreateCacheAsync(CACHE_NAME); - } - - private async Task, System.Diagnostics.Stopwatch>> DoMomentoSets(CacheClient client) { - try { - - Dictionary, System.Diagnostics.Stopwatch> momentoSetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); - - Console.WriteLine("Executing MomentoSets"); - string compressedString = Compress(); - - for (int i = 1; i <= numMomentoSetRequests; i++) { - Console.WriteLine("Setting inside the loop"); - string key = $"key-{i}"; - - Console.WriteLine("Setting key " + key); - var responseWithStopwatch = SetAsyncWithStopwatch(client, CACHE_NAME, key, compressedString, TimeSpan.FromSeconds(600)); - - // Task response = client.SetAsync(CACHE_NAME, key, compressedString, TimeSpan.FromSeconds(600)); - var continued = await responseWithStopwatch.ContinueWith( - (r) => { - var (response, stopwatch) = r.Result; - stopwatch.Stop(); - Console.WriteLine("Stopwatch stopped for key " + key); - return r; - } - ); - momentoSetTasks[continued] = continued.Result.Item2; - } - return momentoSetTasks; - } catch (Exception e) { - Console.WriteLine("Exception in set " + e); - throw new Exception(); - } - } - - private async Task<(CacheSetResponse, System.Diagnostics.Stopwatch)> SetAsyncWithStopwatch(CacheClient client, string cacheName, string key, string value, TimeSpan expirationTime) - { - var stopwatch = System.Diagnostics.Stopwatch.StartNew(); - var response = await client.SetAsync(cacheName, key, value, expirationTime); - return (response, stopwatch); - } - - private async Task, System.Diagnostics.Stopwatch>> DoMomentoGets(CacheClient client) { - Dictionary, System.Diagnostics.Stopwatch> momentoGetTasks = new Dictionary, System.Diagnostics.Stopwatch>(); - - for (int i = 1; i <= numMomentoGetRequests; i++) { - Console.WriteLine("Getting inside the loop"); - string key = $"key-{i}"; - - Console.WriteLine("Getting key " + key); - var responseWithStopwatch = GetAsyncWithStopwatch(client, CACHE_NAME, key); - - // momentoGetTasks[response] = startTime; - var continuedTask = responseWithStopwatch.ContinueWith( - async (r) => { - try { - Console.WriteLine("In ContinueWith"); - var (response, stopwatch) = r.Result; - stopwatch.Stop(); - Console.WriteLine("Stopwatch stopped for key " + key); - momentoGetTasks[r] = stopwatch; - - var hitResult = (CacheGetResponse.Hit)response; - string hitValue = hitResult.ValueString; - - // Decompressing compressed strings - string decompressedString = await DecompressAsync(hitValue); - return r; - } catch(Exception e) { - Console.WriteLine(e.Message); - throw new Exception(); - } - } - ); - - await continuedTask; - } - return momentoGetTasks; - } - - private async Task<(CacheGetResponse, System.Diagnostics.Stopwatch)> GetAsyncWithStopwatch(CacheClient client, string cacheName, string key) + private async Task ExecuteLambda(Input input, MomentoCache momentoCache, RedisCache redisCache) { - var stopwatch = System.Diagnostics.Stopwatch.StartNew(); - var response = await client.GetAsync(cacheName, key); - return (response, stopwatch); - } - - private string Compress() { - string compressedString; - // Convert the string to bytes - byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(bigString); + Console.WriteLine("Inside Execute Lambda function"); + Console.WriteLine($"Input {input}"); - // Create a memory stream to hold the compressed data - using (MemoryStream outputMemoryStream = new MemoryStream()) + if (input is { RunMomentoWithCompression: true, RunMomentoWithoutCompression: true } or { RunRedisWithCompression: true, RunRedisWithoutCompression: true }) { - // Create a GZip stream and specify CompressionMode.Compress - using (GZipStream compressionStream = new GZipStream(outputMemoryStream, CompressionMode.Compress)) - { - // Compress the input string bytes - compressionStream.Write(inputBytes, 0, inputBytes.Length); - } - - // Get the compressed bytes from the memory stream - byte[] compressedBytes = outputMemoryStream.ToArray(); - - // Convert the compressed bytes to a Base64 string - compressedString = Convert.ToBase64String(compressedBytes); + Console.WriteLine("Cannot run with and without compression configurations together!"); + throw new Exception("Invalid combination of parameters."); } - - return compressedString; - } - - private async Task DecompressAsync(string valueString) -{ - byte[] compressedBytes = Convert.FromBase64String(valueString); - using (MemoryStream compressedStream = new MemoryStream(compressedBytes)) - { - using (MemoryStream decompressedStream = new MemoryStream()) + if (input is { RunMomentoCompressionWithSleep: true, RunMomentoWithCompression: false}) { - using (GZipStream gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress)) - { - await gzipStream.CopyToAsync(decompressedStream); - } - - byte[] decompressedBytes = decompressedStream.ToArray(); - string decompressedString = System.Text.Encoding.UTF8.GetString(decompressedBytes); - - return decompressedString; + Console.WriteLine("RunMomentoCompressionWithSleep can run only when RunMomentoWithCompression is true."); + throw new Exception("Invalid combination of parameters. RunMomentoCompressionWithSleep can run only when RunMomentoWithCompression is true."); } - } -} + var trueCount = 0; + if (input.RunMomentoWithCompression) trueCount++; + if (input.RunMomentoWithoutCompression) trueCount++; + if (input.RunRedisWithCompression) trueCount++; + if (input.RunRedisWithoutCompression) trueCount++; - private void DoRedisSets(IDatabase db, int startKeyId) { - // Set string keys with string values - for (int i = startKeyId; i <= numRedisSetRequests; i++) - { - string key = "key" + i; - byte[] value = GenerateLargeValue(1 * 1024 * 1024); // 1MB - Console.WriteLine("Starting the stopwatch"); - var startTime = System.Diagnostics.Stopwatch.StartNew(); - Console.WriteLine("Setting key " + key); - Task response = db.StringSetAsync(key, value); - redisSetTasks[response] = startTime; + List> momentoSetTasks; + List> momentoGetTasks; + List> redisSetTasks; + List> redisGetTasks; - response.ContinueWith( - (r) => { - redisSetTasks[response].Stop(); - return r; - } - ); - Console.WriteLine("Stopped stopwatch"); - } - } - - private void DoRedisGets(IDatabase db, int startKeyId) { - // Get values of keys asynchronously - for (int i = startKeyId; i <= 10; i++) + switch (trueCount) { - string key = "key" + i; - - Console.WriteLine("Starting the stopwatch"); - var startTime = System.Diagnostics.Stopwatch.StartNew(); - Console.WriteLine("Getting key " + key); - var response = db.StringGetAsync(key); + case 1 when input.RunMomentoWithCompression: + // Execute code for running Momento with compression + Console.WriteLine("------- RUNNING MOMENTO WITH COMPRESSION -------"); + momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.RunMomentoCompressionWithSleep); + momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: true, withSleep: input.RunMomentoCompressionWithSleep); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + momentoCache.LogMomentoSetResult(momentoSetTasks); + momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: true); + break; + + case 1 when input.RunMomentoWithoutCompression: + // Execute code for running Momento without compression + Console.WriteLine("------- RUNNING MOMENTO WITHOUT COMPRESSION -------"); + momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests); + momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: false); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + momentoCache.LogMomentoSetResult(momentoSetTasks); + momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: false); + break; + + case 1 when input.RunRedisWithCompression: + // Execute code for running Redis with compression + Console.WriteLine("------- RUNNING REDIS WITH COMPRESSION -------"); + redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); + redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: true); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + redisCache.LogRedisSetResult(redisSetTasks); + redisCache.LogRedisGetResult(redisGetTasks, compressValue: true); + break; - redisGetTasks[response] = startTime; - response.ContinueWith( - (r) => { - redisGetTasks[response].Stop(); - return r; - } - ); - Console.WriteLine("Stopping stopwatch"); + case 1 when input.RunRedisWithoutCompression: + // Execute code for running Redis without compression + Console.WriteLine("------- RUNNING REDIS WITHOUT COMPRESSION -------"); + redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); + redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: false); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + redisCache.LogRedisSetResult(redisSetTasks); + redisCache.LogRedisGetResult(redisGetTasks, compressValue: false); + break; + + case 2 when input is { RunMomentoWithCompression: true, RunRedisWithCompression: true }: + // Execute code for running Momento with compression and Redis with compression + Console.WriteLine("------- RUNNING MOMENTO AND REDIS WITH COMPRESSION -------"); + momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.RunMomentoCompressionWithSleep); + redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); + momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: true, withSleep: input.RunMomentoCompressionWithSleep); + redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: true); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + momentoCache.LogMomentoSetResult(momentoSetTasks); + momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: true); + redisCache.LogRedisSetResult(redisSetTasks); + redisCache.LogRedisGetResult(redisGetTasks, compressValue: true); + break; + + case 2 when input is { RunMomentoWithCompression: true, RunRedisWithoutCompression: true }: + // Execute code for running Momento with compression and Redis without compression + Console.WriteLine("------- RUNNING MOMENTO WITH COMPRESSION AND REDIS WITHOUT COMPRESSION -------"); + momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.RunMomentoCompressionWithSleep); + redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); + momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: true, withSleep: input.RunMomentoCompressionWithSleep); + redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: false); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + momentoCache.LogMomentoSetResult(momentoSetTasks); + momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: true); + redisCache.LogRedisSetResult(redisSetTasks); + redisCache.LogRedisGetResult(redisGetTasks, compressValue: false); + break; + + case 2 when input is { RunMomentoWithoutCompression: true, RunRedisWithCompression: true }: + // Execute code for running Momento without compression and Redis with compression + Console.WriteLine("------- RUNNING MOMENTO WITHOUT COMPRESSION AND REDIS WITH COMPRESSION -------"); + momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests); + redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); + momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: false); + redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: true); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + momentoCache.LogMomentoSetResult(momentoSetTasks); + momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: false); + redisCache.LogRedisSetResult(redisSetTasks); + redisCache.LogRedisGetResult(redisGetTasks, compressValue: true); + break; + + case 2 when input is { RunMomentoWithoutCompression: true, RunRedisWithoutCompression: true }: + // Execute code for running Momento without compression and Redis without compression + Console.WriteLine("------- RUNNING MOMENTO AND REDIS WITHOUT COMPRESSION-------"); + momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests); + redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); + momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: false); + redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: false); + + Console.WriteLine("Awaiting pending tasks"); + Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + momentoCache.LogMomentoSetResult(momentoSetTasks); + momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: false); + redisCache.LogRedisSetResult(redisSetTasks); + redisCache.LogRedisGetResult(redisGetTasks, compressValue: false); + break; + + default: + // Handle the case when no parameters are set to true or more than two parameters are set to true + throw new Exception("Invalid combination of parameters."); } - } - private void pingRedis(IDatabase db) { - // Chceck/Ping the redis server - Console.WriteLine("Pinging db"); - var pong = db.Ping(); - Console.WriteLine(pong); + return "Lambda Execution Complete"; } - private static byte[] GenerateLargeValue(int sizeInBytes) - { - byte[] value = new byte[sizeInBytes]; - new Random().NextBytes(value); - return value; - } - - static void Main(string[] args) { + static void Main() { try { Console.WriteLine("Calling DoStuff"); - var task = new Function().DoStuff(); + Input input = new Input + { + RunMomentoWithCompression = true, + RunMomentoCompressionWithSleep = false, + RunMomentoWithoutCompression = false, + RunRedisWithCompression = false, + RunRedisWithoutCompression = false + }; + var task = new Function().DoStuff(input); Console.WriteLine("Waiting for task via task.Result"); Console.WriteLine($"RESULT: {task.Result}"); } catch(Exception ex) { diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs new file mode 100644 index 00000000..5be1ccf2 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs @@ -0,0 +1,188 @@ +using System.Diagnostics; +using Momento.Sdk; +using Momento.Sdk.Responses; + +namespace MomentoRedisExampleLambdaHandler; + +public class MomentoCache +{ + private string _cacheName; + private CacheClient _client; + + public MomentoCache(CacheClient client, string cacheName) + { + _client = client; + _cacheName = cacheName; + } + + public async Task CreateMomentoCache() + { + var response = await _client.CreateCacheAsync(_cacheName); + + switch (response) + { + case CreateCacheResponse.Success: + Console.WriteLine($"\t Cache: {_cacheName} created successfully."); + break; + case CreateCacheResponse.CacheAlreadyExists: + Console.WriteLine($"\t Cache: {_cacheName} already exists."); + break; + case CreateCacheResponse.Error: + Console.WriteLine($"\t Error creating cache: {_cacheName}"); + break; + } + } + + public async Task>> DoMomentoSets(int numMomentoSetRequests, bool withSleep = false) + { + Console.WriteLine($"\t WITH SLEEP flag: {withSleep}"); + try + { + List> momentoSetTasks = new List>(); + string sourceData = await Utils.GetSourceData(); + Console.WriteLine("Executing MomentoSets"); + + byte[] compressedSourceData = Compression.Compress(sourceData); + + for (int i = 1; i <= numMomentoSetRequests; i++) + { + Console.WriteLine("Setting inside the loop"); + string key = $"key-{i}"; + momentoSetTasks.Add(ExecuteSet(key, compressedSourceData, withSleep)); + } + + return momentoSetTasks; + } + catch (Exception e) + { + Console.WriteLine("Exception in set " + e); + throw new Exception(); + } + } + + private async Task ExecuteSet(string key, byte[] value, bool withSleep) + { + Console.WriteLine($"Beginning set request for {key}"); + var stopWatch = Stopwatch.StartNew(); + var setResponseTask = _client.SetAsync(_cacheName, key, value, TimeSpan.FromMinutes(30)); + Console.WriteLine($"\tIssued set request for {key}"); + var setResponse = await setResponseTask; + Console.WriteLine($"\tDone awaiting set response for {key}"); + + if (withSleep) + { + await Task.Delay(500); + Console.WriteLine($"SET returned from sleeping 500ms for key {key}"); + } + + stopWatch.Stop(); + var duration = stopWatch.ElapsedMilliseconds; + Console.WriteLine($"\tReturning set response for {key}: {setResponse}"); + return new SetResult(Response: setResponse, ElapsedMillis: duration); + } + +#pragma warning disable CS1998 + public async Task>> DoMomentoGets(int numMomentoGetRequests, bool compressValue, bool withSleep = false) { +#pragma warning restore CS1998 + List> momentoGetTasks = new List>(); + + for (int i = 1; i <= numMomentoGetRequests; i++) + { + Console.WriteLine("Executing MomentoGets"); + string key = $"key-{i}"; + momentoGetTasks.Add(ExecuteGet(key, compressValue, withSleep)); + } + + return momentoGetTasks; + } + + private async Task ExecuteGet(string key, bool compressValue, bool withSleep) + { + var withCompressionStopWatch = new Stopwatch(); + Console.WriteLine($"Beginning get request for {key}"); + var stopWatch = Stopwatch.StartNew(); + if (compressValue) + { + withCompressionStopWatch = Stopwatch.StartNew(); + } + var getResponseTask = _client.GetAsync(_cacheName, key); + Console.WriteLine($"\tIssued get request for {key}"); + var getResponse = await getResponseTask; + Console.WriteLine($"\tDone awaiting get response for {key}"); + + if (withSleep) + { + await Task.Delay(500); + Console.WriteLine($"GET returned from sleeping 500ms for key {key}"); + } + + stopWatch.Stop(); + var responseElapsedMillis = stopWatch.ElapsedMilliseconds; + long withDecompressionElapsedMillis = 0; + long responseSize = 0; + long decompressedResponseSize = 0; + if (getResponse is CacheGetResponse.Hit hitResponse) + { + Console.WriteLine($"\tResponse for {key} is a hit; decompressing"); + responseSize = hitResponse.ValueByteArray.Length; + if (compressValue) + { + var decompressed = Compression.Decompress(hitResponse.ValueByteArray); + Console.WriteLine($"\tResponse finished decompressing for {key}"); + decompressedResponseSize = decompressed.Length; + withCompressionStopWatch.Stop(); + withDecompressionElapsedMillis = withCompressionStopWatch.ElapsedMilliseconds; + } + + } + else + { + Console.WriteLine( + $"\n\nGOT SOMETHING BESIDES A HIT FOR KEY {key}; PROBABLY SHOULDN'T USE THIS DATA\n\n"); + } + + var getResult = new GetResult( + Response: getResponse, + ResponseSize: responseSize, + DecompressedResponseSize: decompressedResponseSize, + ElapsedMillis: responseElapsedMillis, + ElapsedMillisWithDecompression: withDecompressionElapsedMillis + ); + Console.WriteLine($"\tReturning get response for {key}: {getResult}"); + return getResult; + } + + public async void LogMomentoSetResult(List> momentoSetTasks) + { + Console.WriteLine("------- MOMENTO SET RESULT -------"); + foreach(var setTask in momentoSetTasks) + { + var setResult = await setTask; + if (setResult.Response is CacheSetResponse.Error err) { + Console.WriteLine("ERROR: " + err.Message); + } else if (setResult.Response is CacheSetResponse.Success) { + Console.WriteLine("Set in " + setResult.ElapsedMillis); + } + } + } + + public async void LogMomentoGetResult(List> momentoGetTasks, bool compressValue) + { + Console.WriteLine("------- MOMENTO GET RESULT -------"); + + foreach(var task in momentoGetTasks) + { + var getResult = await task; + if (getResult.Response is CacheGetResponse.Miss) { + Console.WriteLine($"Unexpected MISS for result: {getResult}"); + } else if (getResult.Response is CacheGetResponse.Error) { + Console.WriteLine($"ERROR: {getResult}"); + } else if (getResult.Response is CacheGetResponse.Hit) + { + Console.WriteLine(!compressValue + ? $"Got HIT for: {getResult.ResponseSize} in {getResult.ElapsedMillis}" + : $"Got HIT after decompressing for: {getResult.DecompressedResponseSize} in {getResult.ElapsedMillisWithDecompression}"); + } + } + } +} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj index 629dcce1..facc726c 100644 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj @@ -14,6 +14,7 @@ + diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs new file mode 100644 index 00000000..e12620e6 --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs @@ -0,0 +1,143 @@ +using System.Diagnostics; +using StackExchange.Redis; + +namespace MomentoRedisExampleLambdaHandler; + +public class RedisCache +{ + private IDatabase _db; + public RedisCache(ConnectionMultiplexer redis) + { + _db = redis.GetDatabase(); + } + public void PingRedis() { + // Check/Ping the redis server + Console.WriteLine("Pinging db"); + var pong = _db.Ping(); + Console.WriteLine(pong); + } + + public async Task>> DoRedisSets(int numRedisSetRequests) + { + Console.WriteLine("Executing Redis Sets"); + try + { + List> redisSetTasks = new List>(); + string sourceData = await Utils.GetSourceData(); + Console.WriteLine("Executing RedisSets"); + + byte[] compressedSourceData = Compression.Compress(sourceData); + + for (int i = 1; i <= numRedisSetRequests; i++) + { + Console.WriteLine("Setting inside the loop"); + string key = $"key-{i}"; + redisSetTasks.Add(ExecuteSet(key, compressedSourceData)); + } + + return redisSetTasks; + } + catch (Exception e) + { + Console.WriteLine("Exception in set " + e); + throw new Exception(); + } + } + + private async Task ExecuteSet(string key, byte[] value) + { + Console.WriteLine($"Beginning redis set request for {key}"); + var stopWatch = Stopwatch.StartNew(); + var setResponseTask = _db.StringSetAsync(key, value); + Console.WriteLine($"\tIssued redis set request for {key}"); + var setResponse = await setResponseTask; + Console.WriteLine($"\tDone awaiting redis set response for {key}"); + stopWatch.Stop(); + var duration = stopWatch.ElapsedMilliseconds; + // Console.WriteLine($"\tReturning redis set response for {key}: {setResponse}"); + Console.WriteLine($"\tReturning redis set response for {key}"); + return new RedisSetResult(Response: setResponse, ElapsedMillis: duration); + } + +#pragma warning disable CS1998 + public async Task>> DoRedisGets(int numRedisGetRequests, bool compressValue) +#pragma warning restore CS1998 + { + Console.WriteLine("Executing Redis Gets"); + List> redisGetTasks = new List>(); + + for (int i = 1; i <= numRedisGetRequests; i++) + { + Console.WriteLine("Executing RedisGets"); + string key = $"key-{i}"; + redisGetTasks.Add(ExecuteGet(key, compressValue)); + } + + return redisGetTasks; + } + + private async Task ExecuteGet(string key, bool compressValue) + { + + Console.WriteLine($"Beginning redis get request for {key}"); + var withCompressionStopWatch = new Stopwatch(); + var stopWatch = Stopwatch.StartNew(); + if (compressValue) + { + withCompressionStopWatch = Stopwatch.StartNew(); + } + var getResponseTask = _db.StringGetAsync(key); + Console.WriteLine($"\tIssued redis get request for {key}"); + var getResponse = await getResponseTask; + Console.WriteLine($"\tDone awaiting redis get response for {key}"); + stopWatch.Stop(); + var responseElapsedMillis = stopWatch.ElapsedMilliseconds; + long withDecompressionElapsedMillis = 0; + + if (compressValue) + { + if (getResponse.HasValue) + { + var decompressed = Compression.Decompress(getResponse!); + Console.WriteLine($"\tResponse finished decompressing for {key}"); + withCompressionStopWatch.Stop(); + withDecompressionElapsedMillis = withCompressionStopWatch.ElapsedMilliseconds; + } + else + { + Console.WriteLine($"\tValue not found for {key}"); + } + } + + var getResult = new RedisGetResult( + Response: getResponse, + ElapsedMillis: responseElapsedMillis, + ElapsedMillisWithDecompression: withDecompressionElapsedMillis + ); + // Console.WriteLine($"\tReturning get response for {key}: {getResult}"); + Console.WriteLine($"\tReturning get response for {key}"); + return getResult; + } + + public async void LogRedisSetResult(List> redisSetTasks) + { + Console.WriteLine("------- REDIS SET RESULT -------"); + foreach(var setTask in redisSetTasks) + { + var setResult = await setTask; + Console.WriteLine($"Set response in {setResult.ElapsedMillis}"); + } + } + + public async void LogRedisGetResult(List> redisGetTasks, bool compressValue) + { + Console.WriteLine("------- REDIS GET RESULT -------"); + foreach(var getTask in redisGetTasks) + { + var getResult = await getTask; + Console.WriteLine(compressValue + ? $"Got response with compression in {getResult.ElapsedMillisWithDecompression}" + : $"Got response in {getResult.ElapsedMillis}"); + } + } +} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs new file mode 100644 index 00000000..627100bb --- /dev/null +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs @@ -0,0 +1,42 @@ +using Amazon.S3; +using Amazon.S3.Model; + +namespace MomentoRedisExampleLambdaHandler; + +public class Utils +{ + private static IAmazonS3? _s3Client; + private static readonly string BucketName = "my-super-secret-bucket"; + private static readonly string ObjectKey = "super-secret-source-data.json"; + + public static async Task GetSourceData() + { + string sourceData; + try + { + // Create Amazon S3 Client + _s3Client = new AmazonS3Client(); + GetObjectRequest request = new GetObjectRequest + { + BucketName = BucketName, + Key = ObjectKey + }; + + using (GetObjectResponse response = await _s3Client.GetObjectAsync(request)) + { + // Read the object content + using (StreamReader reader = new StreamReader(response.ResponseStream)) + { + sourceData = await reader.ReadToEndAsync(); + } + } + + return sourceData; + } + catch (Exception ex) + { + Console.WriteLine("Error reading from S3: " + ex.Message); + throw; + } + } +} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs index 5e602887..dc8fd230 100644 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs @@ -3,6 +3,7 @@ using Constructs; using Amazon.CDK.AWS.IAM; using Amazon.CDK.AWS.EC2; +using Amazon.CDK.AWS.S3; using Amazon.CDK.AWS.Events; using Amazon.CDK.AWS.Events.Targets; @@ -43,8 +44,9 @@ internal MomentoRedisLambdaExampleStack(Construct scope, string id, IStackProps lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")); lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonEC2FullAccess")); lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonElastiCacheFullAccess")); + lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonS3FullAccess")); - var MOMENTO_AUTH_TOKEN = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJyaXNodGlAbW9tZW50b2hxLmNvbSIsImNwIjoiY29udHJvbC5jZWxsLTQtdXMtd2VzdC0yLTEucHJvZC5hLm1vbWVudG9ocS5jb20iLCJjIjoiY2FjaGUuY2VsbC00LXVzLXdlc3QtMi0xLnByb2QuYS5tb21lbnRvaHEuY29tIn0.eGgz9D7-R_6T9TVL-zsE8rnNf6TaVG6qKh7G0PmuaOBkWDC61hVOvZPwvu-n43Ld5NV5-sfTFQwY5BL0iL9Dpw"; + var MOMENTO_AUTH_TOKEN = "replace this with your momento auth token"; Function fn1 = new Function(this, "MomentoRedisLambdaExampleHandler", new FunctionProps { @@ -62,18 +64,6 @@ internal MomentoRedisLambdaExampleStack(Construct scope, string id, IStackProps { "MOMENTO_AUTH_TOKEN", MOMENTO_AUTH_TOKEN} } }); - - // Create an event rule with a schedule expression for every 5 minutes - // var rule = new Rule(this, "MomentoRedisExampleLambdaTriggerRule", new RuleProps - // { - // Schedule = Schedule.Cron(new CronOptions - // { - // Minute = "*/5" // Run every 5 minutes - // }) - // }); - - // Add the Lambda function as a target for the event rule - // rule.AddTarget(new LambdaFunction(fn1)); } } } From 1227dc80181aaabd06eee086b15c8f85374371cd Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Tue, 13 Jun 2023 13:44:20 -0700 Subject: [PATCH 10/16] fix: remove super-secret json file --- examples/.gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/.gitignore b/examples/.gitignore index 2ce902f6..92275dbc 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -402,5 +402,4 @@ ASALocalRun/ .mfractor/ # Local History for Visual Studio -.localhistory/ -/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/super-secret-source-data.json +.localhistory/ \ No newline at end of file From 7d9393b147740e2376dc3c41fa6e16038de18ba8 Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Tue, 13 Jun 2023 17:02:16 -0700 Subject: [PATCH 11/16] feat: simple ExecuteLambda logic --- .../Function.cs | 211 +++--------------- .../MomentoRedisLambdaExampleStack.cs | 5 +- 2 files changed, 33 insertions(+), 183 deletions(-) diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs index 7cd3fa80..f6dbe1ea 100644 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs +++ b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs @@ -12,11 +12,11 @@ namespace MomentoRedisExampleLambdaHandler; public class Input { - public bool RunMomentoWithCompression { get; set; } - public bool RunMomentoCompressionWithSleep { get; set; } - public bool RunMomentoWithoutCompression { get; set; } - public bool RunRedisWithCompression { get; set; } - public bool RunRedisWithoutCompression { get; set; } + public bool RunMomento { get; set; } + public bool CompressMomento { get; set; } + public bool SleepMomento { get; set; } + public bool RunRedis { get; set; } + public bool CompressRedis { get; set; } } public record struct GetResult( @@ -100,178 +100,31 @@ private async Task ExecuteLambda(Input input, MomentoCache momentoCache, Console.WriteLine("Inside Execute Lambda function"); Console.WriteLine($"Input {input}"); - if (input is { RunMomentoWithCompression: true, RunMomentoWithoutCompression: true } or { RunRedisWithCompression: true, RunRedisWithoutCompression: true }) - { - Console.WriteLine("Cannot run with and without compression configurations together!"); - throw new Exception("Invalid combination of parameters."); - } - - if (input is { RunMomentoCompressionWithSleep: true, RunMomentoWithCompression: false}) - { - Console.WriteLine("RunMomentoCompressionWithSleep can run only when RunMomentoWithCompression is true."); - throw new Exception("Invalid combination of parameters. RunMomentoCompressionWithSleep can run only when RunMomentoWithCompression is true."); - } - - var trueCount = 0; - if (input.RunMomentoWithCompression) trueCount++; - if (input.RunMomentoWithoutCompression) trueCount++; - if (input.RunRedisWithCompression) trueCount++; - if (input.RunRedisWithoutCompression) trueCount++; - List> momentoSetTasks; List> momentoGetTasks; List> redisSetTasks; List> redisGetTasks; - - switch (trueCount) - { - case 1 when input.RunMomentoWithCompression: - // Execute code for running Momento with compression - Console.WriteLine("------- RUNNING MOMENTO WITH COMPRESSION -------"); - momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.RunMomentoCompressionWithSleep); - momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: true, withSleep: input.RunMomentoCompressionWithSleep); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - momentoCache.LogMomentoSetResult(momentoSetTasks); - momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: true); - break; - - case 1 when input.RunMomentoWithoutCompression: - // Execute code for running Momento without compression - Console.WriteLine("------- RUNNING MOMENTO WITHOUT COMPRESSION -------"); - momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests); - momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: false); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - momentoCache.LogMomentoSetResult(momentoSetTasks); - momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: false); - break; - - case 1 when input.RunRedisWithCompression: - // Execute code for running Redis with compression - Console.WriteLine("------- RUNNING REDIS WITH COMPRESSION -------"); - redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); - redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: true); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - redisCache.LogRedisSetResult(redisSetTasks); - redisCache.LogRedisGetResult(redisGetTasks, compressValue: true); - break; - - case 1 when input.RunRedisWithoutCompression: - // Execute code for running Redis without compression - Console.WriteLine("------- RUNNING REDIS WITHOUT COMPRESSION -------"); - redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); - redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: false); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - redisCache.LogRedisSetResult(redisSetTasks); - redisCache.LogRedisGetResult(redisGetTasks, compressValue: false); - break; - - case 2 when input is { RunMomentoWithCompression: true, RunRedisWithCompression: true }: - // Execute code for running Momento with compression and Redis with compression - Console.WriteLine("------- RUNNING MOMENTO AND REDIS WITH COMPRESSION -------"); - momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.RunMomentoCompressionWithSleep); - redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); - momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: true, withSleep: input.RunMomentoCompressionWithSleep); - redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: true); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - momentoCache.LogMomentoSetResult(momentoSetTasks); - momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: true); - redisCache.LogRedisSetResult(redisSetTasks); - redisCache.LogRedisGetResult(redisGetTasks, compressValue: true); - break; - - case 2 when input is { RunMomentoWithCompression: true, RunRedisWithoutCompression: true }: - // Execute code for running Momento with compression and Redis without compression - Console.WriteLine("------- RUNNING MOMENTO WITH COMPRESSION AND REDIS WITHOUT COMPRESSION -------"); - momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.RunMomentoCompressionWithSleep); - redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); - momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: true, withSleep: input.RunMomentoCompressionWithSleep); - redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: false); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - momentoCache.LogMomentoSetResult(momentoSetTasks); - momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: true); - redisCache.LogRedisSetResult(redisSetTasks); - redisCache.LogRedisGetResult(redisGetTasks, compressValue: false); - break; - - case 2 when input is { RunMomentoWithoutCompression: true, RunRedisWithCompression: true }: - // Execute code for running Momento without compression and Redis with compression - Console.WriteLine("------- RUNNING MOMENTO WITHOUT COMPRESSION AND REDIS WITH COMPRESSION -------"); - momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests); - redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); - momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: false); - redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: true); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - momentoCache.LogMomentoSetResult(momentoSetTasks); - momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: false); - redisCache.LogRedisSetResult(redisSetTasks); - redisCache.LogRedisGetResult(redisGetTasks, compressValue: true); - break; - - case 2 when input is { RunMomentoWithoutCompression: true, RunRedisWithoutCompression: true }: - // Execute code for running Momento without compression and Redis without compression - Console.WriteLine("------- RUNNING MOMENTO AND REDIS WITHOUT COMPRESSION-------"); - momentoSetTasks = await momentoCache.DoMomentoSets(_numMomentoSetRequests); - redisSetTasks = await redisCache.DoRedisSets(_numRedisSetRequests); - momentoGetTasks = await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: false); - redisGetTasks = await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: false); - - Console.WriteLine("Awaiting pending tasks"); - Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - momentoCache.LogMomentoSetResult(momentoSetTasks); - momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: false); - redisCache.LogRedisSetResult(redisSetTasks); - redisCache.LogRedisGetResult(redisGetTasks, compressValue: false); - break; - - default: - // Handle the case when no parameters are set to true or more than two parameters are set to true - throw new Exception("Invalid combination of parameters."); + + momentoSetTasks = input.RunMomento ? await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.SleepMomento) : new List>(); + redisSetTasks = input.RunRedis ? await redisCache.DoRedisSets(_numRedisSetRequests) : new List>(); + momentoGetTasks = input.RunMomento ? await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: input.CompressMomento, withSleep: input.SleepMomento) : new List>(); + redisGetTasks = input.RunRedis ? await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: input.CompressRedis) : new List>(); + + Console.WriteLine("Awaiting pending tasks"); + // empty lists should no-op + Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); + Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); + Console.Write("Done awaiting tasks"); + + if (input.RunMomento) { + momentoCache.LogMomentoSetResult(momentoSetTasks); + momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: input.CompressMomento); + } + if (input.RunRedis) { + redisCache.LogRedisSetResult(redisSetTasks); + redisCache.LogRedisGetResult(redisGetTasks, compressValue: input.CompressRedis); } return "Lambda Execution Complete"; @@ -280,13 +133,13 @@ private async Task ExecuteLambda(Input input, MomentoCache momentoCache, static void Main() { try { Console.WriteLine("Calling DoStuff"); - Input input = new Input + var input = new Input { - RunMomentoWithCompression = true, - RunMomentoCompressionWithSleep = false, - RunMomentoWithoutCompression = false, - RunRedisWithCompression = false, - RunRedisWithoutCompression = false + RunMomento = true, + CompressMomento = false, + SleepMomento = false, + RunRedis = false, + CompressRedis = false }; var task = new Function().DoStuff(input); Console.WriteLine("Waiting for task via task.Result"); diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs index dc8fd230..77ee73af 100644 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs @@ -3,9 +3,6 @@ using Constructs; using Amazon.CDK.AWS.IAM; using Amazon.CDK.AWS.EC2; -using Amazon.CDK.AWS.S3; -using Amazon.CDK.AWS.Events; -using Amazon.CDK.AWS.Events.Targets; namespace MomentoRedisLambdaExample { @@ -46,7 +43,7 @@ internal MomentoRedisLambdaExampleStack(Construct scope, string id, IStackProps lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonElastiCacheFullAccess")); lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonS3FullAccess")); - var MOMENTO_AUTH_TOKEN = "replace this with your momento auth token"; + var MOMENTO_AUTH_TOKEN = "replace with your momento auth token"; Function fn1 = new Function(this, "MomentoRedisLambdaExampleHandler", new FunctionProps { From eaed22d43ffa7fd90f233c11e77036dd917e5d11 Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Tue, 13 Jun 2023 17:21:40 -0700 Subject: [PATCH 12/16] fix: remove hardcoded aws account info from cd stack --- .../src/MomentoRedisLambdaExample/Program.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs index 50370fa1..0fea7a5d 100644 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs +++ b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs @@ -1,7 +1,4 @@ using Amazon.CDK; -using System; -using System.Collections.Generic; -using System.Linq; namespace MomentoRedisLambdaExample { @@ -12,10 +9,10 @@ public static void Main(string[] args) var app = new App(); new MomentoRedisLambdaExampleStack(app, "MomentoRedisLambdaExampleStack", new StackProps { - Env = new Amazon.CDK.Environment + Env = new Environment { - Account = "287427698164", - Region = "us-west-2" + Account = Aws.ACCOUNT_ID, + Region = Aws.REGION } }); app.Synth(); From e9d6c29f1b06fbf5a9e252dcea5287755340559c Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Mon, 26 Jun 2023 16:56:17 +0000 Subject: [PATCH 13/16] Update templated README.md file --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 347ddac5..3373822b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Momento Cache is a fast, simple, pay-as-you-go caching solution without any of the operational overhead required by traditional caching solutions. This repo contains the source code for the Momento .NET client library. +To get started with Momento you will need a Momento Auth Token. You can get one from the [Momento Console](https://console.gomomento.com). + * Website: [https://www.gomomento.com/](https://www.gomomento.com/) * Momento Documentation: [https://docs.momentohq.com/](https://docs.momentohq.com/) * Getting Started: [https://docs.momentohq.com/getting-started](https://docs.momentohq.com/getting-started) From 02ec7e665be7ee0f6fcab3c556db76167fc4c696 Mon Sep 17 00:00:00 2001 From: Chris Price Date: Mon, 26 Jun 2023 17:14:47 -0700 Subject: [PATCH 14/16] chore: get rid of TEST_CACHE environment variable Our tests currently require a TEST_CACHE environment variable, which is not really useful and sets a pattern that other SDKs may need to require this too in order to standardize on a way to launch them (for example in the SDK canaries). The JS SDK does not work properly if you set that environment variable, because it is intended for use when running against a local mr2. This commit removes the env var and dynamically creates a cache name to use for the tests. --- .github/workflows/build.yaml | 1 - .github/workflows/on-push-to-main-branch.yaml | 1 - tests/Integration/Momento.Sdk.Tests/CacheControlTest.cs | 6 +++--- tests/Integration/Momento.Sdk.Tests/Fixtures.cs | 6 ++---- tests/Integration/Momento.Sdk.Tests/Utils.cs | 9 +++++++++ 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 910584a0..c774340f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -16,7 +16,6 @@ jobs: runs-on: ${{ matrix.os }} env: TEST_AUTH_TOKEN: ${{ secrets.ALPHA_TEST_AUTH_TOKEN }} - TEST_CACHE_NAME: client-sdk-dotnet-${{ github.sha }}-${{ matrix.target-framework }} steps: - name: Get current time diff --git a/.github/workflows/on-push-to-main-branch.yaml b/.github/workflows/on-push-to-main-branch.yaml index 3ef97e4f..d6f74b70 100644 --- a/.github/workflows/on-push-to-main-branch.yaml +++ b/.github/workflows/on-push-to-main-branch.yaml @@ -16,7 +16,6 @@ jobs: runs-on: ${{ matrix.os }} env: TEST_AUTH_TOKEN: ${{ secrets.ALPHA_TEST_AUTH_TOKEN }} - TEST_CACHE_NAME: client-sdk-dotnet-${{ github.sha }}-${{ matrix.target-framework }} steps: - name: Get current time diff --git a/tests/Integration/Momento.Sdk.Tests/CacheControlTest.cs b/tests/Integration/Momento.Sdk.Tests/CacheControlTest.cs index eba274f1..701073db 100644 --- a/tests/Integration/Momento.Sdk.Tests/CacheControlTest.cs +++ b/tests/Integration/Momento.Sdk.Tests/CacheControlTest.cs @@ -62,7 +62,7 @@ public async Task CreateCacheAsync_NullCache_InvalidArgumentError() public async Task FlushCacheAsync_HappyPath() { string cacheName = Utils.TestCacheName(); - await client.CreateCacheAsync(cacheName); + Utils.CreateCacheForTest(client, cacheName); try { @@ -113,7 +113,7 @@ public async Task ListCachesAsync_OneCache_HappyPath() { // Create cache string cacheName = Utils.TestCacheName(); - await client.CreateCacheAsync(cacheName); + Utils.CreateCacheForTest(client, cacheName); // Test cache exists ListCachesResponse result = await client.ListCachesAsync(); @@ -142,7 +142,7 @@ public async Task ListCachesAsync_Iteration_HappyPath() { String cacheName = Utils.TestCacheName(); cacheNames.Add(cacheName); - await client.CreateCacheAsync(cacheName); + Utils.CreateCacheForTest(client, cacheName); } try { diff --git a/tests/Integration/Momento.Sdk.Tests/Fixtures.cs b/tests/Integration/Momento.Sdk.Tests/Fixtures.cs index ec4b715c..e11e52f1 100644 --- a/tests/Integration/Momento.Sdk.Tests/Fixtures.cs +++ b/tests/Integration/Momento.Sdk.Tests/Fixtures.cs @@ -21,8 +21,7 @@ public class CacheClientFixture : IDisposable public CacheClientFixture() { AuthProvider = new EnvMomentoTokenProvider("TEST_AUTH_TOKEN"); - CacheName = Environment.GetEnvironmentVariable("TEST_CACHE_NAME") ?? - throw new NullReferenceException("TEST_CACHE_NAME environment variable must be set."); + CacheName = $"dotnet-integration-{Utils.NewGuidString()}"; Client = new CacheClient(Configurations.Laptop.Latest(LoggerFactory.Create(builder => { builder.AddSimpleConsole(options => @@ -35,8 +34,7 @@ public CacheClientFixture() builder.SetMinimumLevel(LogLevel.Information); })), AuthProvider, defaultTtl: DefaultTtl); - - var result = Client.CreateCacheAsync(CacheName).Result; + Utils.CreateCacheForTest(Client, CacheName); } public void Dispose() diff --git a/tests/Integration/Momento.Sdk.Tests/Utils.cs b/tests/Integration/Momento.Sdk.Tests/Utils.cs index 66f1721b..b63fb044 100644 --- a/tests/Integration/Momento.Sdk.Tests/Utils.cs +++ b/tests/Integration/Momento.Sdk.Tests/Utils.cs @@ -19,4 +19,13 @@ public static class Utils public static int WaitForItemToBeSet { get; } = 100; public static int WaitForInitialItemToExpire { get; } = 4900; + + public static void CreateCacheForTest(ICacheClient cacheClient, string cacheName) + { + var result = cacheClient.CreateCacheAsync(cacheName).Result; + if (result is not (CreateCacheResponse.Success or CreateCacheResponse.CacheAlreadyExists)) + { + throw new Exception($"Error when creating cache: {result}"); + } + } } \ No newline at end of file From 84e19c0f522adb24af32f095f084b6356d583f0b Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Thu, 29 Jun 2023 13:47:31 -0700 Subject: [PATCH 15/16] chore: delete momento redis lambda example --- examples/MomentoRedisLambdaExample/.gitignore | 342 ------------------ .../Compression.cs | 29 -- .../Function.cs | 153 -------- .../MomentoCache.cs | 188 ---------- .../MomentoRedisExampleLambdaHandler.csproj | 21 -- .../Readme.md | 49 --- .../RedisCache.cs | 143 -------- .../MomentoRedisExampleLambdaHandler/Utils.cs | 42 --- .../aws-lambda-tools-defaults.json | 16 - .../FunctionTest.cs | 20 - ...entoRedisExampleLambdaHandler.Tests.csproj | 17 - examples/MomentoRedisLambdaExample/README.md | 14 - .../cdk.context.json | 46 --- examples/MomentoRedisLambdaExample/cdk.json | 52 --- .../src/MomentoRedisLambdaExample.sln | 34 -- .../GlobalSuppressions.cs | 1 - .../MomentoRedisLambdaExample.csproj | 20 - .../MomentoRedisLambdaExampleStack.cs | 66 ---- .../src/MomentoRedisLambdaExample/Program.cs | 21 -- 19 files changed, 1274 deletions(-) delete mode 100644 examples/MomentoRedisLambdaExample/.gitignore delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs delete mode 100644 examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj delete mode 100644 examples/MomentoRedisLambdaExample/README.md delete mode 100644 examples/MomentoRedisLambdaExample/cdk.context.json delete mode 100644 examples/MomentoRedisLambdaExample/cdk.json delete mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln delete mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs delete mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj delete mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs delete mode 100644 examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs diff --git a/examples/MomentoRedisLambdaExample/.gitignore b/examples/MomentoRedisLambdaExample/.gitignore deleted file mode 100644 index a4609e75..00000000 --- a/examples/MomentoRedisLambdaExample/.gitignore +++ /dev/null @@ -1,342 +0,0 @@ -# CDK asset staging directory -.cdk.staging -cdk.out - -# Created by https://www.gitignore.io/api/csharp - -### Csharp ### -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - - -# End of https://www.gitignore.io/api/csharp \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs deleted file mode 100644 index 495e3bca..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Compression.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.IO.Compression; -using System.Text; - -namespace MomentoRedisExampleLambdaHandler; - -public static class Compression -{ - public static string Decompress(byte[] value) - { - using var gzipStream = new GZipStream(new MemoryStream(value), CompressionMode.Decompress); - using (StreamReader reader = new StreamReader(gzipStream)) - { - return reader.ReadToEnd(); - } - } - - public static byte[] Compress(string value) - { - using var stream = new MemoryStream(); - //using var gzipStream = new GZipStream(stream, CompressionLevel.SmallestSize); - using var gzipStream = new GZipStream(stream, CompressionLevel.Fastest); - var buffer = Encoding.UTF8.GetBytes(value); - gzipStream.Write(buffer, 0, buffer.Length); - gzipStream.Flush(); - stream.Seek(0, SeekOrigin.Begin); - return stream.ToArray(); - } -} - diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs deleted file mode 100644 index f6dbe1ea..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Function.cs +++ /dev/null @@ -1,153 +0,0 @@ -using Amazon.Lambda.Core; -using StackExchange.Redis; -using Momento.Sdk; -using Momento.Sdk.Auth; -using Momento.Sdk.Config; -using Momento.Sdk.Responses; - -// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. -[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] - -namespace MomentoRedisExampleLambdaHandler; - -public class Input -{ - public bool RunMomento { get; set; } - public bool CompressMomento { get; set; } - public bool SleepMomento { get; set; } - public bool RunRedis { get; set; } - public bool CompressRedis { get; set; } -} - -public record struct GetResult( - CacheGetResponse Response, - long ResponseSize, - long DecompressedResponseSize, - long ElapsedMillis, - long ElapsedMillisWithDecompression -); - -public record struct SetResult(CacheSetResponse Response, long ElapsedMillis); - -public record struct RedisGetResult(RedisValue Response, long ElapsedMillis, long ElapsedMillisWithDecompression); - -public record struct RedisSetResult(bool Response, long ElapsedMillis); - -public class Function -{ - const string CacheName = "MomentoLambda"; - const string RedisClusterEndpoint = "momentoredisexamplecluster.exmof5.ng.0001.usw2.cache.amazonaws.com:6379"; - private int _numMomentoGetRequests = 10; - private int _numMomentoSetRequests = 10; - private int _numRedisGetRequests = 10; - private int _numRedisSetRequests = 10; - - /// - /// Function Handler for running Momento Requests - /// - /// - /// - /// - public async Task FunctionHandler(Input input, ILambdaContext context) - { - await new Function().DoStuff(input); - - return "Task completed"; - } - - private async Task DoStuff(Input input) { - - Console.WriteLine("Start executing DoStuff...."); - - // Create Momento client - ICredentialProvider authProvider = new EnvMomentoTokenProvider("MOMENTO_AUTH_TOKEN"); - var momentoClient = new CacheClient( - Configurations.InRegion.Lambda.Latest().WithClientTimeout(TimeSpan.FromSeconds(3000)), - authProvider, - TimeSpan.FromSeconds(30) - ); - - // Create a Redis client - Console.WriteLine("Creating redis client"); - var configurationOptions = new ConfigurationOptions - { - EndPoints = { RedisClusterEndpoint } - }; - ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - - // Instantiate MomentoCache and RedisCache - MomentoCache momentoCache = new MomentoCache(momentoClient, CacheName); - RedisCache redisCache = new RedisCache(redis); - - // Create momento cache if not already exists - await momentoCache.CreateMomentoCache(); - - // Ping redis client - redisCache.PingRedis(); - - await ExecuteLambda(input, momentoCache, redisCache); - - // Close the redis connection - await redis.CloseAsync(); - - Console.WriteLine("End executing DoStuff"); - - return "Task completed!"; - } - - private async Task ExecuteLambda(Input input, MomentoCache momentoCache, RedisCache redisCache) - { - Console.WriteLine("Inside Execute Lambda function"); - Console.WriteLine($"Input {input}"); - - List> momentoSetTasks; - List> momentoGetTasks; - List> redisSetTasks; - List> redisGetTasks; - - momentoSetTasks = input.RunMomento ? await momentoCache.DoMomentoSets(_numMomentoSetRequests, withSleep: input.SleepMomento) : new List>(); - redisSetTasks = input.RunRedis ? await redisCache.DoRedisSets(_numRedisSetRequests) : new List>(); - momentoGetTasks = input.RunMomento ? await momentoCache.DoMomentoGets(_numMomentoGetRequests, compressValue: input.CompressMomento, withSleep: input.SleepMomento) : new List>(); - redisGetTasks = input.RunRedis ? await redisCache.DoRedisGets(_numRedisGetRequests, compressValue: input.CompressRedis) : new List>(); - - Console.WriteLine("Awaiting pending tasks"); - // empty lists should no-op - Task.WaitAll(momentoSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisSetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(momentoGetTasks.Select(task => (Task)task).ToArray()); - Task.WaitAll(redisGetTasks.Select(task => (Task)task).ToArray()); - Console.Write("Done awaiting tasks"); - - if (input.RunMomento) { - momentoCache.LogMomentoSetResult(momentoSetTasks); - momentoCache.LogMomentoGetResult(momentoGetTasks, compressValue: input.CompressMomento); - } - if (input.RunRedis) { - redisCache.LogRedisSetResult(redisSetTasks); - redisCache.LogRedisGetResult(redisGetTasks, compressValue: input.CompressRedis); - } - - return "Lambda Execution Complete"; - } - - static void Main() { - try { - Console.WriteLine("Calling DoStuff"); - var input = new Input - { - RunMomento = true, - CompressMomento = false, - SleepMomento = false, - RunRedis = false, - CompressRedis = false - }; - var task = new Function().DoStuff(input); - Console.WriteLine("Waiting for task via task.Result"); - Console.WriteLine($"RESULT: {task.Result}"); - } catch(Exception ex) { - Console.WriteLine("Caught Exception"); - Console.WriteLine(ex); - } - } - -} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs deleted file mode 100644 index 5be1ccf2..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoCache.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System.Diagnostics; -using Momento.Sdk; -using Momento.Sdk.Responses; - -namespace MomentoRedisExampleLambdaHandler; - -public class MomentoCache -{ - private string _cacheName; - private CacheClient _client; - - public MomentoCache(CacheClient client, string cacheName) - { - _client = client; - _cacheName = cacheName; - } - - public async Task CreateMomentoCache() - { - var response = await _client.CreateCacheAsync(_cacheName); - - switch (response) - { - case CreateCacheResponse.Success: - Console.WriteLine($"\t Cache: {_cacheName} created successfully."); - break; - case CreateCacheResponse.CacheAlreadyExists: - Console.WriteLine($"\t Cache: {_cacheName} already exists."); - break; - case CreateCacheResponse.Error: - Console.WriteLine($"\t Error creating cache: {_cacheName}"); - break; - } - } - - public async Task>> DoMomentoSets(int numMomentoSetRequests, bool withSleep = false) - { - Console.WriteLine($"\t WITH SLEEP flag: {withSleep}"); - try - { - List> momentoSetTasks = new List>(); - string sourceData = await Utils.GetSourceData(); - Console.WriteLine("Executing MomentoSets"); - - byte[] compressedSourceData = Compression.Compress(sourceData); - - for (int i = 1; i <= numMomentoSetRequests; i++) - { - Console.WriteLine("Setting inside the loop"); - string key = $"key-{i}"; - momentoSetTasks.Add(ExecuteSet(key, compressedSourceData, withSleep)); - } - - return momentoSetTasks; - } - catch (Exception e) - { - Console.WriteLine("Exception in set " + e); - throw new Exception(); - } - } - - private async Task ExecuteSet(string key, byte[] value, bool withSleep) - { - Console.WriteLine($"Beginning set request for {key}"); - var stopWatch = Stopwatch.StartNew(); - var setResponseTask = _client.SetAsync(_cacheName, key, value, TimeSpan.FromMinutes(30)); - Console.WriteLine($"\tIssued set request for {key}"); - var setResponse = await setResponseTask; - Console.WriteLine($"\tDone awaiting set response for {key}"); - - if (withSleep) - { - await Task.Delay(500); - Console.WriteLine($"SET returned from sleeping 500ms for key {key}"); - } - - stopWatch.Stop(); - var duration = stopWatch.ElapsedMilliseconds; - Console.WriteLine($"\tReturning set response for {key}: {setResponse}"); - return new SetResult(Response: setResponse, ElapsedMillis: duration); - } - -#pragma warning disable CS1998 - public async Task>> DoMomentoGets(int numMomentoGetRequests, bool compressValue, bool withSleep = false) { -#pragma warning restore CS1998 - List> momentoGetTasks = new List>(); - - for (int i = 1; i <= numMomentoGetRequests; i++) - { - Console.WriteLine("Executing MomentoGets"); - string key = $"key-{i}"; - momentoGetTasks.Add(ExecuteGet(key, compressValue, withSleep)); - } - - return momentoGetTasks; - } - - private async Task ExecuteGet(string key, bool compressValue, bool withSleep) - { - var withCompressionStopWatch = new Stopwatch(); - Console.WriteLine($"Beginning get request for {key}"); - var stopWatch = Stopwatch.StartNew(); - if (compressValue) - { - withCompressionStopWatch = Stopwatch.StartNew(); - } - var getResponseTask = _client.GetAsync(_cacheName, key); - Console.WriteLine($"\tIssued get request for {key}"); - var getResponse = await getResponseTask; - Console.WriteLine($"\tDone awaiting get response for {key}"); - - if (withSleep) - { - await Task.Delay(500); - Console.WriteLine($"GET returned from sleeping 500ms for key {key}"); - } - - stopWatch.Stop(); - var responseElapsedMillis = stopWatch.ElapsedMilliseconds; - long withDecompressionElapsedMillis = 0; - long responseSize = 0; - long decompressedResponseSize = 0; - if (getResponse is CacheGetResponse.Hit hitResponse) - { - Console.WriteLine($"\tResponse for {key} is a hit; decompressing"); - responseSize = hitResponse.ValueByteArray.Length; - if (compressValue) - { - var decompressed = Compression.Decompress(hitResponse.ValueByteArray); - Console.WriteLine($"\tResponse finished decompressing for {key}"); - decompressedResponseSize = decompressed.Length; - withCompressionStopWatch.Stop(); - withDecompressionElapsedMillis = withCompressionStopWatch.ElapsedMilliseconds; - } - - } - else - { - Console.WriteLine( - $"\n\nGOT SOMETHING BESIDES A HIT FOR KEY {key}; PROBABLY SHOULDN'T USE THIS DATA\n\n"); - } - - var getResult = new GetResult( - Response: getResponse, - ResponseSize: responseSize, - DecompressedResponseSize: decompressedResponseSize, - ElapsedMillis: responseElapsedMillis, - ElapsedMillisWithDecompression: withDecompressionElapsedMillis - ); - Console.WriteLine($"\tReturning get response for {key}: {getResult}"); - return getResult; - } - - public async void LogMomentoSetResult(List> momentoSetTasks) - { - Console.WriteLine("------- MOMENTO SET RESULT -------"); - foreach(var setTask in momentoSetTasks) - { - var setResult = await setTask; - if (setResult.Response is CacheSetResponse.Error err) { - Console.WriteLine("ERROR: " + err.Message); - } else if (setResult.Response is CacheSetResponse.Success) { - Console.WriteLine("Set in " + setResult.ElapsedMillis); - } - } - } - - public async void LogMomentoGetResult(List> momentoGetTasks, bool compressValue) - { - Console.WriteLine("------- MOMENTO GET RESULT -------"); - - foreach(var task in momentoGetTasks) - { - var getResult = await task; - if (getResult.Response is CacheGetResponse.Miss) { - Console.WriteLine($"Unexpected MISS for result: {getResult}"); - } else if (getResult.Response is CacheGetResponse.Error) { - Console.WriteLine($"ERROR: {getResult}"); - } else if (getResult.Response is CacheGetResponse.Hit) - { - Console.WriteLine(!compressValue - ? $"Got HIT for: {getResult.ResponseSize} in {getResult.ElapsedMillis}" - : $"Got HIT after decompressing for: {getResult.DecompressedResponseSize} in {getResult.ElapsedMillisWithDecompression}"); - } - } - } -} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj deleted file mode 100644 index facc726c..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/MomentoRedisExampleLambdaHandler.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - net6.0 - Exe - enable - enable - true - Lambda - - true - - true - - - - - - - - - \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md deleted file mode 100644 index 4ed9e5a8..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Readme.md +++ /dev/null @@ -1,49 +0,0 @@ -# AWS Lambda Empty Function Project - -This starter project consists of: -* Function.cs - class file containing a class with a single function handler method -* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS - -You may also have a test project depending on the options selected. - -The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. - -## Here are some steps to follow from Visual Studio: - -To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. - -To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. - -To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. - -To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. - -To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. - -To view execution logs of invocations of your function use the Logs tab in the opened Function View window. - -## Here are some steps to follow to get started from the command line: - -Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. - -Install Amazon.Lambda.Tools Global Tools if not already installed. -``` - dotnet tool install -g Amazon.Lambda.Tools -``` - -If already installed check if new version is available. -``` - dotnet tool update -g Amazon.Lambda.Tools -``` - -Execute unit tests -``` - cd "MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests" - dotnet test -``` - -Deploy function to AWS Lambda -``` - cd "MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler" - dotnet lambda deploy-function -``` diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs deleted file mode 100644 index e12620e6..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/RedisCache.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System.Diagnostics; -using StackExchange.Redis; - -namespace MomentoRedisExampleLambdaHandler; - -public class RedisCache -{ - private IDatabase _db; - public RedisCache(ConnectionMultiplexer redis) - { - _db = redis.GetDatabase(); - } - public void PingRedis() { - // Check/Ping the redis server - Console.WriteLine("Pinging db"); - var pong = _db.Ping(); - Console.WriteLine(pong); - } - - public async Task>> DoRedisSets(int numRedisSetRequests) - { - Console.WriteLine("Executing Redis Sets"); - try - { - List> redisSetTasks = new List>(); - string sourceData = await Utils.GetSourceData(); - Console.WriteLine("Executing RedisSets"); - - byte[] compressedSourceData = Compression.Compress(sourceData); - - for (int i = 1; i <= numRedisSetRequests; i++) - { - Console.WriteLine("Setting inside the loop"); - string key = $"key-{i}"; - redisSetTasks.Add(ExecuteSet(key, compressedSourceData)); - } - - return redisSetTasks; - } - catch (Exception e) - { - Console.WriteLine("Exception in set " + e); - throw new Exception(); - } - } - - private async Task ExecuteSet(string key, byte[] value) - { - Console.WriteLine($"Beginning redis set request for {key}"); - var stopWatch = Stopwatch.StartNew(); - var setResponseTask = _db.StringSetAsync(key, value); - Console.WriteLine($"\tIssued redis set request for {key}"); - var setResponse = await setResponseTask; - Console.WriteLine($"\tDone awaiting redis set response for {key}"); - stopWatch.Stop(); - var duration = stopWatch.ElapsedMilliseconds; - // Console.WriteLine($"\tReturning redis set response for {key}: {setResponse}"); - Console.WriteLine($"\tReturning redis set response for {key}"); - return new RedisSetResult(Response: setResponse, ElapsedMillis: duration); - } - -#pragma warning disable CS1998 - public async Task>> DoRedisGets(int numRedisGetRequests, bool compressValue) -#pragma warning restore CS1998 - { - Console.WriteLine("Executing Redis Gets"); - List> redisGetTasks = new List>(); - - for (int i = 1; i <= numRedisGetRequests; i++) - { - Console.WriteLine("Executing RedisGets"); - string key = $"key-{i}"; - redisGetTasks.Add(ExecuteGet(key, compressValue)); - } - - return redisGetTasks; - } - - private async Task ExecuteGet(string key, bool compressValue) - { - - Console.WriteLine($"Beginning redis get request for {key}"); - var withCompressionStopWatch = new Stopwatch(); - var stopWatch = Stopwatch.StartNew(); - if (compressValue) - { - withCompressionStopWatch = Stopwatch.StartNew(); - } - var getResponseTask = _db.StringGetAsync(key); - Console.WriteLine($"\tIssued redis get request for {key}"); - var getResponse = await getResponseTask; - Console.WriteLine($"\tDone awaiting redis get response for {key}"); - stopWatch.Stop(); - var responseElapsedMillis = stopWatch.ElapsedMilliseconds; - long withDecompressionElapsedMillis = 0; - - if (compressValue) - { - if (getResponse.HasValue) - { - var decompressed = Compression.Decompress(getResponse!); - Console.WriteLine($"\tResponse finished decompressing for {key}"); - withCompressionStopWatch.Stop(); - withDecompressionElapsedMillis = withCompressionStopWatch.ElapsedMilliseconds; - } - else - { - Console.WriteLine($"\tValue not found for {key}"); - } - } - - var getResult = new RedisGetResult( - Response: getResponse, - ElapsedMillis: responseElapsedMillis, - ElapsedMillisWithDecompression: withDecompressionElapsedMillis - ); - // Console.WriteLine($"\tReturning get response for {key}: {getResult}"); - Console.WriteLine($"\tReturning get response for {key}"); - return getResult; - } - - public async void LogRedisSetResult(List> redisSetTasks) - { - Console.WriteLine("------- REDIS SET RESULT -------"); - foreach(var setTask in redisSetTasks) - { - var setResult = await setTask; - Console.WriteLine($"Set response in {setResult.ElapsedMillis}"); - } - } - - public async void LogRedisGetResult(List> redisGetTasks, bool compressValue) - { - Console.WriteLine("------- REDIS GET RESULT -------"); - foreach(var getTask in redisGetTasks) - { - var getResult = await getTask; - Console.WriteLine(compressValue - ? $"Got response with compression in {getResult.ElapsedMillisWithDecompression}" - : $"Got response in {getResult.ElapsedMillis}"); - } - } -} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs deleted file mode 100644 index 627100bb..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/Utils.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Amazon.S3; -using Amazon.S3.Model; - -namespace MomentoRedisExampleLambdaHandler; - -public class Utils -{ - private static IAmazonS3? _s3Client; - private static readonly string BucketName = "my-super-secret-bucket"; - private static readonly string ObjectKey = "super-secret-source-data.json"; - - public static async Task GetSourceData() - { - string sourceData; - try - { - // Create Amazon S3 Client - _s3Client = new AmazonS3Client(); - GetObjectRequest request = new GetObjectRequest - { - BucketName = BucketName, - Key = ObjectKey - }; - - using (GetObjectResponse response = await _s3Client.GetObjectAsync(request)) - { - // Read the object content - using (StreamReader reader = new StreamReader(response.ResponseStream)) - { - sourceData = await reader.ReadToEndAsync(); - } - } - - return sourceData; - } - catch (Exception ex) - { - Console.WriteLine("Error reading from S3: " + ex.Message); - throw; - } - } -} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json deleted file mode 100644 index df66d700..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/aws-lambda-tools-defaults.json +++ /dev/null @@ -1,16 +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-architecture": "x86_64", - "function-runtime": "dotnet6", - "function-memory-size": 256, - "function-timeout": 30, - "function-handler": "MomentoRedisExampleLambdaHandler::MomentoRedisExampleLambdaHandler.Function::FunctionHandler" -} \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs deleted file mode 100644 index 3d32e68b..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/FunctionTest.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Xunit; -using Amazon.Lambda.Core; -using Amazon.Lambda.TestUtilities; - -namespace MomentoRedisExampleLambdaHandler.Tests; - -public class FunctionTest -{ - [Fact] - public void TestToUpperFunction() - { - - // Invoke the lambda function and confirm the string was upper cased. - var function = new Function(); - var context = new TestLambdaContext(); - var upperCase = function.FunctionHandler("hello world", context); - - Assert.Equal("HELLO WORLD", upperCase); - } -} diff --git a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj b/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj deleted file mode 100644 index f53e8d6e..00000000 --- a/examples/MomentoRedisLambdaExample/MomentoRedisExampleLambdaHandler/test/MomentoRedisExampleLambdaHandler.Tests/MomentoRedisExampleLambdaHandler.Tests.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - net6.0 - enable - enable - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/README.md b/examples/MomentoRedisLambdaExample/README.md deleted file mode 100644 index f28e4d55..00000000 --- a/examples/MomentoRedisLambdaExample/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Welcome to your CDK C# project! - -This is a blank project for CDK development with C#. - -The `cdk.json` file tells the CDK Toolkit how to execute your app. - -It uses the [.NET CLI](https://docs.microsoft.com/dotnet/articles/core/) to compile and execute your project. - -## Useful commands - -* `dotnet build src` compile this app -* `cdk deploy` deploy this stack to your default AWS account/region -* `cdk diff` compare deployed stack with current state -* `cdk synth` emits the synthesized CloudFormation template \ No newline at end of file diff --git a/examples/MomentoRedisLambdaExample/cdk.context.json b/examples/MomentoRedisLambdaExample/cdk.context.json deleted file mode 100644 index 07322898..00000000 --- a/examples/MomentoRedisLambdaExample/cdk.context.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "vpc-provider:account=287427698164:filter.vpc-id=vpc-00e94e9613dde8d21:region=us-west-2:returnAsymmetricSubnets=true": { - "vpcId": "vpc-00e94e9613dde8d21", - "vpcCidrBlock": "172.31.0.0/16", - "ownerAccountId": "287427698164", - "availabilityZones": [], - "subnetGroups": [ - { - "name": "Public", - "type": "Public", - "subnets": [ - { - "subnetId": "subnet-04b581aed6af02515", - "cidr": "172.31.32.0/20", - "availabilityZone": "us-west-2a", - "routeTableId": "rtb-0a2470cafd0b7bd73" - }, - { - "subnetId": "subnet-09e0ce2f2c6b2faac", - "cidr": "172.31.16.0/20", - "availabilityZone": "us-west-2b", - "routeTableId": "rtb-0a2470cafd0b7bd73" - }, - { - "subnetId": "subnet-00482a2a73a2a56de", - "cidr": "172.31.0.0/20", - "availabilityZone": "us-west-2c", - "routeTableId": "rtb-0a2470cafd0b7bd73" - }, - { - "subnetId": "subnet-0c5efae5cc62020bc", - "cidr": "172.31.48.0/20", - "availabilityZone": "us-west-2d", - "routeTableId": "rtb-0a2470cafd0b7bd73" - } - ] - } - ] - }, - "availability-zones:account=287427698164:region=us-west-2": [ - "us-west-2a", - "us-west-2b", - "us-west-2c", - "us-west-2d" - ] -} diff --git a/examples/MomentoRedisLambdaExample/cdk.json b/examples/MomentoRedisLambdaExample/cdk.json deleted file mode 100644 index 27f865c3..00000000 --- a/examples/MomentoRedisLambdaExample/cdk.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "app": "dotnet run --project src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj", - "watch": { - "include": [ - "**" - ], - "exclude": [ - "README.md", - "cdk*.json", - "src/*/obj", - "src/*/bin", - "src/*.sln", - "src/*/GlobalSuppressions.cs", - "src/*/*.csproj" - ] - }, - "context": { - "@aws-cdk/aws-lambda:recognizeLayerVersion": true, - "@aws-cdk/core:checkSecretUsage": true, - "@aws-cdk/core:target-partitions": [ - "aws", - "aws-cn" - ], - "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, - "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, - "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, - "@aws-cdk/aws-iam:minimizePolicies": true, - "@aws-cdk/core:validateSnapshotRemovalPolicy": true, - "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, - "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, - "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, - "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, - "@aws-cdk/core:enablePartitionLiterals": true, - "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, - "@aws-cdk/aws-iam:standardizedServicePrincipals": true, - "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, - "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, - "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, - "@aws-cdk/aws-route53-patters:useCertificate": true, - "@aws-cdk/customresources:installLatestAwsSdkDefault": false, - "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, - "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, - "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, - "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, - "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, - "@aws-cdk/aws-redshift:columnId": true, - "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, - "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, - "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, - "@aws-cdk/aws-kms:aliasNameRef": true - } -} diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln deleted file mode 100644 index ca600f61..00000000 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample.sln +++ /dev/null @@ -1,34 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 -MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MomentoRedisLambdaExample", "MomentoRedisLambdaExample\MomentoRedisLambdaExample.csproj", "{156AEF6B-F9DA-42DB-806A-CDC179673456}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|Any CPU.Build.0 = Debug|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x64.ActiveCfg = Debug|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x64.Build.0 = Debug|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x86.ActiveCfg = Debug|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Debug|x86.Build.0 = Debug|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|Any CPU.ActiveCfg = Release|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|Any CPU.Build.0 = Release|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x64.ActiveCfg = Release|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x64.Build.0 = Release|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x86.ActiveCfg = Release|Any CPU - {156AEF6B-F9DA-42DB-806A-CDC179673456}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs deleted file mode 100644 index 26233fcb..00000000 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/GlobalSuppressions.cs +++ /dev/null @@ -1 +0,0 @@ -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "Constructs add themselves to the scope in which they are created")] diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj deleted file mode 100644 index dad278f5..00000000 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExample.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - Exe - net6.0 - - Major - - - - - - - - - - - diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs deleted file mode 100644 index 77ee73af..00000000 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/MomentoRedisLambdaExampleStack.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Amazon.CDK; -using Amazon.CDK.AWS.Lambda; -using Constructs; -using Amazon.CDK.AWS.IAM; -using Amazon.CDK.AWS.EC2; - -namespace MomentoRedisLambdaExample -{ - public class MomentoRedisLambdaExampleStack : Stack - { - internal MomentoRedisLambdaExampleStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) - { - var vpc = new Vpc(this, "VPC", new VpcProps - { - SubnetConfiguration = new ISubnetConfiguration[] { - new SubnetConfiguration{ - Name = "public-subnet", - SubnetType = SubnetType.PUBLIC, - CidrMask = 24, - }, - new SubnetConfiguration{ - Name = "private-subnet", - SubnetType = SubnetType.PRIVATE_WITH_EGRESS, - CidrMask = 24, - }, - } - // maxAzs: 2, - // natGateways: 2, - }); - - var privateSubnet = Subnet.FromSubnetId(this, "PrivateSubnet", "subnet-07fff86b0e418963c"); // Specify the desired private subnet ID - - // Create the IAM role for the Lambda function - Role lambdaRole = new Role(this, "LambdaRole", new RoleProps - { - AssumedBy = new ServicePrincipal("lambda.amazonaws.com"), - RoleName = "MomentoRedisExampleLambdaRole" - }); - - // Attach the managed policies - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")); - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonEC2FullAccess")); - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonElastiCacheFullAccess")); - lambdaRole.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName("AmazonS3FullAccess")); - - var MOMENTO_AUTH_TOKEN = "replace with your momento auth token"; - - Function fn1 = new Function(this, "MomentoRedisLambdaExampleHandler", new FunctionProps - { - Runtime = Runtime.DOTNET_6, - Code = Code.FromAsset("./MomentoRedisExampleLambdaHandler/src/MomentoRedisExampleLambdaHandler/bin/Release/net6.0/publish"), - Handler = "MomentoRedisExampleLambdaHandler::MomentoRedisExampleLambdaHandler.Function::FunctionHandler", - FunctionName = "MomentoRedisLambdaExampleHandler", - MemorySize = 1024, - Timeout = Duration.Seconds(300), - Role = lambdaRole, - Vpc = vpc, - VpcSubnets = new SubnetSelection { Subnets = new[] { privateSubnet } }, - Environment = new System.Collections.Generic.Dictionary - { - { "MOMENTO_AUTH_TOKEN", MOMENTO_AUTH_TOKEN} - } - }); - } - } -} diff --git a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs b/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs deleted file mode 100644 index 0fea7a5d..00000000 --- a/examples/MomentoRedisLambdaExample/src/MomentoRedisLambdaExample/Program.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Amazon.CDK; - -namespace MomentoRedisLambdaExample -{ - sealed class Program - { - public static void Main(string[] args) - { - var app = new App(); - new MomentoRedisLambdaExampleStack(app, "MomentoRedisLambdaExampleStack", new StackProps - { - Env = new Environment - { - Account = Aws.ACCOUNT_ID, - Region = Aws.REGION - } - }); - app.Synth(); - } - } -} From ced1fd72632010137c632f9ea3c33ee6503315e9 Mon Sep 17 00:00:00 2001 From: pgautier404 Date: Wed, 19 Jul 2023 13:32:16 -0700 Subject: [PATCH 16/16] feat: add ItemGetTtl operation (#458) * feat: add ItemGetTtl operation * fix: expose itemGetTtl value as a TimeSpan * fix: fix TimeSpan test assertions --- src/Momento.Sdk/CacheClient.cs | 38 +++++++ src/Momento.Sdk/ICacheClient.cs | 13 ++- src/Momento.Sdk/Internal/DataGrpcManager.cs | 7 ++ src/Momento.Sdk/Internal/ScsDataClient.cs | 45 +++++++- .../Responses/CacheItemGetTtlResponse.cs | 103 ++++++++++++++++++ .../Momento.Sdk.Tests/CacheDataTest.cs | 1 - .../Integration/Momento.Sdk.Tests/TtlTest.cs | 46 ++++++++ 7 files changed, 249 insertions(+), 4 deletions(-) create mode 100644 src/Momento.Sdk/Responses/CacheItemGetTtlResponse.cs diff --git a/src/Momento.Sdk/CacheClient.cs b/src/Momento.Sdk/CacheClient.cs index 5bcd55d2..049694e4 100644 --- a/src/Momento.Sdk/CacheClient.cs +++ b/src/Momento.Sdk/CacheClient.cs @@ -184,6 +184,44 @@ public async Task UpdateTtlAsync(string cacheName, strin return await this.DataClient.UpdateTtlAsync(cacheName, key, ttl); } + /// + public async Task ItemGetTtlAsync(string cacheName, byte[] key) + { + try + { + Utils.ArgumentNotNull(cacheName, nameof(cacheName)); + Utils.ArgumentNotNull(key, nameof(key)); + } + catch (ArgumentNullException e) + { + return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message)); + } + catch (ArgumentOutOfRangeException e) + { + return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message)); + } + return await this.DataClient.ItemGetTtlAsync(cacheName, key); + } + + /// + public async Task ItemGetTtlAsync(string cacheName, string key) + { + try + { + Utils.ArgumentNotNull(cacheName, nameof(cacheName)); + Utils.ArgumentNotNull(key, nameof(key)); + } + catch (ArgumentNullException e) + { + return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message)); + } + catch (ArgumentOutOfRangeException e) + { + return new CacheItemGetTtlResponse.Error(new InvalidArgumentException(e.Message)); + } + return await this.DataClient.ItemGetTtlAsync(cacheName, key); + } + /// public async Task SetAsync(string cacheName, byte[] key, byte[] value, TimeSpan? ttl = null) { diff --git a/src/Momento.Sdk/ICacheClient.cs b/src/Momento.Sdk/ICacheClient.cs index 343bc876..ada9b5a4 100644 --- a/src/Momento.Sdk/ICacheClient.cs +++ b/src/Momento.Sdk/ICacheClient.cs @@ -172,6 +172,17 @@ public interface ICacheClient : IDisposable /// public Task UpdateTtlAsync(string cacheName, string key, TimeSpan ttl); + /// + /// Get the TTL of a cache item. + /// + /// The name of the cache to perform the lookup in. + /// The key to get the TTL for. + /// Task representing the result of the item get TTL operation. + public Task ItemGetTtlAsync(string cacheName, byte[] key); + + /// + public Task ItemGetTtlAsync(string cacheName, string key); + /// /// Set the value in cache with a given time to live (TTL) seconds. /// @@ -531,7 +542,7 @@ public interface ICacheClient : IDisposable /// The set to fetch. /// Task representing with the status of the fetch operation and the associated set. public Task SetFetchAsync(string cacheName, string setName); - + /// /// Calculate the length of a set in the cache. /// diff --git a/src/Momento.Sdk/Internal/DataGrpcManager.cs b/src/Momento.Sdk/Internal/DataGrpcManager.cs index 6a471ea3..fc3fad3e 100644 --- a/src/Momento.Sdk/Internal/DataGrpcManager.cs +++ b/src/Momento.Sdk/Internal/DataGrpcManager.cs @@ -24,6 +24,7 @@ public interface IDataClient { public Task<_KeysExistResponse> KeysExistAsync(_KeysExistRequest request, CallOptions callOptions); public Task<_UpdateTtlResponse> UpdateTtlAsync(_UpdateTtlRequest request, CallOptions callOptions); + public Task<_ItemGetTtlResponse> ItemGetTtlAsync(_ItemGetTtlRequest request, CallOptions callOptions); public Task<_GetResponse> GetAsync(_GetRequest request, CallOptions callOptions); public Task<_SetResponse> SetAsync(_SetRequest request, CallOptions callOptions); public Task<_DeleteResponse> DeleteAsync(_DeleteRequest request, CallOptions callOptions); @@ -84,6 +85,12 @@ public async Task<_UpdateTtlResponse> UpdateTtlAsync(_UpdateTtlRequest request, return await wrapped.ResponseAsync; } + public async Task<_ItemGetTtlResponse> ItemGetTtlAsync(_ItemGetTtlRequest request, CallOptions callOptions) + { + var wrapped = await _middlewares.WrapRequest(request, callOptions, (r, o) => _generatedClient.ItemGetTtlAsync(r, o)); + return await wrapped.ResponseAsync; + } + public async Task<_DeleteResponse> DeleteAsync(_DeleteRequest request, CallOptions callOptions) { var wrapped = await _middlewares.WrapRequest(request, callOptions, (r, o) => _generatedClient.DeleteAsync(r, o)); diff --git a/src/Momento.Sdk/Internal/ScsDataClient.cs b/src/Momento.Sdk/Internal/ScsDataClient.cs index fb89fcce..b120cf5b 100644 --- a/src/Momento.Sdk/Internal/ScsDataClient.cs +++ b/src/Momento.Sdk/Internal/ScsDataClient.cs @@ -106,6 +106,16 @@ public async Task UpdateTtlAsync(string cacheName, strin return await this.SendUpdateTtlAsync(cacheName, key: key.ToByteString(), ttl: ttl); } + public async Task ItemGetTtlAsync(string cacheName, byte[] key) + { + return await this.SendItemGetTtlAsync(cacheName, key: key.ToByteString()); + } + + public async Task ItemGetTtlAsync(string cacheName, string key) + { + return await this.SendItemGetTtlAsync(cacheName, key: key.ToByteString()); + } + public async Task SetAsync(string cacheName, byte[] key, byte[] value, TimeSpan? ttl = null) { return await this.SendSetAsync(cacheName, key: key.ToByteString(), value: value.ToByteString(), ttl: ttl); @@ -307,7 +317,7 @@ public async Task SetFetchAsync(string cacheName, string { return await SendSetFetchAsync(cacheName, setName); } - + public async Task SetLengthAsync(string cacheName, string setName) { return await SendSetLengthAsync(cacheName, setName); @@ -468,6 +478,37 @@ private async Task SendUpdateTtlAsync(string cacheName, } } + const string REQUEST_TYPE_ITEM_GET_TTL = "ITEM_GET_TTL"; + private async Task SendItemGetTtlAsync(string cacheName, ByteString key) + { + _ItemGetTtlRequest request = new _ItemGetTtlRequest() { CacheKey = key }; + _ItemGetTtlResponse response; + var metadata = MetadataWithCache(cacheName); + try + { + this._logger.LogTraceExecutingRequest(REQUEST_TYPE_UPDATE_TTL, cacheName, key, null, null); + response = await this.grpcManager.Client.ItemGetTtlAsync(request, new CallOptions(headers: metadata, deadline: CalculateDeadline())); + } + catch (Exception e) + { + return this._logger.LogTraceRequestError(REQUEST_TYPE_UPDATE_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Error(_exceptionMapper.Convert(e, metadata))); + } + + if (response.ResultCase == _ItemGetTtlResponse.ResultOneofCase.Missing) + { + return this._logger.LogTraceRequestSuccess(REQUEST_TYPE_ITEM_GET_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Miss()); + } + else if (response.ResultCase == _ItemGetTtlResponse.ResultOneofCase.Found) + { + return this._logger.LogTraceRequestSuccess(REQUEST_TYPE_ITEM_GET_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Hit(response)); + } + else + { + return this._logger.LogTraceRequestError(REQUEST_TYPE_ITEM_GET_TTL, cacheName, key, null, null, new CacheItemGetTtlResponse.Error( + _exceptionMapper.Convert(new Exception("Unknown response type"), metadata))); + } + } + const string REQUEST_TYPE_SET = "SET"; private async Task SendSetAsync(string cacheName, ByteString key, ByteString value, TimeSpan? ttl = null) { @@ -939,7 +980,7 @@ private async Task SendSetFetchAsync(string cacheName, st return this._logger.LogTraceCollectionRequestSuccess(REQUEST_TYPE_SET_FETCH, cacheName, setName, new CacheSetFetchResponse.Miss()); } - + const string REQUEST_TYPE_SET_LENGTH = "SET_LENGTH"; private async Task SendSetLengthAsync(string cacheName, string setName) { diff --git a/src/Momento.Sdk/Responses/CacheItemGetTtlResponse.cs b/src/Momento.Sdk/Responses/CacheItemGetTtlResponse.cs new file mode 100644 index 00000000..dd6bdd7b --- /dev/null +++ b/src/Momento.Sdk/Responses/CacheItemGetTtlResponse.cs @@ -0,0 +1,103 @@ +namespace Momento.Sdk.Responses; + +using System; +using Momento.Protos.CacheClient; +using Momento.Sdk.Exceptions; + +/// +/// Parent response type for a cache item get ttl request. The +/// response object is resolved to a type-safe object of one of +/// the following subtypes: +/// +/// CacheItemGetTtlResponse.Hit +/// CacheItemGetTtlResponse.Miss +/// CacheItemGetTtlResponse.Error +/// +/// Pattern matching can be used to operate on the appropriate subtype. +/// For example: +/// +/// if (response is CacheItemGetTtlResponse.Hit hitResponse) +/// { +/// // handle ttl value as appropriate +/// } +/// else if (response is CacheItemGetTtlResponse.Miss missResponse) +/// { +/// // handle key was not found as appropriate +/// } +/// else if (response is CacheItemGetTtlResponse.Error errorResponse) +/// { +/// // handle error as appropriate +/// } +/// else +/// { +/// // handle unexpected response +/// } +/// +/// +public abstract class CacheItemGetTtlResponse +{ + /// + /// Indicates the key was found in the cache and the ttl was returned. + /// + public class Hit : CacheItemGetTtlResponse { + /// + /// The value of the ttl. + /// + protected readonly ulong value; + + /// + public Hit(_ItemGetTtlResponse response) + { + value = response.Found.RemainingTtlMillis; + } + + /// + /// The value of the ttl. + /// + public TimeSpan Value + { + get => TimeSpan.FromMilliseconds(value); + } + + /// + public override string ToString() + { + return $"{base.ToString()}: Value: {Value}"; + } + } + + /// + /// Indicates the key was not found in the cache, hence the ttl was not returned. + /// + public class Miss : CacheItemGetTtlResponse { } + + /// + public class Error : CacheItemGetTtlResponse, IError + { + private readonly SdkException _error; + + /// + public Error(SdkException error) + { + _error = error; + } + + /// + public SdkException InnerException + { + get => _error; + } + + /// + public MomentoErrorCode ErrorCode + { + get => _error.ErrorCode; + } + + /// + public string Message + { + get => _error.Message; + } + } +} diff --git a/tests/Integration/Momento.Sdk.Tests/CacheDataTest.cs b/tests/Integration/Momento.Sdk.Tests/CacheDataTest.cs index 09794630..b45259e1 100644 --- a/tests/Integration/Momento.Sdk.Tests/CacheDataTest.cs +++ b/tests/Integration/Momento.Sdk.Tests/CacheDataTest.cs @@ -167,7 +167,6 @@ public async Task KeysExistAsync_String() Assert.Equal(expectedDict, goodResponse.ExistsDictionary); } - [Theory] [InlineData(null, new byte[] { 0x00 }, new byte[] { 0x00 })] [InlineData("cache", null, new byte[] { 0x00 })] diff --git a/tests/Integration/Momento.Sdk.Tests/TtlTest.cs b/tests/Integration/Momento.Sdk.Tests/TtlTest.cs index 3fe0dd2a..cd55c705 100644 --- a/tests/Integration/Momento.Sdk.Tests/TtlTest.cs +++ b/tests/Integration/Momento.Sdk.Tests/TtlTest.cs @@ -110,4 +110,50 @@ public async Task UpdateTtlAsync_KeyIsStringAndExists_IsSet() Assert.True(existsResponse is CacheKeyExistsResponse.Success, "exists response should be success"); Assert.False(((CacheKeyExistsResponse.Success)existsResponse).Exists, "Key should not exist"); } + + [Fact] + public async Task ItemGetTtl_HappyPath() + { + // Add an item with a minute ttl + string key = Utils.NewGuidString(); + var ttl = TimeSpan.FromSeconds(60); + var response = await client.SetAsync(cacheName, key, Utils.NewGuidString(), ttl); + Assert.True(response is CacheSetResponse.Success, $"Unexpected response: {response}"); + + var ttlResponse = await client.ItemGetTtlAsync(cacheName, key); + Assert.True(ttlResponse is CacheItemGetTtlResponse.Hit, $"Unexpected response: {ttlResponse}"); + var theTtl = ((CacheItemGetTtlResponse.Hit)ttlResponse).Value; + Assert.True(theTtl.TotalMilliseconds < 60000 && theTtl.TotalMilliseconds > 55000); + + await Task.Delay(1000); + + var ttlResponse2 = await client.ItemGetTtlAsync(cacheName, key); + Assert.True(ttlResponse2 is CacheItemGetTtlResponse.Hit, $"Unexpected response: {ttlResponse}"); + var theTtl2 = ((CacheItemGetTtlResponse.Hit)ttlResponse2).Value; + + Assert.True(theTtl2.TotalMilliseconds <= theTtl.TotalMilliseconds - 1000); + } + + [Fact] + public async Task ItemGetTtl_Miss() + { + var ttlResponse = await client.ItemGetTtlAsync(cacheName, Utils.NewGuidString()); + Assert.True(ttlResponse is CacheItemGetTtlResponse.Miss, $"Unexpected response: {ttlResponse}"); + } + + [Fact] + public async Task ItemGetTtl_NonexistentCacheError() + { + var ttlResponse = await client.ItemGetTtlAsync(Utils.NewGuidString(), Utils.NewGuidString()); + Assert.True(ttlResponse is CacheItemGetTtlResponse.Error, $"Unexpected response: {ttlResponse}"); + Assert.Equal(MomentoErrorCode.NOT_FOUND_ERROR, ((CacheItemGetTtlResponse.Error)ttlResponse).ErrorCode); + } + + [Fact] + public async Task ItemGetTtl_EmptyCacheNameError() + { + var ttlResponse = await client.ItemGetTtlAsync(null!, Utils.NewGuidString()); + Assert.True(ttlResponse is CacheItemGetTtlResponse.Error, $"Unexpected response: {ttlResponse}"); + Assert.Equal(MomentoErrorCode.INVALID_ARGUMENT_ERROR, ((CacheItemGetTtlResponse.Error)ttlResponse).ErrorCode); + } }