<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CDK Patterns</title>
    <description>The latest articles on DEV Community by CDK Patterns (@cdkpatterns).</description>
    <link>https://dev.to/cdkpatterns</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2688%2Fbf1ddf06-16c8-4aa2-a06c-46ceea34ae36.png</url>
      <title>DEV Community: CDK Patterns</title>
      <link>https://dev.to/cdkpatterns</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cdkpatterns"/>
    <language>en</language>
    <item>
      <title>Add Voice To Your Serverless Apps with Alexa Through AWS CDK</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Thu, 22 Oct 2020 13:23:55 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/add-voice-to-your-serverless-apps-with-alexa-through-aws-cdk-45n0</link>
      <guid>https://dev.to/cdkpatterns/add-voice-to-your-serverless-apps-with-alexa-through-aws-cdk-45n0</guid>
      <description>&lt;h2&gt;
  
  
  Introducing "The Alexa Skill" pattern at &lt;a href="https://cdkpatterns.com"&gt;CDK Patterns&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vu664zKz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h1tua03yx35jiwqs9w93.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vu664zKz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h1tua03yx35jiwqs9w93.png" alt="Alexa Skill Arch" width="494" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a community contribution by Chris Plankey which allows you to deploy an Alexa skill that is backed by a Lambda Function and a DynamoDB table. Out of the box the pattern will hold a short conversation where it will tell you a random selection of pattern names from cdk patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available Versions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-alexa-skill/typescript"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-alexa-skill/python"&gt;Python&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;//TypeScript
npx cdkp init the-alexa-skill

//Python
npx cdkp init the-alexa-skill &lt;span class="nt"&gt;--lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Unfortunately these steps cannot be skipped or shortened as you need to configure an Amazon developer account and acquire an OAuth 2.0 Refresh token that allows you to deploy your skill using CloudFormation.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Create an &lt;a href="https://developer.amazon.com/"&gt;Amazon Developer account&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Alexa is an Amazon product even though it can be deployed through AWS you still need to have a separate &lt;a href="https://developer.amazon.com/"&gt;Amazon Developer account&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a &lt;a href="https://developer.amazon.com/loginwithamazon/console/site/lwa/create-security-profile.html"&gt;Developer Account Security Profile&lt;/a&gt;.
&lt;/h3&gt;

&lt;p&gt;Open the &lt;a href="https://developer.amazon.com/loginwithamazon/console/site/lwa/create-security-profile.html"&gt;Developer Account Security Profile&lt;/a&gt; page and feel free to use whatever values you want for the Security Profile Name and Description. The Privacy Notice URL must be a valid URL format but does not need to be a valid URL. Once you create your security profile, navigate to the &lt;code&gt;Web Settings&lt;/code&gt; tab and add the following as &lt;code&gt;Allowed Return URLs&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://127.0.0.1:9090/cb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;https://s3.amazonaws.com/ask-cli/response_parser.html&lt;/code&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lETgcJBD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ivpz4wxjnji8ubbcvh94.png" alt="Security Profile" width="880" height="535"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Copy Your &lt;code&gt;Client Id&lt;/code&gt; and &lt;code&gt;Client Secret&lt;/code&gt; from the security profile
&lt;/h3&gt;

&lt;p&gt;Keep these values safe as we will use them in a second.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Make Sure You Have An AWS Account with CLI Access
&lt;/h3&gt;

&lt;p&gt;You will need this to deploy the CDK stack anyway but for the next step we need to associate Alexa with our AWS Account so this is crucial&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Setup ASK CLI on your local machine
&lt;/h3&gt;

&lt;p&gt;Alexa needs to associate your Amazon Developer Account with your AWS Account. The easiest way to do this is to run &lt;code&gt;ask configure&lt;/code&gt; after you have installed the &lt;a href="https://developer.amazon.com/en-US/docs/alexa/smapi/quick-start-alexa-skills-kit-command-line-interface.html"&gt;Alexa Skills Kit CLI&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Generate a Refresh Token
&lt;/h3&gt;

&lt;p&gt;We are going to use Postman to fetch a new &lt;code&gt;OAuth 2.0&lt;/code&gt; token&lt;/p&gt;

&lt;p&gt;Set the following key/values in the request:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Grant Type&lt;/td&gt;
&lt;td&gt;Authorization Code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Callback URL&lt;/td&gt;
&lt;td&gt;&lt;a href="http://127.0.0.1:9090/cb"&gt;http://127.0.0.1:9090/cb&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth URL&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.amazon.com/ap/oa"&gt;https://www.amazon.com/ap/oa&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access Token URL&lt;/td&gt;
&lt;td&gt;&lt;a href="https://api.amazon.com/auth/o2/token"&gt;https://api.amazon.com/auth/o2/token&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client ID&lt;/td&gt;
&lt;td&gt;{YOUR_CLIENT_ID}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client Secret&lt;/td&gt;
&lt;td&gt;{YOUR_CLIENT_SECRET}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;alexa::ask:skills:readwrite alexa::ask:models:readwrite alexa::ask:skills:test alexa::ask:catalogs:read alexa::ask:catalogs:readwrite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iarqmHXg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r8vhycv90f5dd9aizku8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iarqmHXg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r8vhycv90f5dd9aizku8.png" alt="Postman Auth" width="638" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Pop-Up should show up prompting you to log into your Developer account. Log in and you will be redirected to Postman where you should have a &lt;code&gt;refresh_token&lt;/code&gt; to use in the next steps&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Copy Your Vendor ID
&lt;/h3&gt;

&lt;p&gt;Visit the &lt;a href="https://developer.amazon.com/settings/console/mycid"&gt;Customer Details Page&lt;/a&gt; for your Amazon Developer Account and make a note of your "vendor ID"&lt;/p&gt;

&lt;h2&gt;
  
  
  Before You Deploy
&lt;/h2&gt;

&lt;p&gt;You need to add your ClientID, ClientSecret, Refresh Token and VendorID to the skill resource which can be found in &lt;code&gt;the-alexa-skill/typescript/lib/the-alexa-skill-stack.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      vendorId: 'foo',
      authenticationConfiguration: {
        clientId: 'foo',
        clientSecret: 'bar',
        refreshToken: 'foobar'
      },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Since this is a CDK project you can deploy it with the CDK Deploy command&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do I Test This After Deployment?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the Alexa Developer Console, or follow this link - &lt;a href="https://developer.amazon.com/alexa/console/ask"&gt;https://developer.amazon.com/alexa/console/ask&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;If you see a skill named "CDK Patterns Sample" in your Alexa Skills list then it has successfully been uploaded! Now we just need to test the skill itself.&lt;/li&gt;
&lt;li&gt;Select the CDK Patterns Sample skill by clicking on the name.&lt;/li&gt;
&lt;li&gt;On the next page, select "Test" at the top of the screen. &lt;/li&gt;
&lt;li&gt;Amazon will ask if you'd to use your microphone or not. This is entirely optional as you may test Alexa using either voice commands or  the text box provided.&lt;/li&gt;
&lt;li&gt;Change the "skill testing is enabled in:" option from "Off" to "Development" if needed.&lt;/li&gt;
&lt;li&gt;Either type or say "CDK Patterns" (Case sensitive if typing) and wait for a response.&lt;/li&gt;
&lt;li&gt;The response should be "Hey, it\'s Pancakes the CDK Otter here, what would you like to know?"&lt;/li&gt;
&lt;li&gt;For further testing, either type or say "What patterns do you have?"&lt;/li&gt;
&lt;li&gt;The response should be "I have many patterns for you to see! For example, there is" followed by three pattern names randomly picked from CDK Patterns.&lt;/li&gt;
&lt;li&gt;Now we just need to confirm that it is interacting with DynamoDB correctly.&lt;/li&gt;
&lt;li&gt;Go to the AWS Console and navigate to DynamoDB. Open your tables and find the one corresponding to TheAlexaSkillStack.&lt;/li&gt;
&lt;li&gt;Confirm that one item is in the table (It should have 2 attributes and a UserID). If it does then congratulations! Everything works! &lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>awscdk</category>
      <category>aws</category>
      <category>tutorial</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Add Resiliency To Your Lambda Function with a Circuit Breaker</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Thu, 15 Oct 2020 09:00:15 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/add-resiliency-to-your-lambda-with-a-circuit-breaker-1na6</link>
      <guid>https://dev.to/cdkpatterns/add-resiliency-to-your-lambda-with-a-circuit-breaker-1na6</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F37blu3o2cf75mhzbit2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F37blu3o2cf75mhzbit2b.png" alt="The Lambda Circuit Breaker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pattern takes advantage of the awesome &lt;a href="https://github.com/gunnargrosch/circuitbreaker-lambda" rel="noopener noreferrer"&gt;circuitbreaker-lambda library&lt;/a&gt; from &lt;a href="https://twitter.com/GunnarGrosch" rel="noopener noreferrer"&gt;Gunnar Grosch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;View Codebase:&lt;br&gt;
&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-lambda-circuit-breaker" rel="noopener noreferrer"&gt;https://github.com/cdk-patterns/serverless/tree/master/the-lambda-circuit-breaker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To Clone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;//TypeScript
npx cdkp init the-lambda-circuit-breaker
//Python
npx cdkp init the-lambda-circuit-breaker &lt;span class="nt"&gt;--lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8vb3bdr9sk82bepq2vsc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8vb3bdr9sk82bepq2vsc.png" alt="AWS Well Architected"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://aws.amazon.com/architecture/well-architected/" rel="noopener noreferrer"&gt;AWS Well-Architected&lt;/a&gt; Framework helps you understand the pros and cons of&lt;br&gt;
decisions you make while building systems on AWS. By using the Framework, you will learn architectural best practices for designing and operating reliable, secure, efficient, and cost-effective systems in the cloud. It provides a way for you to consistently measure your architectures against best practices and identify areas for improvement.&lt;/p&gt;

&lt;p&gt;We believe that having well-architected systems greatly increases the likelihood of business success.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf" rel="noopener noreferrer"&gt;Serverless Lens Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://d0.awsstatic.com/whitepapers/architecture/AWS_Well-Architected_Framework.pdf" rel="noopener noreferrer"&gt;Well Architected Whitepaper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Reliability Pillar
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note -&lt;/strong&gt; The content for this section is a subset of the &lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf" rel="noopener noreferrer"&gt;Serverless Lens Whitepaper&lt;/a&gt; with some minor tweaks.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf#page=48" rel="noopener noreferrer"&gt;reliability pillar&lt;/a&gt; includes the ability of a system to recover from infrastructure or service disruptions, dynamically acquire computing resources to meet demand, and mitigate disruptions such as misconfigurations or transient network issues.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;REL 2: How are you building resiliency into your serverless application?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Evaluate scaling mechanisms for Serverless and non-Serverless resources to meet customer demand, and build resiliency to withstand partial and intermittent failures across dependencies.&lt;/p&gt;

&lt;p&gt;Best Practices:&lt;/p&gt;

&lt;p&gt;1 / Manage transaction, partial, and intermittent failures: Transaction failures might occur when components are under high load. Partial failures can occur during batch processing, while intermittent failures might occur due to network or other transient issues.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's Included In This Pattern?
&lt;/h2&gt;

&lt;p&gt;This is an implementation of the simple webservice pattern only instead of our Lambda Function using DynamoDB to store and retrieve data for the user it is being used to tell our Lambda Function if the webservice it wants to call is reliable right now or if it should use a fallback function.&lt;/p&gt;

&lt;p&gt;To demonstrate this behaviour the Lambda function has some logic in it to simulate failure. The below logic will randomly fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;unreliableFunction&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we have a circuitbreaker configured with a fallback mechanism for when it has failed too many times recently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fallbackFunction&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Expensive Fallback Successful&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fallback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fallbackFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;successThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;circuitBreaker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CircuitBreaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unreliableFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;circuitBreaker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When You Would Use This Pattern
&lt;/h2&gt;

&lt;p&gt;When integrating with an external service and you want to provide a cost effective, resilient service for your consumers. If you don't do this and the external service is down you will be paying lambda invocation costs for the full request timeout plus your consumers will be waiting for an ultimately frustrating experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Test This Pattern
&lt;/h2&gt;

&lt;p&gt;After you deploy this pattern you will have a url for an API Gateway where if you open it in a browser you will get a JSON payload back with one of two messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;circuit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;closed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unreliable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;worked&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Success"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;circuit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;open&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fallback"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So refresh the browser a few times and you will see the message switch to Fallback then if you open the CloudWatch logs for your Lambda Function as you hit it again you should be able to watch the circuit breaker change state&lt;/p&gt;

&lt;p&gt;You will see messages like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;INFO CircuitBreaker state: OPEN&lt;/li&gt;
&lt;li&gt;INFO CircuitBreaker state: HALF&lt;/li&gt;
&lt;li&gt;INFO CircuitBreaker state: CLOSED&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open means that no requests are going through to the unreliable function, half means that some requests are let through to test the stability of the unreliable function and closed means operating as normal.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>architecture</category>
      <category>awscdk</category>
    </item>
    <item>
      <title>CDK Patterns on the AWS Architecture Blog</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Sun, 26 Jul 2020 07:41:17 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/cdk-patterns-on-the-aws-architecture-blog-b85</link>
      <guid>https://dev.to/cdkpatterns/cdk-patterns-on-the-aws-architecture-blog-b85</guid>
      <description>&lt;p&gt;I recently worked with AWS on an article talking about how we use AWS CDK, CDK Patterns and AWS Well Architected within Liberty IT.&lt;/p&gt;

&lt;p&gt;AWS posted it on their Architecture blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq66zosy9izpod8mh9omw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq66zosy9izpod8mh9omw.png" alt="Arch blog preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To view the article visit &lt;a href="https://aws.amazon.com/blogs/architecture/liberty-it-adopts-serverless-best-practices-using-aws-cdk/" rel="noopener noreferrer"&gt;this link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>architecture</category>
      <category>serverless</category>
    </item>
    <item>
      <title>CDK Patterns at 20! Let's Walk Through all 20 Serverless Patterns for AWS</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Mon, 20 Jul 2020 15:28:54 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/cdk-patterns-at-20-let-s-walk-through-all-20-serverless-patterns-for-aws-dh</link>
      <guid>https://dev.to/cdkpatterns/cdk-patterns-at-20-let-s-walk-through-all-20-serverless-patterns-for-aws-dh</guid>
      <description>&lt;p&gt;This is a link to the original post under my nideveloper account but I cannot move it yet because multiple sources still actively deep link to that post. I will swap over the content in a couple of weeks but I want visitors to cdkpatterns to find the article:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/nideveloper" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mIs0j92M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--DxTcaqtz--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/344151/981e1051-b576-4a48-955f-3b6bcf891f58.png" alt="nideveloper"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/nideveloper/cdk-patterns-at-20-let-s-walk-through-all-20-serverless-patterns-for-aws-d1n" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;CDK Patterns at 20! Let's Walk Through all 20 Serverless Patterns for AWS&lt;/h2&gt;
      &lt;h3&gt;Matt Coulter ・ Jul 14 '20 ・ 12 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#aws&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#cdk&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#serverless&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>aws</category>
      <category>awscdk</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Open your content to the world by combining Amazon Translate and Polly - Natural language translations and voice synthesis</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Sat, 11 Jul 2020 09:03:19 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/open-your-content-to-the-world-by-combining-amazon-lex-and-polly-natural-language-translations-and-voice-synthesis-4akm</link>
      <guid>https://dev.to/cdkpatterns/open-your-content-to-the-world-by-combining-amazon-lex-and-polly-natural-language-translations-and-voice-synthesis-4akm</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QZ0uLMXd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vu0afsf94zdm9nvxxo3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QZ0uLMXd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vu0afsf94zdm9nvxxo3u.png" alt="overview image" width="880" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a pattern that integrates the Amazon Polly service into an AWS Lambda Function so that you can synthesize text into speech using a serverless stack. It also integrates with Amazon Translate to allow you to choose the language for the spoken text.&lt;/p&gt;

&lt;p&gt;Some Useful References:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Author&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Polly&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/polly/"&gt;Amazon Polly Site&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polly Pricing&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/polly/pricing/"&gt;Polly Pricing&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polly Permissions&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/polly/latest/dg/api-permissions-reference.html"&gt;Polly IAM Permissions&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Translate&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/translate/latest/dg/what-is.html"&gt;What Is Amazon Translate?&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Translate Pricing&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/translate/pricing/"&gt;Translate Pricing&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Blogs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/machine-learning/giving-your-content-a-voice-with-the-newscaster-speaking-style-from-amazon-polly/"&gt;Giving your content a voice with the Newscaster speaking style from Amazon Polly&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Docs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/translate/latest/dg/examples-polly.html"&gt;Using Amazon Polly with Amazon Translate&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timothy Mugayi&lt;/td&gt;
&lt;td&gt;&lt;a href="https://medium.com/better-programming/text-to-speech-build-apps-that-talk-with-aws-polly-and-node-js-a9cdab99af04"&gt;Text-to-Speech: Build Apps That Talk With AWS Polly and Node.js&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Philip Kiely&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.smashingmagazine.com/2019/08/text-to-speech-aws/"&gt;Text-To-Speech With AWS (Part 1)&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Available Versions
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/polly/typescript"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/polly/python"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Included In This Pattern?
&lt;/h2&gt;

&lt;p&gt;After deployment you will have an API Gateway HTTP API configured where all traffic points to a Lambda Function that calls the Polly / Translate service.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Gateway HTTP API
&lt;/h3&gt;

&lt;p&gt;This is setup with basic settings where all traffic is routed to our Lambda Function&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Function
&lt;/h3&gt;

&lt;p&gt;Takes in whatever voice you want and whatever text you want, translates it to whatever language you want then sends it to the Polly service and returns an Audio stream&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing The Pattern
&lt;/h2&gt;

&lt;p&gt;After deployment in the deploy logs you will see the url for the API Gateway.&lt;/p&gt;

&lt;p&gt;If you open that URL in chrome it will play an audio recording saying "To hear your own script, you need to include text in the message body of your restful request to the API Gateway"&lt;/p&gt;

&lt;p&gt;For examples of the voice clips produced checkout the mp3 files in the &lt;a href="https://github.com/cdk-patterns/serverless/tree/master/polly/recordings"&gt;recordings folder&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can customise this message based on how you call the url:&lt;/p&gt;

&lt;h3&gt;
  
  
  Changing the voice
&lt;/h3&gt;

&lt;p&gt;You can pick from 3 voices "Matthew" (the default), "Joanna" or "Lupe". This is using the newsreader style of voice which AWS recently launched so it currently only supports these 3.&lt;/p&gt;

&lt;p&gt;To change voices just add a query param onto your url like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://{api-url}/?voice=Lupe
https://{api-url}/?voice=Joanna
https://{api-url}/?voice=Matthew
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Changing the language spoken
&lt;/h3&gt;

&lt;p&gt;This Lambda Function is integrated with Amazon Translate so you can have Polly speak a variety of languages&lt;/p&gt;

&lt;p&gt;To have Lupe speak Spanish just add the translateTo query param&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://{api-url}/?voice=Lupe&amp;amp;translateTo=es
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the text you are translating is in a language other than english you can use the translateFrom parameter&lt;/p&gt;

&lt;p&gt;To understand what languages are possible please refer to the &lt;a href="https://docs.aws.amazon.com/translate/latest/dg/what-is.html"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Changing the text
&lt;/h3&gt;

&lt;p&gt;If you use a tool like Postman to send text in the body of a POST request to the url it will use Polly to synthesize your text&lt;/p&gt;

&lt;h2&gt;
  
  
  Calling Translate / Polly
&lt;/h2&gt;

&lt;p&gt;Integrating our Lambda Function with these services was relatively straightforward.&lt;/p&gt;

&lt;p&gt;First I needed to make sure the function had IAM permissions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://docs.aws.amazon.com/polly/latest/dg/api-permissions-reference.html&lt;/span&gt;
    &lt;span class="c1"&gt;// https://docs.aws.amazon.com/translate/latest/dg/translate-api-permissions-ref.html&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pollyStatement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;translate:TranslateText&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;polly:SynthesizeSpeech&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;pollyLambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addToRolePolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pollyStatement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can use translate and polly from the AWS SDK.&lt;/p&gt;

&lt;p&gt;For Translate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If we passed in a translation language, use translate to do the translation&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;translateTo&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;translateFrom&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Translate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;translateParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;SourceLanguageCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;translateFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;TargetLanguageCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;translateTo&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rawTranslation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;translateParams&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawTranslation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TranslatedText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Polly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Use Polly to translate text into speech&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;polly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Polly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;OutputFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mp3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;neural&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;TextType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ssml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;speak&amp;gt;&amp;lt;amazon:domain name="news"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;/amazon:domain&amp;gt;&amp;lt;/speak&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;VoiceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;synthesis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;polly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;synthesizeSpeech&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;audioStreamBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;synthesis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AudioStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sendVoiceRes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;audioStreamBuffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>aws</category>
      <category>cdk</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Attach a FileSystem to your AWS Lambda Function</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Thu, 09 Jul 2020 12:29:27 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/attach-a-filesystem-to-your-aws-lambda-function-3bi9</link>
      <guid>https://dev.to/cdkpatterns/attach-a-filesystem-to-your-aws-lambda-function-3bi9</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwk7tpot809kpgwtv64eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwk7tpot809kpgwtv64eg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a pattern that attaches an EFS file system to your lambda function to give it expandable, persistent storage. Having this level of storage in a Lambda Function opens the door to many new possibilities (multiple functions can even use the same file system).&lt;/p&gt;

&lt;p&gt;Some Useful References:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Author&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS Docs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/services-efs.html" rel="noopener noreferrer"&gt;Using Amazon EFS with Lambda&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Docs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-filesystem.html" rel="noopener noreferrer"&gt;Configuring file system access for Lambda functions&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Samples&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/aws-samples/aws-lambda-efs-samples" rel="noopener noreferrer"&gt;EFS for Lambda - Example SAM applications&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;James Beswick&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/compute/using-amazon-efs-for-aws-lambda-in-your-serverless-applications/" rel="noopener noreferrer"&gt;Using Amazon EFS for AWS Lambda in your serverless applications&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Danilo Poccia&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/aws/new-a-shared-file-system-for-your-lambda-functions/" rel="noopener noreferrer"&gt;A Shared File System for Your Lambda Functions&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yan Cui&lt;/td&gt;
&lt;td&gt;&lt;a href="https://lumigo.io/blog/unlocking-more-serverless-use-cases-with-efs-and-lambda/" rel="noopener noreferrer"&gt;Unlocking New Serverless Use Caes With EFS and Lambda&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Available Versions
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-efs-lambda/typescript" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-efs-lambda/python" rel="noopener noreferrer"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Included In This Pattern?
&lt;/h2&gt;

&lt;p&gt;This pattern covers the first half of Danilo Poccia's awesome &lt;a href="https://aws.amazon.com/blogs/aws/new-a-shared-file-system-for-your-lambda-functions/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;. After deployment you will have an API Gateway HTTP API where any url you hit gets directed to a Lambda Function that is integrated with EFS.&lt;/p&gt;

&lt;h3&gt;
  
  
  VPC
&lt;/h3&gt;

&lt;p&gt;A VPC is bundled in this pattern because EFS requires it, this is using the default settings from CDK so if you want to put this in production you will have to review / refine this&lt;/p&gt;

&lt;h3&gt;
  
  
  EFS FileSystem
&lt;/h3&gt;

&lt;p&gt;A FileSystem is included in the above VPC with a removal policy of destroy. In a production system you probably would want to retain your storage on stack deletion.&lt;/p&gt;

&lt;p&gt;POSIX permissions are also setup for this File System&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Function
&lt;/h3&gt;

&lt;p&gt;A simple Python lambda function that interacts with the file system - storing, retrieving and deleting messages&lt;/p&gt;

&lt;h3&gt;
  
  
  API Gateway HTTP API
&lt;/h3&gt;

&lt;p&gt;This is configured with the Lambda Function as the default handler for any url you hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do I Test This Pattern?
&lt;/h2&gt;

&lt;p&gt;Our deployed Lambda Function is acting as a shared message broker. It allows you to send messages to it which it stores in EFS, then you can retrieve all messages to read them or delete all messages after you have finished reading.&lt;/p&gt;

&lt;p&gt;The Lambda Function will behave differently based on the RESTful verb you use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET - Retrieve messages&lt;/li&gt;
&lt;li&gt;POST - Send a message (whatever you send in the body is the message)&lt;/li&gt;
&lt;li&gt;DELETE - Deletes all stored messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The URL for the HTTP API to use these commands will be printed in the CloudFormation stack output after you deploy.&lt;/p&gt;

&lt;p&gt;Note - After deployment you may need to wait 60-90 seconds before the implementation works as expected. There are a lot of network configurations happening so you need to wait on propagation&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Protect your RDS MySQL DB from AWS Lambda Scalability</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Mon, 06 Jul 2020 07:13:41 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/protect-your-rds-mysql-db-from-aws-lambda-scalability-5d80</link>
      <guid>https://dev.to/cdkpatterns/protect-your-rds-mysql-db-from-aws-lambda-scalability-5d80</guid>
      <description>&lt;p&gt;RDS MySQL is a resource that cannot scale at the same rate as fully serverless components like AWS Lambda. That is why you should always implement some kind of buffer between the two. Otherwise if your application gets a spike in traffic your RDS could fall over.&lt;/p&gt;

&lt;p&gt;AWS have built that buffer for you in &lt;a href="https://aws.amazon.com/rds/proxy/"&gt;AWS RDS Proxy&lt;/a&gt;, it is a like for like replacement for your RDS integration and just sits in front of your existing DB.&lt;/p&gt;

&lt;p&gt;I have built a reference architecture for you in AWS CDK that you can deploy in one command to understand how this works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pu0BAnqs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8fvi2s4tnwgx9f3q5kb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pu0BAnqs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8fvi2s4tnwgx9f3q5kb7.png" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a project that has been configured with a MySQL RDS DB, an RDS Proxy, a Lambda Function to run queries and an API Gateway HTTP API to trigger the lambda function.&lt;/p&gt;

&lt;p&gt;A VPC is included in this project that has the RDS Subnets configured and custom security groups for allowing communication between Lambda -&amp;gt; Proxy -&amp;gt; MySQL.&lt;/p&gt;

&lt;p&gt;Some Useful References:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Author&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS RDS Proxy&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/rds/proxy/"&gt;RDS Proxy Site&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS User Guide&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html"&gt;Managing Connections with Amazon RDS Proxy&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ben Smith&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/compute/introducing-the-serverless-lamp-stack-part-2-relational-databases/"&gt;Introducing the serverless LAMP stack - part 2&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;George Mao&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/compute/using-amazon-rds-proxy-with-aws-lambda/"&gt;Using Amazon RDS Proxy with AWS Lambda&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL Cert for RDS MySQL&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.amazontrust.com/repository/AmazonRootCA1.pem"&gt;AmazonRootCA1.pem&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS User Guide&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Tutorials.WebServerDB.CreateDBInstance.html"&gt;Manual Steps for RDS Creation&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS User Guide&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_MySQL.html"&gt;MySQL in Amazon RDS&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node MySQL Lib&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/mysqljs/mysql"&gt;MySQL&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Docs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SecretsManager.html"&gt;Secrets Manager JS SDK Docs&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS User Guide&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/secretsmanager/latest/userguide/tutorials_basic.html"&gt;Creating and Retrieving a Secret&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Available Versions
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-rds-proxy/typescript"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-rds-proxy/python"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iqQH-aXt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5eu7yhht2ygpad57gh31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iqQH-aXt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5eu7yhht2ygpad57gh31.png" alt="AWS Well Architected" width="880" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://aws.amazon.com/architecture/well-architected/"&gt;AWS Well-Architected&lt;/a&gt; Framework helps you understand the pros and cons of&lt;br&gt;
decisions you make while building systems on AWS. By using the Framework, you will learn architectural best practices for designing and operating reliable, secure, efficient, and cost-effective systems in the cloud. It provides a way for you to consistently measure your architectures against best practices and identify areas for improvement.&lt;/p&gt;

&lt;p&gt;We believe that having well-architected systems greatly increases the likelihood of business success.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf"&gt;Serverless Lens Whitepaper&lt;/a&gt; &lt;br&gt;&lt;br&gt;
&lt;a href="http://d0.awsstatic.com/whitepapers/architecture/AWS_Well-Architected_Framework.pdf"&gt;Well Architected Whitepaper&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Reliability Pillar
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note -&lt;/strong&gt; The content for this section is a subset of the &lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf"&gt;Serverless Lens Whitepaper&lt;/a&gt; with some minor tweaks.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf#page=48"&gt;reliability pillar&lt;/a&gt; includes the ability of a system to recover from infrastructure or service disruptions, dynamically acquire computing resources to meet demand, and mitigate disruptions such as misconfigurations or transient network issues.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;REL 1: How are you regulating inbound request rates?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Best Practices:&lt;/p&gt;

&lt;p&gt;Use mechanisms to protect non-scalable resources: Functions can scale faster than traditional resources, such as relational databases and cache systems. Protect non-scalable resources by adapting fast scaling components to downstream systems throughput.&lt;/p&gt;

&lt;p&gt;For relational databases such as Amazon RDS, you can limit the number of connections per user in addition to the global maximum number of connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Included In This Pattern?
&lt;/h2&gt;

&lt;p&gt;This pattern is a version of &lt;a href="https://github.com/cdk-patterns/serverless/blob/master/the-scalable-webhook/README.md"&gt;the scalable webhook&lt;/a&gt; built using AWS RDS Proxy. &lt;/p&gt;

&lt;p&gt;You get a MySQL Database setup inside a VPC with appropriate subnets and security groups to connect with an RDS Proxy. That RDS Proxy is then communicated with via a Lambda Function / API Gateway HTTP API.&lt;/p&gt;

&lt;p&gt;The big benefit here is that you are using fully managed infrastructure to protect the RDS DB, you have not needed to spin up your own queue and mechanism for how rapidly to pull from it.&lt;/p&gt;

&lt;p&gt;For the AWS official benefits see &lt;a href="https://aws.amazon.com/rds/proxy/#Benefits"&gt;this page&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  VPC
&lt;/h3&gt;

&lt;p&gt;The VPC bundled with this pattern is the default one setup by the CDK L2 construct. In a production system you would want to tailor this to your needs&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Groups
&lt;/h3&gt;

&lt;p&gt;I bundled 2 security groups lambdaToRDSProxyGroup and dbConnectionGroup.&lt;/p&gt;

&lt;p&gt;dbConnectionGroup allows TCP traffic on port 3306 from other peers within this group. It also allows TCP traffic on port 3306 for peers within the lambdaToRDSProxyGroup group.&lt;/p&gt;

&lt;p&gt;I added the second group because I saw no need for peers to be allowed to hit the Lambda Function with TCP traffic on 3306. This separated the capability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto Generated Password and Username in Secrets Manager
&lt;/h3&gt;

&lt;p&gt;The username is a static value but we use secrets manager to generate the password to be used for our DB. We then give our Lambda Function permissions to read this secret so that it can connect to the DB. That means the only value that needs to be shared as an environment variable is the secret name,&lt;/p&gt;

&lt;h3&gt;
  
  
  MySQL RDS Instance
&lt;/h3&gt;

&lt;p&gt;This is just a small, burstable instance using MySQL 5.7.22. I have removed the deletion protection and told Cloudformation to delete it on stack deletion because this is a learning stack. In a production stack, never use these two properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  RDS Proxy
&lt;/h3&gt;

&lt;p&gt;This is what we are using to protect the MySQL DB which is a small instance from the massively scalable Lambda Function that will be querying it. The proxy makes sure we do not overload it and shares connections between queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Function
&lt;/h3&gt;

&lt;p&gt;This reads our username and password for our proxy from Secrets Manager then uses the MySQL library to create a database and table if they do not exist then insert a record for the url you hit on the API Gateway. Finally it queries the database for all records stored and returns them.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Gateway HTTP API
&lt;/h3&gt;

&lt;p&gt;Any url you hit on this gateway will integrate with the Lambda Function&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing The Pattern
&lt;/h2&gt;

&lt;p&gt;After you deploy this pattern you will have an API Gateway HTTP API where any url you hit gets routed to a Lambda function that inserts the URL path you hit into our MySQL table.&lt;/p&gt;

&lt;p&gt;Simply open the url printed out in the deployment logs for our HTTP API in a browser and you should see a table containing all the urls you have hit. Try hitting a couple of different urls and watch the table grow.&lt;/p&gt;

</description>
      <category>cdk</category>
      <category>aws</category>
      <category>tutorial</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Tune your AWS Lambdas for best cost vs performance with "The Lambda Power Tuner" serverless pattern</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Sat, 09 May 2020 09:21:03 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/tune-your-aws-lambdas-for-best-cost-vs-performance-with-the-lambda-power-tuner-serverless-pattern-2cea</link>
      <guid>https://dev.to/cdkpatterns/tune-your-aws-lambdas-for-best-cost-vs-performance-with-the-lambda-power-tuner-serverless-pattern-2cea</guid>
      <description>&lt;h1&gt;
  
  
  The Lambda Power Tuner
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hlQgLcXy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7f8zpyudowvm0t5ypu8u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hlQgLcXy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7f8zpyudowvm0t5ypu8u.jpg" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Available CDK Versions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-lambda-power-tuner/typescript"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-lambda-power-tuner/python"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatively use the cdkp command line tool to download the code:&lt;/p&gt;

&lt;p&gt;TypeScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cdkp init the-lambda-power-tuner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cdkp init the-lambda-power-tuner &lt;span class="nt"&gt;--lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;This is an AWS CDK project that deploys the awesome &lt;a href="https://github.com/alexcasalboni/aws-lambda-power-tuning"&gt;AWS Lambda Power Tuning&lt;/a&gt; project. &lt;/p&gt;

&lt;p&gt;AWS Lambda Power Tuning is an AWS Step Functions state machine that helps you optimize your Lambda functions in a data-driven way.&lt;/p&gt;

&lt;p&gt;The state machine is designed to be quick and language agnostic. You can provide any Lambda function as input and the state machine will run it with multiple power configurations (from 128MB to 3GB), analyze execution logs and suggest you the best configuration to minimize cost or maximize performance.&lt;/p&gt;

&lt;p&gt;The input function will be executed in your AWS account - performing real HTTP calls, SDK calls, cold starts, etc. The state machine also supports cross-region invocations and you can enable parallel execution to generate results in just a few seconds. Optionally, you can configure the state machine to automatically optimize the function and the end of its execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yXjkTTRe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oco3tnin3bnng3589fqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yXjkTTRe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oco3tnin3bnng3589fqq.png" alt="results graph" width="880" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason for doing this is that it helps with two of the Serverless Well Architected pillars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance Efficiency Pillar&lt;/li&gt;
&lt;li&gt;Cost Optimization Pillar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VW4xjz-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tbznhav3bzhl3f7pqlx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VW4xjz-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tbznhav3bzhl3f7pqlx0.png" alt="AWS Well Architected" width="880" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://aws.amazon.com/architecture/well-architected/"&gt;AWS Well-Architected&lt;/a&gt; Framework helps you understand the pros and cons of&lt;br&gt;
decisions you make while building systems on AWS. By using the Framework, you will learn architectural best practices for designing and operating reliable, secure, efficient, and cost-effective systems in the cloud. It provides a way for you to consistently measure your architectures against best practices and identify areas for improvement.&lt;/p&gt;

&lt;p&gt;We believe that having well-architected systems greatly increases the likelihood of business success.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf"&gt;Serverless Lens Whitepaper&lt;/a&gt; &lt;br&gt;&lt;br&gt;
&lt;a href="http://d0.awsstatic.com/whitepapers/architecture/AWS_Well-Architected_Framework.pdf"&gt;Well Architected Whitepaper&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Performance Efficiency Pillar
&lt;/h2&gt;

&lt;p&gt;The performance efficiency pillar focuses on the efficient use of computing resources to meet requirements and the maintenance of that efficiency as demand changes and technologies evolve.&lt;/p&gt;

&lt;p&gt;Performance efficiency in the cloud is composed of four areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selection&lt;/li&gt;
&lt;li&gt;Review&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;Tradeoffs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take a data-driven approach to selecting a high-performance architecture. Gather data on all aspects of the architecture, from the high-level design to the selection and configuration of resource types. By reviewing your choices on a cyclical basis, you will ensure that you are taking advantage of the continually evolving AWS Cloud.&lt;/p&gt;

&lt;p&gt;Monitoring will ensure that you are aware of any deviance from expected performance and can take action on it. Finally, you can make tradeoffs in your architecture to improve performance, such as using compression or caching, or by relaxing consistency requirements.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PER 1: How have you optimized the performance of your serverless application?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Selection
&lt;/h3&gt;

&lt;p&gt;Run performance tests on your serverless application using steady and burst rates. Using the result, try tuning capacity units and load test after changes to help you select the best configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda: Test different memory settings as CPU, network, and storage IOPS are allocated proportionally. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Cost Optimization Pillar
&lt;/h2&gt;

&lt;p&gt;The cost optimization pillar includes the continual process of refinement and improvement of a system over its entire lifecycle. From the initial design of your first proof of concept to the ongoing operation of production workloads, adopting the practices in this document will enable you to build and operate cost-aware systems that achieve business outcomes and minimize costs, thus allowing your business to maximize its return on investment.&lt;/p&gt;

&lt;p&gt;There are four best practice areas for cost optimization in the cloud:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost-effective resources&lt;/li&gt;
&lt;li&gt;Matching supply and demand&lt;/li&gt;
&lt;li&gt;Expenditure awareness&lt;/li&gt;
&lt;li&gt;Optimizing over time&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;COST 1: How do you optimize your costs?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Cost-Effective Resources
&lt;/h3&gt;

&lt;p&gt;Serverless architectures are easier to manage in terms of correct resource allocation. Due to its pay-per-value pricing model and scale based on demand, serverless effectively reduces the capacity planning effort.&lt;/p&gt;

&lt;p&gt;As covered in the operational excellence and performance pillars, optimizing your serverless application has a direct impact on the value it produces and its cost.&lt;/p&gt;

&lt;p&gt;As Lambda proportionally allocates CPU, network, and storage IOPS based on&lt;br&gt;
memory, the faster the execution the cheaper and more value your function produces due to 100-ms billing incremental dimension.&lt;/p&gt;
&lt;h2&gt;
  
  
  Default Configuration Settings Provided
&lt;/h2&gt;

&lt;p&gt;There are some variables that you can pass into the SAR app to manipulate the power tuning step function. You can find two that I have set for you at the top of the cdk stack&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;powerValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;128,256,512,1024,1536,3008&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lambdaResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the powerValues lets you pick exactly what AWS Lambda memory settings you want to tune against. The full list of allowed values is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['128','192','256','320','384','448','512','576','640','704','768','832','896','960','1024','1088','1152','1216','1280','1344','1408','1472','1536','3008']
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;lambdaResource is about what IAM permissions do you want to give the state machine? In general, you want to give your components the least privileges they require to reduce their blast radius. &lt;/p&gt;

&lt;p&gt;By default the power tuner uses * permissions which means that it has wide scope and can tune any function. If you can scope this down to something more specific that is advisable.&lt;/p&gt;

&lt;p&gt;Alex gave me this advice&lt;/p&gt;

&lt;p&gt;I can see 3 common patterns :&lt;br&gt;
1) use * (easy default, not always ideal)&lt;br&gt;
2) restrict to region or name prefix (better)&lt;br&gt;
3) restrict to only 1 ARN (not very flexible but ideal for CI/CD scenarios where you’ll delete the stack immediately after tuning)&lt;/p&gt;

&lt;p&gt;An example of option 3 is included in the stack but currently commented out, so all you have to do is uncomment it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Uncomment to only allow this power tuner to manipulate this defined function&lt;/span&gt;
&lt;span class="c1"&gt;//lambdaResource = exampleLambda.functionArn;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How To Test This Pattern
&lt;/h2&gt;

&lt;p&gt;After deployment, navigate to the step functions section of the AWS Console.&lt;/p&gt;

&lt;p&gt;from the list of availabe state machines, pick the power tuner state machine.&lt;/p&gt;

&lt;p&gt;Now click "start execution" in the top right&lt;/p&gt;

&lt;p&gt;In the input field enter the following JSON and add in the ARN to the lambda you want to test. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can either use the example lambda we bundled by getting the ARN from the cdk deploy logs or any another function in your account if you know the ARN.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "lambdaARN": "your lambda arn to test",
  "powerValues": [
    128,
    256,
    512,
    1024,
    2048,
    3008
  ],
  "num": 10,
  "payload": {},
  "parallelInvocation": true,
  "strategy": "cost"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click "Start Execution" in the bottom right.&lt;/p&gt;

&lt;p&gt;When the tuner has finished your visual workflow should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zq4R_R_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qajeijghmj6nkael6mdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zq4R_R_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qajeijghmj6nkael6mdc.png" alt="state machine success" width="880" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you can scroll down to the very last event and expand it to get the URL for your results graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rBu0W0M2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3wgrrgq36jep121f6eku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rBu0W0M2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3wgrrgq36jep121f6eku.png" alt="output" width="880" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Learn Serverless Tracability with "The X-Ray Tracer" CDK Pattern - Lambda, SNS, SQS, DynamoDB</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Mon, 04 May 2020 18:57:28 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/learn-serverless-tracability-with-the-x-ray-tracer-cdk-pattern-lambda-sns-sqs-dynamodb-3457</link>
      <guid>https://dev.to/cdkpatterns/learn-serverless-tracability-with-the-x-ray-tracer-cdk-pattern-lambda-sns-sqs-dynamodb-3457</guid>
      <description>&lt;h1&gt;
  
  
  The X-Ray Tracer
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G2lwdY8X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e3503qv5i2mtv7nx9zy3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G2lwdY8X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e3503qv5i2mtv7nx9zy3.png" alt="High Level Image" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a pattern not defined by the components used but how they send information back to the AWS X-Ray service to help you make your application perform better when viewed through the Serverless &lt;a href="https://aws.amazon.com/architecture/well-architected/"&gt;Well-Architected&lt;/a&gt; lens. A fully well architected solution would use embedded metric format for the logs like in the Julian Wood reference below but I am saving that for another pattern so as not to confuse the concepts.&lt;/p&gt;

&lt;p&gt;Some useful references:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Author&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS X-Ray Developer Guide&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.amazonaws.cn/en_us/xray/latest/devguide/xray-guide.pdf"&gt;X-Ray Developer Guide&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS X-Ray Concepts&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html"&gt;X-Ray Concepts&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Serverless Lens Whitepaper&lt;/td&gt;
&lt;td&gt;&lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf"&gt;Serverless Lens Whitepaper&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Well Architected Whitepaper&lt;/td&gt;
&lt;td&gt;&lt;a href="http://d0.awsstatic.com/whitepapers/architecture/AWS_Well-Architected_Framework.pdf"&gt;Well Architected Whitepaper&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://twitter.com/julian_wood"&gt;Julian Wood&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/compute/building-well-architected-serverless-applications-understanding-application-health-part-2/"&gt;Building Well Architected Applications&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Developer Blog&lt;/td&gt;
&lt;td&gt;&lt;a href="https://aws.amazon.com/blogs/developer/category/developer-tools/aws-x-ray/"&gt;Category: AWS X-Ray&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Training&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.aws.training/Details/Video?id=16450"&gt;Introduction to AWS X-Ray&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Available CDK Versions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-xray-tracer/typescript"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cdk-patterns/serverless/tree/master/the-xray-tracer/python"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatively use the cdkp command line tool to download the code:&lt;/p&gt;

&lt;p&gt;TypeScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cdkp init the-xray-tracer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cdkp init the-xray-tracer &lt;span class="nt"&gt;--lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w7B_optL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u6x68r40c03z8llc8sad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w7B_optL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u6x68r40c03z8llc8sad.png" alt="Well Architected" width="880" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://aws.amazon.com/architecture/well-architected/"&gt;AWS Well-Architected&lt;/a&gt; Framework helps you understand the pros and cons of&lt;br&gt;
decisions you make while building systems on AWS. By using the Framework, you will learn architectural best practices for designing and operating reliable, secure, efficient, and cost-effective systems in the cloud. It provides a way for you to consistently measure your architectures against best practices and identify areas for improvement.&lt;/p&gt;

&lt;p&gt;We believe that having well-architected systems greatly increases the likelihood of business success.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf"&gt;Serverless Lens Whitepaper&lt;/a&gt; &lt;br&gt;&lt;br&gt;
&lt;a href="http://d0.awsstatic.com/whitepapers/architecture/AWS_Well-Architected_Framework.pdf"&gt;Well Architected Whitepaper&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Operational Excellence Pillar
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note -&lt;/strong&gt; The content for this section is a subset of the &lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf"&gt;Serverless Lens Whitepaper&lt;/a&gt; with some minor tweaks.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf#page=28"&gt;operational excellence pillar&lt;/a&gt; includes the ability to run and monitor systems to deliver business value and to continually improve supporting processes and procedures.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OPS 1: How do you understand the health of your Serverless application?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Distributed Tracing
&lt;/h4&gt;

&lt;p&gt;Similar to non-serverless applications, anomalies can occur at larger scale in distributed systems. Due to the nature of serverless architectures, it’s fundamental to have distributed tracing.&lt;/p&gt;

&lt;p&gt;Making changes to your serverless application entails many of the same principles of deployment, change, and release management used in traditional workloads. However, there are subtle changes in how you use existing tools to accomplish these principles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Active tracing with AWS X-Ray should be enabled to provide distributed tracing capabilities as well as to enable visual service maps for faster troubleshooting&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;X-Ray helps you identify performance degradation and quickly understand anomalies, including latency distributions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fO0dmBH4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2x75lg4eougilw0l7a08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fO0dmBH4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2x75lg4eougilw0l7a08.png" alt="Example Trace" width="880" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Service Maps are helpful to understand integration points that need attention and resiliency practices. For integration calls, retries, backoffs, and possibly circuit breakers are necessary to prevent faults from propagating to downstream services. &lt;/p&gt;

&lt;p&gt;Another example is networking anomalies. You should not rely on default timeouts and retry settings. Instead, tune them to fail fast if a socket read/write timeout happens where the default can be seconds if not minutes in certain clients.&lt;/p&gt;

&lt;p&gt;X-Ray also provides two powerful features that can improve the efficiency on identifying anomalies within applications: Annotations and Subsegments.&lt;br&gt;
Subsegments are helpful to understand how application logic is constructed and what external dependencies it has to talk to. Annotations are key-value pairs with string, number, or Boolean values that are automatically indexed by AWS X-Ray.&lt;/p&gt;

&lt;p&gt;Combined, they can help you quickly identify performance statistics on specific&lt;br&gt;
operations and business transactions, for example, how long it takes to query a&lt;br&gt;
database, or how long it takes to process pictures with large crowds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f5QTbdxM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ypejkzlwodbnrgupsigg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f5QTbdxM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ypejkzlwodbnrgupsigg.png" alt="Alt Text" width="880" height="546"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Included In This Pattern?
&lt;/h2&gt;

&lt;p&gt;I wanted to make this pattern as "real" as possible for people so I included most of the serverless components you will use everyday. I have included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway -&amp;gt; SNS -&amp;gt; Lambda (not SQS for reasons documented later)&lt;/li&gt;
&lt;li&gt;Lambda -&amp;gt; DynamoDB&lt;/li&gt;
&lt;li&gt;Lambda -&amp;gt; SQS -&amp;gt; Lambda&lt;/li&gt;
&lt;li&gt;Lambda -&amp;gt; External Http Endpoint&lt;/li&gt;
&lt;li&gt;Lambda -&amp;gt; SNS -&amp;gt; Lambda&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I map the flow in a high level conceptual image it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1fUVoJ0s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uhpe56prtfb2h1k4hjdu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1fUVoJ0s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uhpe56prtfb2h1k4hjdu.png" alt="Flow" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After deployment, the X-Ray service map looks something like (You get two circles per Lambda):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_bVUXCne--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ms3jabugtkfxq9mbxtco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_bVUXCne--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ms3jabugtkfxq9mbxtco.png" alt="x-ray service map" width="880" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or if you look at CloudWatch Service Lens:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--veG7bKL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t5z56w8argn94yvbcz6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--veG7bKL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t5z56w8argn94yvbcz6g.png" alt="cloudwatch service lens" width="880" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that these two diagrams aren't a massive distance away from my high level conceptual flow, the difference is the X-Ray generated diagram is 100% accurate because it is created from real traces based on user flow. When viewed through the AWS Console, it cannot become the out of date diagram you found on a wiki last updated 12 months ago - it is always accurate. If a developer checks in a piece of code that changes the flow, you will see it immediately.&lt;/p&gt;
&lt;h2&gt;
  
  
  Testing This Pattern
&lt;/h2&gt;

&lt;p&gt;After you deploy this pattern you will have an API Gateway with the URL being output in the CDK Deploy logs.&lt;/p&gt;

&lt;p&gt;Any URL you hit on that gateway will trigger this flow, it uses your URL as the message sent to SNS.&lt;/p&gt;

&lt;p&gt;This URL is inserted into DynamoDB with a counter of how many times it was hit, the SNS and the SQS consumer lambdas both log the message to CloudWatch.&lt;/p&gt;

&lt;p&gt;To see the random service errors try to hit the URL at least 10 times then you can either navigate to the X-Ray section of the AWS Console followed by clicking on "Service Map" in the sidebar. Please be aware that sometimes there can be a 30 second or so delay before your calls show up in service map.&lt;/p&gt;

&lt;p&gt;Alternatively you can go to CloudWatch in the AWS Console and click "Service Lens" in the sidebar. Both offer views onto the system.&lt;/p&gt;
&lt;h2&gt;
  
  
  Deliberate Random Errors
&lt;/h2&gt;

&lt;p&gt;I introduced a random SSL Cert error into the Lambda that connects to the External Http Endpoint to let you experiment with using X-Ray to source an error&lt;/p&gt;

&lt;p&gt;Service map showing something isn't healthy:&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jf2BvRbv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3zuj18wpxbrlib8h3chv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jf2BvRbv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3zuj18wpxbrlib8h3chv.png" alt="Unhealthy service map" width="880" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Trace details showing error:&lt;br&gt;
&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SYUEN-xU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1c5qns5lqttzx1yumxxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SYUEN-xU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1c5qns5lqttzx1yumxxx.png" alt="error showing in hover in console" width="880" height="381"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Enabling X-Ray
&lt;/h2&gt;

&lt;p&gt;Depending on the component you are using and what it is integrating with you need to enable X-Ray in a different way.&lt;/p&gt;
&lt;h3&gt;
  
  
  API Gateway
&lt;/h3&gt;

&lt;p&gt;This is done by simply setting a property of &lt;code&gt;tracingEnabled: true&lt;/code&gt; on deployOptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;apigw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RestApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xrayTracerAPI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;deployOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;metricsEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loggingLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;apigw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MethodLoggingLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dataTraceEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tracingEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lambda
&lt;/h3&gt;

&lt;p&gt;You set a tracing property to &lt;code&gt;lambda.Tracing.ACTIVE&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpLambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;httpLambdaHandler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_12_X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lambdas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http.handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tracing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ACTIVE&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SNS/SQS/DynamoDB
&lt;/h3&gt;

&lt;p&gt;These just pick up when being called from a component with tracing enabled, they do not need a specific setting to enable it. &lt;/p&gt;

&lt;h3&gt;
  
  
  AWS SDK Calls
&lt;/h3&gt;

&lt;p&gt;You need to make sure your AWS SDK code is wrapped with X-Ray during invocation. This is true of any SDK calls e.g. Lambda to Lambda direct invoke, DynamoDB queries, Publishing to SNS etc&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWSXRay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-xray-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Wrap AWS SDK with X-Ray&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AWSXRay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;captureAWS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Create an SQS service object as normal&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sqs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SQS&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2012-11-05&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  External HTTP Requests
&lt;/h3&gt;

&lt;p&gt;You need to wrap the https module with X-Ray:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWSXRay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-xray-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Wrap HTTPS module with X-Ray&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;AWSXRay&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;captureHTTPs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Make a call to a webservice as normal&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://url.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Subsegments, Metadata and Annotations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Subsegments
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A segment can break down the data about the work done into subsegments. &lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-subsegments"&gt;Subsegments&lt;/a&gt; provide more granular timing information and details about downstream calls that your application made to fulfill the original request. A subsegment can contain additional details about a call to an AWS service, an external HTTP API, or an SQL database. You can even define arbitrary subsegments to instrument specific functions or lines of code in your application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have included some custom &lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-subsegments"&gt;subsegments&lt;/a&gt; in this pattern, like "external HTTP Request" below:&lt;br&gt;
&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7sQLPGFS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f5nke42ohhl2gm2dn0ht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7sQLPGFS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f5nke42ohhl2gm2dn0ht.png" alt="Subsegment showing in console" width="880" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are easy to create inside the Lambda Functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subsegment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addNewSubsegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;external HTTP Request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Make a call to a webservice&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://url.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;//resolve promise&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;//reject promise&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;subsegment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;response&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;subsegment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Metadata
&lt;/h3&gt;

&lt;p&gt;You are allowed to put whole objects inside metadata, this is brilliant for showing things like the response from a webservice. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Metadata are key-value pairs that can have values of any type, including objects and lists, but are not indexed for use with filter expressions. Use metadata to record additional data that you want stored in the trace but don't need to use with search.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TdhJyDrE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y5z4o9wslzegnsovqoo2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TdhJyDrE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y5z4o9wslzegnsovqoo2.png" alt="metadata on segment in console" width="880" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Annotations
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Annotations are key-value pairs with string, number, or Boolean values. Annotations are indexed for use with filter expressions. Use annotations to record data that you want to use to group traces in the console, or when calling the GetTraceSummaries API.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7uPIsW9i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wz7g2dqqo5jz8hlklhix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7uPIsW9i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wz7g2dqqo5jz8hlklhix.png" alt="annotations on segment in console" width="880" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  X-Ray Groups
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;X-Ray groups enable customers to slice and dice their X-Ray service graph and focus on certain workflows, applications, or routes.&lt;/p&gt;

&lt;p&gt;Customers can create a group by setting a filter expression. All the traces that match the set filter expression will be part of that group. Customers can then view service graphs for the selected group, and understand performance bottlenecks, errors, or faults in services belonging to that service graph.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/developer/deep-dive-into-aws-x-ray-groups-and-use-cases/"&gt;Deep dive into AWS X-Ray groups and use cases&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A useful tip is that Annotations can be used in filter expressions so you can easily create groups for smaller bounded contexts within a larger service map and then create CloudWatch alerts per group.&lt;/p&gt;

&lt;h2&gt;
  
  
  Known X-Ray "Quirks"
&lt;/h2&gt;

&lt;p&gt;There are a couple of X-Ray quirks that I need to document, I thought it better to show them than refactor the pattern to hide them then you hit one later. If these are a deal breaker for you there are other tools out there for tracing that I have been promised will integrate with no extra code changes like &lt;a href="https://epsagon.com/"&gt;Epsagon&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  SQS -&amp;gt; Lambda Traces
&lt;/h3&gt;

&lt;p&gt;There is a &lt;a href="https://github.com/aws/aws-xray-sdk-node/issues/208"&gt;known bug&lt;/a&gt; where this doesn't connect and you end up with two paths on your service map.&lt;/p&gt;

&lt;p&gt;I have included some logic inside the SQS subscriber lambda to move an X-Ray custom subsegment trace circle from the new second flow to where it should be but this is a workaround and hopefully that bug gets closed sooner than later.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Gateway -&amp;gt; SNS through direct integration
&lt;/h3&gt;

&lt;p&gt;X-Ray does work as expected with SNS when using the AWS SDK but for some reason when I do a direct integration with API Gateway through VTL the service map shows the subscribers of the SNS topic as being connected to API GW rather than SNS which is fine because I am not missing information but it's not correct. If I workout a fix for this I will update the pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R14YaFbf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3apy0xdtjy4q7so07p7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R14YaFbf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3apy0xdtjy4q7so07p7m.png" alt="sns bug" width="880" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Map Changes Design Randomly
&lt;/h3&gt;

&lt;p&gt;Unlike other tracing solutions I have used that let you position all of the circles where they give a feeling of inner calmness based on personal OCD; X-Ray randomly positions the circles on every refresh which can lead to some interesting map layouts. The important thing is being able to spot anomalies which you can definitely still do so this is purely aesthetic. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W1rI0M4p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ndr2igoqmvtfbly1kav7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W1rI0M4p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ndr2igoqmvtfbly1kav7.png" alt="service map positioning" width="880" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Watch me deconstruct "The Scalable Webhook" AWS Serverless Pattern - Lambda, API GW, SQS</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Wed, 29 Apr 2020 07:49:24 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/watch-me-deconstruct-the-scalable-webhook-aws-serverless-pattern-lambda-api-gw-sqs-25ec</link>
      <guid>https://dev.to/cdkpatterns/watch-me-deconstruct-the-scalable-webhook-aws-serverless-pattern-lambda-api-gw-sqs-25ec</guid>
      <description>&lt;h1&gt;
  
  
  The Scalable Webhook
&lt;/h1&gt;

&lt;p&gt;This is an example CDK stack from &lt;a href="https://www.cdkpatterns.com"&gt;CDK Patterns&lt;/a&gt; to deploy The Scalable Webhook stack described by Jeremy Daly here - &lt;a href="https://www.jeremydaly.com/serverless-microservice-patterns-for-aws/#scalablewebhook"&gt;https://www.jeremydaly.com/serverless-microservice-patterns-for-aws/#scalablewebhook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An advanced version of this pattern was talked about by &lt;a href="https://twitter.com/heitor_lessa"&gt;Heitor Lessa&lt;/a&gt; at re:Invent 2019 as Call me, “Maybe” (Webhook)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=9IYpGTS7Jy0"&gt;Youtube Recording&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://d1.awsstatic.com/events/reinvent/2019/REPEAT_3_Serverless_architectural_patterns_and_best_practices_ARC307-R3.pdf"&gt;Static Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Desconstructing The Scalable Webhook
&lt;/h2&gt;

&lt;p&gt;If you want a walkthrough of the theory, the code and finally a demo of the deployed implementation check out:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/kRI7QJfGBI8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  High Level Description
&lt;/h2&gt;

&lt;p&gt;You would use this pattern when you have a non serverless resource like an RDS DB in direct contact with a serverless resource like a lambda. You need to make&lt;br&gt;
sure that your serverless resource doesn't scale up to an amount that it DOS attacks your non serverless resource.&lt;/p&gt;

&lt;p&gt;This is done by putting a queue between them and having a lambda with a throttled concurrency policy pull items off the queue and communicate with your &lt;br&gt;
serverless resource at a rate it can handle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ned91O29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5z4z2kbcqbe45hwni3yo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ned91O29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5z4z2kbcqbe45hwni3yo.png" alt="Alt Text" width="880" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; For this pattern in the cdk deployable construct I have swapped RDS for DynamoDB. &lt;br&gt;&lt;br&gt;Why? Because it is significantly cheaper/faster for developers to deploy and maintain, I also don't think we lose the essence of the pattern with this swap given we still do the pub/sub deduplication via SQS/Lambda and throttle the subscription lambda. RDS also introduces extra complexity in that it needs to be deployed in a VPC. I am slightly worried developers would get distracted by the extra RDS logic when the main point is the pattern. A real life implementation of this pattern could use RDS MySQL or it could be a call to an on-prem mainframe, the main purpose of the pattern is the throttling to not overload the scale-limited resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern Background
&lt;/h2&gt;

&lt;p&gt;When people move to the cloud (especially serverless) they tend to think that this means their applications are now infinitely scalable:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xatkzOtD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1lg07x4ab9njed4iwclg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xatkzOtD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1lg07x4ab9njed4iwclg.png" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the right reasons this just isn't true. If any one person's resources were infinitely scalable then any one person could consume the whole of AWS no matter how scalable the platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uPI7pwT_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xpxv6wd3902dte659g91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uPI7pwT_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xpxv6wd3902dte659g91.png" alt="Alt Text" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html"&gt;View API Gateway limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html"&gt;View Lambda limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html"&gt;View DynamoDB Limits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we weren't using DynamoDB, we would need to know the max connections limit configured for our instance size:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oKogIXKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sfgkkqnhoms5lvqkzfzq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oKogIXKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sfgkkqnhoms5lvqkzfzq.png" alt="MySQL Reality" width="880" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OXR11eVW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ss5qx7spnbrvfjke34x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OXR11eVW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ss5qx7spnbrvfjke34x.png" alt="Postgres reality" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to slow down the amount of direct requests to our DB somehow, that is where the scalable webhook comes in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MMeO3VTi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9qcpoxt2xuyz0r3wcjt8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MMeO3VTi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9qcpoxt2xuyz0r3wcjt8.png" alt="scalable webhook" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can use SQS to hold all requests in a queue as soon as they come in. Again, SQS will have limits:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ULQoJvlJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xmlezvi3ykv1wff0qwi7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ULQoJvlJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xmlezvi3ykv1wff0qwi7.png" alt="sqs limits" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;120,000 in flight messages with an unlimited backlog I think will be effective enough as a buffer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-quotas.html"&gt;View SQS quotas&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have our messages in a queue but we need to subscribe to the queue and insert the records into the DB. To do this we create a throttled lambda where we set the max number of concurrent executions to whatever scale we are happy with. This should be less than the max connections on our DB and should take into account any other Lambdas running in this account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fGZBpE03--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w7gqfpkt3juni95yozxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fGZBpE03--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w7gqfpkt3juni95yozxk.png" alt="throttle" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One final improvement that we could make if implementing this in a production system is to delete the Lambda between the API Gateway and SQS. You can do a direct integration which will reduce costs and latency:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_bIR6dpx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pmvqg6h3yg71aqs87qgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_bIR6dpx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pmvqg6h3yg71aqs87qgj.png" alt="More scalable Webhook" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want an AWS managed service to try and help with this scalability problem you can check out &lt;a href="https://aws.amazon.com/rds/proxy/"&gt;AWS RDS Proxy&lt;/a&gt; which is in preview&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rshuxS2_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bzjn6m25wxzt2lytlloa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rshuxS2_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bzjn6m25wxzt2lytlloa.png" alt="rds proxy" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Learn "the saga stepfunction" pattern today - Single Table DynamoDB, Lambdas, Step Function and API Gateway</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Fri, 17 Apr 2020 08:10:24 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/learn-the-saga-stepfunction-pattern-today-single-table-dynamodb-lambdas-step-function-and-api-gateway-2o0a</link>
      <guid>https://dev.to/cdkpatterns/learn-the-saga-stepfunction-pattern-today-single-table-dynamodb-lambdas-step-function-and-api-gateway-2o0a</guid>
      <description>&lt;h1&gt;
  
  
  Youtube Walkthrough
&lt;/h1&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/1nJNx6_KSRU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting The Code
&lt;/h1&gt;

&lt;p&gt;This is available on &lt;a href="https://github.com/cdk-patterns/serverless" rel="noopener noreferrer"&gt;cdkpatterns.com&lt;/a&gt; or you can run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Typescript version
npx cdkp init the-saga-stepfunction

// Python version
npx cdkp init the-saga-stepfunction --lang=python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The Saga Step Function
&lt;/h1&gt;

&lt;p&gt;This is a pattern that I found via &lt;a href="https://twitter.com/theburningmonk" rel="noopener noreferrer"&gt;Yan Cui&lt;/a&gt; and his 2017 &lt;a href="https://theburningmonk.com/2017/07/applying-the-saga-pattern-with-aws-lambda-and-step-functions/" rel="noopener noreferrer"&gt;Blog Post&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;After doing research I found some other references:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Author&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hector Garcia-Molina&lt;/td&gt;
&lt;td&gt;&lt;a href="http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf" rel="noopener noreferrer"&gt;Research Paper&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Well Architected WhitePaper&lt;/td&gt;
&lt;td&gt;&lt;a href="https://d1.awsstatic.com/whitepapers/architecture/AWS-Serverless-Applications-Lens.pdf" rel="noopener noreferrer"&gt;Serverless Application Lens&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://twitter.com/theburningmonk" rel="noopener noreferrer"&gt;Yan Cui&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://theburningmonk.com/2017/07/applying-the-saga-pattern-with-aws-lambda-and-step-functions/" rel="noopener noreferrer"&gt;Blog Post&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://twitter.com/caitie" rel="noopener noreferrer"&gt;Caitie McCaffrey&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.youtube.com/watch?v=xDuwrtwYHu8" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.youtube.com%2Fvi%2FxDuwrtwYHu8%2F0.jpg" alt="Alt text"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://twitter.com/heitor_lessa" rel="noopener noreferrer"&gt;Heitor Lessa&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/aws-samples/aws-serverless-airline-booking/tree/develop/src/backend/booking#booking-state-machine" rel="noopener noreferrer"&gt;AWS Serverless Airline Booking Example&lt;/a&gt; and &lt;a href="https://youtu.be/MyoOeHTp2pg?t=1447" rel="noopener noreferrer"&gt;YouTube Recording&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://twitter.com/jeremy_daly" rel="noopener noreferrer"&gt;Jeremy Daly&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://twitter.com/jeremy_daly/status/1151657527475654657" rel="noopener noreferrer"&gt;EventBridge Saga Tweet&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://twitter.com/crichardson" rel="noopener noreferrer"&gt;Chris Richardson&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://microservices.io/patterns/data/saga.html" rel="noopener noreferrer"&gt;Blog Post&lt;/a&gt; and &lt;a href="https://microservices.io/book" rel="noopener noreferrer"&gt;Book&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://medium.com/@chaosgears" rel="noopener noreferrer"&gt;Chaos Gears&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://medium.com/@chaosgears/saga-patterns-inside-step-functions-world-b330c40fb9d5" rel="noopener noreferrer"&gt;Blog Post&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dzone.com/users/3207440/yosriady.html" rel="noopener noreferrer"&gt;Yos Riady&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dzone.com/articles/distributed-sagas-for-microservices" rel="noopener noreferrer"&gt;Blog Post&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Is The Saga Pattern?
&lt;/h2&gt;

&lt;p&gt;Hector Garcia-Molina described it in his &lt;a href="http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf" rel="noopener noreferrer"&gt;paper&lt;/a&gt; as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Long lived transactions (LLTs) hold on to database resources for relatively long periods of&lt;br&gt;
time, signficantly delaying the termination of shorter and more common transactions To alleviate these problems we &lt;br&gt;
propose the notion of a saga.&lt;/p&gt;

&lt;p&gt;A LLT is a saga if it can be written as a sequence of transactions that can be interleaved&lt;br&gt;
with other transactions. The database management system guarantees that either all the transactions in a saga are successfully completed or compensating transactions are run to amend a partial execution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can think of this as a complete transaction is made up of a series of smaller tasks. We need all of these tasks to&lt;br&gt;
be successful for us to call the transaction a success.&lt;/p&gt;

&lt;p&gt;Caitie uses a holiday booking example to demonstrate this which Yan elaborated on so let's continue the trend. If you are booking a holiday let's say you need at a minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To Book Flights&lt;/li&gt;
&lt;li&gt;To Book A hotel&lt;/li&gt;
&lt;li&gt;To Pay&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You wouldn't be very happy if you booked a holiday then found out when you landed that you had a reservation at the hotel but an error occured with payment so they gave it away. The saga pattern forces you to have a compensating action for that payment error, either you have some other payment selection process or you roll back the whole booking and ask the customer to try again.&lt;/p&gt;

&lt;p&gt;Every action must have a corresponding reaction for error. Note the reaction cannot always be equal as Caitie points out, if one of the actions was to send an email you cannot undo that send but you can send a follow up to say it was an error.&lt;/p&gt;

&lt;p&gt;If we assume from this point we will roll back when an error hits then the flow might look something like:&lt;/p&gt;
&lt;h3&gt;
  
  
  Success
&lt;/h3&gt;

&lt;p&gt;This flows as you might expect - we reserve a room in the hotel, a spot on the plane, take the payment, then confirm the booking with the airline and hotel. Finally we notify the customer that it was a successful booking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxl5dgrctqzv8axwb1c6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxl5dgrctqzv8axwb1c6u.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Failure
&lt;/h3&gt;

&lt;p&gt;If after reserving the flight and hotel our payment fails then we need to release that reservation and notify the customer it failed.&lt;/p&gt;

&lt;p&gt;Notice how it peels back the layers, it doesn't do one massive compensation step. It runs the cancel steps in reverse order until the system should be the way it was before we started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjnp3fu74y7pg6cl87r14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjnp3fu74y7pg6cl87r14.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the first ReserveHotel task had failed the only difference is the number of Cancel tasks that run:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F746gazjbaabvqhdjy6c8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F746gazjbaabvqhdjy6c8.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What Does The Saga Step Function Look Like?
&lt;/h2&gt;

&lt;p&gt;We have an API Gateway connected to a Lambda through a {proxy+} setup. This lambda starts a stepfunction workflow representing the flows above. 8 lambdas inside that workflow communicate with 1 DynamoDB table to complete a travel booking transaction:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzm2fwxf5k6wqkso1pxz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzm2fwxf5k6wqkso1pxz9.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Saga Lambda and Step Fuction Exection
&lt;/h3&gt;

&lt;p&gt;The Saga Lambda is a function that takes in input from the query parameters in the url and passes them to a step function execution. The data passed to the step function looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;trip_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tripID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//taken from queryParams&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;depart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;London&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;depart_at&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2021-07-10T06:00:00.000Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arrive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dublin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arrive_at&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2021-07-12T08:00:00.000Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hotel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;holiday inn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;check_in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2021-07-10T12:00:00.000Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;check_out&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2021-07-12T14:00:00.000Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rental&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Volvo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rental_from&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2021-07-10T00:00:00.000Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rental_to&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2021-07-12T00:00:00.000Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run_type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;runType&lt;/span&gt; &lt;span class="c1"&gt;//taken from queryParams&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lambdas Inside Our Step Function
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Author&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reserve Hotel&lt;/td&gt;
&lt;td&gt;Inserts a record into DynamoDB for our hotel booking with a transaction_status of pending&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reserve Flight&lt;/td&gt;
&lt;td&gt;Inserts a record into DynamoDB for our flight booking with a transaction_status of pending&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cancel Hotel Reservation&lt;/td&gt;
&lt;td&gt;Deletes the record from DynamoDB for our pending hotel booking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cancel Flight Reservation&lt;/td&gt;
&lt;td&gt;Deletes the record from DynamoDB for our pending Flight booking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Take Payment&lt;/td&gt;
&lt;td&gt;Inserts a record into DynamoDB for the payment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cancel Payment&lt;/td&gt;
&lt;td&gt;Deletes the record from DynamoDB for the payment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirm Hotel&lt;/td&gt;
&lt;td&gt;Updates the record in DynamoDB for transaction_status to confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirm Flight&lt;/td&gt;
&lt;td&gt;Updates the record in DynamoDB for transaction_status to confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Error Handling and Retry Logic
&lt;/h3&gt;

&lt;p&gt;If an error occurs in any of the reserve tasks, confirm tasks or the take payment task (either by you manually passing the trigger or a real error) we have step function catch logic to route to the appropriate cancel event.&lt;/p&gt;

&lt;p&gt;You also need to account for errors in the cancel functions. That is why there is a random fail trigger in each cancel function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internal Server Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To handle this each cancel function has a built in retry policy of 3 attempts as part of the step function definition.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB Table
&lt;/h3&gt;

&lt;p&gt;We have 3 separate entities inside the one DynamoDB table, this was inspired by &lt;a href="https://twitter.com/alexbdebrie" rel="noopener noreferrer"&gt;Alex Debrie&lt;/a&gt; and his brilliant &lt;a href="https://www.dynamodbbook.com/" rel="noopener noreferrer"&gt;book&lt;/a&gt;. If you want to learn more about advanced single table DynamoDB patterns it is worth a purchase.&lt;/p&gt;

&lt;p&gt;You can see that the sort key on our table is overloaded to allow us to effectively filter results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fohvos8ub7pmf2bqmld8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fohvos8ub7pmf2bqmld8b.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More columns exist than is shown above. The data inserted for each record is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Hotel Data Model&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HOTEL#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;hotelBookingID&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trip_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hotel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hotelBookingID&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hotel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hotel&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;check_in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;check_in&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;check_out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;check_out&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transaction_status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Flights Data Model&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FLIGHT#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;flightBookingID&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Flight&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trip_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flightBookingID&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;depart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;depart&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;depart_at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;depart_at&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arrive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arrive&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arrive_at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arrive_at&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transaction_status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Payments Data Model&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PAYMENT#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;paymentID&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trip_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trip_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;paymentID&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;amount&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;450.00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transaction_status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Do I Test This After Deployment?
&lt;/h2&gt;

&lt;p&gt;After deployment you should have an API Gateway where any url you hit triggers the step function to start.&lt;/p&gt;

&lt;p&gt;You can manipulate the flow of the step function with a couple of url parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Successful Execution - https://{api gateway url}
Reserve Hotel Fail - https://{api gateway url}?runType=failHotelReservation
Confirm Hotel Fail - https://{api gateway url}?runType=failHotelConfirmation
Reserve Flight Fail - https://{api gateway url}?runType=failFlightsReservation
Confirm Flight Fail - https://{api gateway url}?runType=failFlightsConfirmation
Take Payment Fail - https://{api gateway url}?runType=failPayment

Inserting Muliple trips into DynamoDB, by default it will use the same ID on every execution
https://{api gateway url}?tripID={whatever you want}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to note that the Cancel Lambdas all have a random failure built in and retry logic up to a max of 3. So when you look at the execution of your stepfunction in the aws console if you see failures in the cancel lambdas this is intentional. The reason why is to teach you that the cancel logic should attempt to self recover in the event of an error. Given that they only retry 3 times it is still possible for the cancel process to fail 3 times and the step function to terminate early. &lt;/p&gt;

&lt;p&gt;To actually view what happened you will need to log into the AWS console and navigate to the step functions section where you can see every execution of your saga step function. You can also look inside the DynamoDB table at the records inserted. If you are fast enough with refresh you can watch them go from pending to confirmed status.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Watch me deconstruct "The EventBridge ETL" Serverless Architecture Pattern</title>
      <dc:creator>Matt Coulter</dc:creator>
      <pubDate>Sun, 12 Apr 2020 08:11:44 +0000</pubDate>
      <link>https://dev.to/cdkpatterns/watch-me-deconstruct-the-eventbridge-etl-serverless-architecture-pattern-39cg</link>
      <guid>https://dev.to/cdkpatterns/watch-me-deconstruct-the-eventbridge-etl-serverless-architecture-pattern-39cg</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8kg5bYsdem4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  The EventBridge ETL
&lt;/h1&gt;

&lt;p&gt;This is an example stack showing how you can use EventBridge to orchestrate events through an ETL process. This pattern was insired by &lt;a href="https://twitter.com/madladvyas" rel="noopener noreferrer"&gt;Vyas Sarangapani&lt;/a&gt; and &lt;a href="https://twitter.com/hervenivon" rel="noopener noreferrer"&gt;Hervé Nivon&lt;/a&gt; as you can see at the bottom of this page.&lt;/p&gt;

&lt;p&gt;Note - This is a learning pattern, if I was implementing this in a production system I would make a couple of changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KMS Encryption of sensitive data in events&lt;/li&gt;
&lt;li&gt;SQS between EventBridge and the Lambdas for resiliency&lt;/li&gt;
&lt;li&gt;Add in error events to EventBridge and error event rules&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy1j4m309jgt19ib6fxmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy1j4m309jgt19ib6fxmo.png" alt="Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Architecture Notes
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Fargate ECS Task
&lt;/h5&gt;

&lt;p&gt;I chose to use a Fargate container to download the file from s3 rather than using Lambda. For the small bundled test data csv Lambda would have worked but I felt it would be misleading and suggestive that you could pull larger files down onto a Lambda function. Lambda functions have a few limitations around memory, storage and runtime. You can do things like partially stream files from s3 to Lambda (if they happen to be in the right format) and then store state somewhere between timeouts but I felt that having an ECS Task that you can define CPU, RAM and Disk Space was the much more flexible way to go and being Fargate you are still on the serverless spectrum. You can see how cheap Fargate is if you go into the cost breakdown in Hervé's GitHub repo.&lt;/p&gt;

&lt;h5&gt;
  
  
  Throttling The Lambda Functions
&lt;/h5&gt;

&lt;p&gt;Without throttling, if you put every row in a huge csv file onto EventBridge with a subscriber lambda; That lambda can scale up until it uses all the concurrency on your account. This may be what you want (probably not though). That is why I limited all the concurrency of the lambdas, you can remove this limit or tweak as much as you want but you always need to think about what else is running in that account. Isolate your stack into its own account if possible.&lt;/p&gt;

&lt;h5&gt;
  
  
  Observer Lambda
&lt;/h5&gt;

&lt;p&gt;In the current format this is more of a technical demo to show what is possible with event driven architectures. Everything that it logs is already in the logs of all the individual components. You could probably use this to keep a tally for every record that gets pulled from the csv to make sure it gets inserted into DynamoDB by pulling the ids from the extraction and load events.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Would Use This Pattern
&lt;/h2&gt;

&lt;p&gt;If you need to create a process where a user uploads a csv and it gets transformed and inserted into DynamoDB&lt;/p&gt;

&lt;h2&gt;
  
  
  How to test pattern
&lt;/h2&gt;

&lt;p&gt;After deployment you will have an s3 bucket where if you go into the aws console for that bucket and upload the file &lt;a href="//data-to-upload/test_data.csv"&gt;test_data.csv&lt;/a&gt; found in the data-to-upload folder you will kick everything off.&lt;/p&gt;

&lt;p&gt;After you upload that file everything should automatically start working. You should be able to watch the process by looking in the cloudwatch logs for your observer lambda. Note this is a multi-threaded, concurrent process so the order of the events in the observer logs may not be what you were expecting!&lt;/p&gt;

&lt;p&gt;Finally all of the data ends up in your DynamoDB table so you should be able to open it in the console and view the data after transform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern Origins
&lt;/h2&gt;

&lt;p&gt;This pattern was insired by two people:&lt;/p&gt;

&lt;h3&gt;
  
  
  Vyas Sarangapani
&lt;/h3&gt;

&lt;p&gt;Twitter - &lt;a href="https://twitter.com/madladvyas" rel="noopener noreferrer"&gt;link&lt;/a&gt; &lt;br&gt;&lt;br&gt;
Full Article explaining architecture on &lt;a href="https://medium.com/@svyasrao22/how-to-build-a-scalable-cost-effective-event-driven-etl-solution-using-serverless-b407c14d4093" rel="noopener noreferrer"&gt;medium&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Architecture
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faxfrof3zev9crtvliz0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faxfrof3zev9crtvliz0u.png" alt="Vyas Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hervé Nivon
&lt;/h3&gt;

&lt;p&gt;Twitter - &lt;a href="https://twitter.com/hervenivon" rel="noopener noreferrer"&gt;link&lt;/a&gt; &lt;br&gt;&lt;br&gt;
Github - &lt;a href="https://github.com/hervenivon/aws-experiments-data-ingestion-and-analytics" rel="noopener noreferrer"&gt;repo&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Architecture
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb11pv8sw0z1xmnulx7ol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb11pv8sw0z1xmnulx7ol.png" alt="Herve Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
