<?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: Kasun de Silva</title>
    <description>The latest articles on DEV Community by Kasun de Silva (@kasundsilva).</description>
    <link>https://dev.to/kasundsilva</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%2Fuser%2Fprofile_image%2F1009425%2F1af61d95-5377-48ae-952b-e9f10f55aa97.jpeg</url>
      <title>DEV Community: Kasun de Silva</title>
      <link>https://dev.to/kasundsilva</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kasundsilva"/>
    <language>en</language>
    <item>
      <title>Simplify AWS Lambda Deployments Using GitHub Actions</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Fri, 15 Aug 2025 00:49:44 +0000</pubDate>
      <link>https://dev.to/aws-builders/simplify-aws-lambda-deployments-using-github-actions-43om</link>
      <guid>https://dev.to/aws-builders/simplify-aws-lambda-deployments-using-github-actions-43om</guid>
      <description>&lt;p&gt;Hey, serverless builders! 🚀 Exciting news from AWS!&lt;/p&gt;

&lt;p&gt;AWS has launched a feature that direct support for deploying AWS Lambda functions using GitHub Actions. This new capability significantly streamlines the deployment process, eliminating the need for complex, custom scripting and boilerplate code.&lt;/p&gt;

&lt;p&gt;Before this, deploying a Lambda function from a GitHub workflow required manual steps to package code, configure IAM roles, and handle potential errors. Now, a dedicated GitHub Action handles all of this for you with a simple, declarative YAML configuration. This means less friction, faster deployments, and more time for you to focus on building amazing serverless applications.&lt;/p&gt;




&lt;h3&gt;
  
  
  What's New?
&lt;/h3&gt;

&lt;p&gt;The new &lt;strong&gt;"Deploy Lambda Function" GitHub Action&lt;/strong&gt; simplifies your CI/CD pipeline by providing a direct and secure way to update your Lambda functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Declarative Configuration:&lt;/strong&gt; Define your deployment settings—like runtime, memory, and environment variables—directly in your GitHub Actions workflow file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Packaging:&lt;/strong&gt; The action automatically handles the packaging of your function code, supporting both &lt;code&gt;.zip&lt;/code&gt; file and container image deployments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless IAM Integration:&lt;/strong&gt; It integrates with AWS IAM using &lt;strong&gt;OpenID Connect (OIDC)&lt;/strong&gt; authentication, which is the most secure way to grant your GitHub workflows temporary, short-lived credentials without ever storing long-lived secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This new workflow is a huge win for developer experience, making it easier than ever to adopt a fully automated, Git-based deployment strategy for your serverless projects.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step-by-Step Guide: Deploying a Lambda Function with GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Ready to get started? Here's how you can set up a GitHub Actions workflow to automatically deploy your Lambda function.&lt;/p&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;A Lambda Function:&lt;/strong&gt; You need an existing AWS Lambda function. If you don't have one, create it in the AWS Management Console or with the AWS CLI.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;IAM Role for OIDC:&lt;/strong&gt; Configure an IAM role in your AWS account that trusts GitHub's OIDC provider. This role will grant your workflow the permissions it needs to deploy the function. This is a crucial security step!&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;A GitHub Repository:&lt;/strong&gt; Your Lambda function code should be in a GitHub repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 1: Configure IAM for OIDC
&lt;/h4&gt;

&lt;p&gt;First, set up a trusted relationship between your AWS account and GitHub.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to &lt;strong&gt;IAM&lt;/strong&gt; in the AWS console.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Access management&lt;/strong&gt;, select &lt;strong&gt;Identity providers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Add provider&lt;/strong&gt; and configure an &lt;strong&gt;OpenID Connect&lt;/strong&gt; provider with the URL: &lt;code&gt;https://token.actions.githubusercontent.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a new IAM role that uses this provider and grant it the necessary permissions, such as &lt;code&gt;lambda:UpdateFunctionCode&lt;/code&gt; and &lt;code&gt;lambda:UpdateFunctionConfiguration&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2: Create Your GitHub Actions Workflow File
&lt;/h4&gt;

&lt;p&gt;In your GitHub repository, create a new file at &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;. This YAML file defines the deployment process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Lambda Function&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt; &lt;span class="c1"&gt;# This workflow runs on pushes to the 'main' branch&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt; &lt;span class="c1"&gt;# Required for OIDC authentication&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;  &lt;span class="c1"&gt;# Required to check out the repository&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::123456789012:role/GitHubActionRole&lt;/span&gt; &lt;span class="c1"&gt;# Replace with your IAM role ARN&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt; &lt;span class="c1"&gt;# Replace with your AWS region&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Lambda Function&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/aws-lambda-deploy@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;function-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-lambda-function&lt;/span&gt; &lt;span class="c1"&gt;# Replace with your function name&lt;/span&gt;
          &lt;span class="na"&gt;code-artifacts-dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./dist&lt;/span&gt; &lt;span class="c1"&gt;# The directory containing your packaged code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Push Your Code and Watch it Deploy!
&lt;/h4&gt;

&lt;p&gt;That's it! When you push new code to the &lt;code&gt;main&lt;/code&gt; branch of your repository, GitHub Actions will automatically trigger this workflow. The &lt;code&gt;aws-lambda-deploy&lt;/code&gt; action will package the code from your specified directory (&lt;code&gt;./dist&lt;/code&gt; in this example) and deploy it to your Lambda function.&lt;/p&gt;




&lt;h3&gt;
  
  
  Beyond the Basics
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;aws-lambda-deploy&lt;/code&gt; action is highly configurable. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deploy via Amazon S3:&lt;/strong&gt; For larger deployment packages, you can specify an S3 bucket to use as an intermediate location.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure Function Settings:&lt;/strong&gt; Update your Lambda function's runtime, memory, timeout, and environment variables directly within the workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Dry Run Mode:&lt;/strong&gt; Test your deployment configuration and permissions without making any changes to the function itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this new feature, AWS is making it simpler and more secure to manage the entire lifecycle of your serverless applications. Happy coding! 💻✨&lt;/p&gt;

&lt;p&gt;For more details and advanced examples, check out the &lt;strong&gt;AWS Lambda Deploy GitHub Action&lt;/strong&gt; repository: &lt;a href="https://github.com/aws-actions/aws-lambda-deploy" rel="noopener noreferrer"&gt;https://github.com/aws-actions/aws-lambda-deploy&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>githubactions</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Lets Encrypt DNS Challenge with Traefik and AWS Route 53</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Fri, 15 Aug 2025 00:46:58 +0000</pubDate>
      <link>https://dev.to/kasundsilva/lets-encrypt-dns-challenge-with-traefik-and-aws-route-53-1312</link>
      <guid>https://dev.to/kasundsilva/lets-encrypt-dns-challenge-with-traefik-and-aws-route-53-1312</guid>
      <description>&lt;p&gt;So, you're self-hosting awesome apps like Jellyfin, Home Assistant, or your personal blog with Docker. You want that sweet, sweet HTTPS padlock for secure connections, and Let's Encrypt is the obvious choice for free SSL certs. Awesome!&lt;/p&gt;

&lt;p&gt;You set up your reverse proxy (maybe Traefik, because it's slick!), point it to your app, and tell it to get a certificate... only to hit a wall. Why? Meet the home networker's nemesis: &lt;strong&gt;ISPs blocking incoming port 80.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Standard Way (and the Wall)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's Encrypt's default validation method, &lt;code&gt;HTTP-01&lt;/code&gt;, is simple: their servers try to access a special file on &lt;em&gt;your&lt;/em&gt; server over standard HTTP (port &lt;code&gt;80&lt;/code&gt;) to prove you control the domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Your Public IP:80 -&amp;gt; Does challenge file exist? -&amp;gt; OK! Cert Issued!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if your ISP blocks incoming connections on port &lt;code&gt;80&lt;/code&gt; (super common on residential plans!), Let's Encrypt's request never reaches your server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Your Public IP:80 -&amp;gt; [ISP BLOCK] -&amp;gt; Challenge Failed! No Cert! :(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frustrating, right? Your quest for HTTPS seems doomed... or is it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The DNS-01 Challenge: A Different Kind of Proof&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;DNS-01&lt;/code&gt; challenge – Let's Encrypt's clever workaround. Instead of checking a file via HTTP, it asks you to prove domain ownership by creating a specific &lt;strong&gt;DNS TXT record&lt;/strong&gt; with a unique value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Checks Your Domain's DNS Records -&amp;gt; Does specific TXT record exist? -&amp;gt; OK! Cert Issued!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this validation happens entirely via DNS lookups (usually port &lt;code&gt;53&lt;/code&gt;, which is almost never blocked inbound for lookups), it completely bypasses the port &lt;code&gt;80&lt;/code&gt; problem!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Magic Combo: Traefik + AWS Route 53&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay, manually creating DNS records every ~90 days sounds tedious. This is where the dynamic duo comes in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Traefik:&lt;/strong&gt; Our smart reverse proxy knows how to talk the ACME protocol and request certificates using the DNS-01 method.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;AWS Route 53:&lt;/strong&gt; A robust, API-driven DNS service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You configure Traefik with AWS API credentials (using an IAM user with &lt;em&gt;just enough&lt;/em&gt; permission to modify Route 53 records – security first!). When it's time to issue or renew a cert, Traefik tells Route 53 (via the API) to create the temporary TXT record Let's Encrypt needs. Once Let's Encrypt verifies it, Traefik tells Route 53 to clean it up. &lt;em&gt;Chef's kiss!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Key Configuration (Traefik + Docker Compose):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your Traefik service definition within &lt;code&gt;docker-compose.yml&lt;/code&gt;, the magic lies in the command arguments for your certificate resolver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Snippet from docker-compose.yml command section for Traefik&lt;/span&gt;
&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other args ...&lt;/span&gt;
  &lt;span class="c1"&gt;# Let's Encrypt Resolver Config&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.email=your-email@example.com"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"&lt;/span&gt;
  &lt;span class="c1"&gt;# --- THE IMPORTANT PART ---&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge=true"&lt;/span&gt;          &lt;span class="c1"&gt;# Enable DNS Challenge&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53"&lt;/span&gt; &lt;span class="c1"&gt;# Tell it to use AWS Route 53&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other args ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need to securely provide your AWS credentials (Access Key ID &amp;amp; Secret) as environment variables, preferably using a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion: Problem Solved!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By switching to the DNS-01 challenge and leveraging the automation power of Traefik integrated with the AWS Route 53 API, the infamous port &lt;code&gt;80&lt;/code&gt; block becomes irrelevant for getting your Let's Encrypt certificates. You get fully automated, secure HTTPS for your self-hosted services without hassle. Now &lt;em&gt;that's&lt;/em&gt; cool.&lt;/p&gt;

&lt;p&gt;Happy (secure) self-hosting!&lt;/p&gt;




</description>
      <category>route53</category>
      <category>dns01</category>
      <category>letsencrypt</category>
      <category>dns</category>
    </item>
    <item>
      <title>Let's Encrypt DNS Challenge with Traefik and AWS Route 53</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Fri, 15 Aug 2025 00:46:30 +0000</pubDate>
      <link>https://dev.to/kasundsilva/lets-encrypt-dns-challenge-with-traefik-and-aws-route-53-3b5e</link>
      <guid>https://dev.to/kasundsilva/lets-encrypt-dns-challenge-with-traefik-and-aws-route-53-3b5e</guid>
      <description>&lt;p&gt;So, you're self-hosting awesome apps like Jellyfin, Home Assistant, or your personal blog with Docker. You want that sweet, sweet HTTPS padlock for secure connections, and Let's Encrypt is the obvious choice for free SSL certs. Awesome!&lt;/p&gt;

&lt;p&gt;You set up your reverse proxy (maybe Traefik, because it's slick!), point it to your app, and tell it to get a certificate... only to hit a wall. Why? Meet the home networker's nemesis: &lt;strong&gt;ISPs blocking incoming port 80.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Standard Way (and the Wall)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's Encrypt's default validation method, &lt;code&gt;HTTP-01&lt;/code&gt;, is simple: their servers try to access a special file on &lt;em&gt;your&lt;/em&gt; server over standard HTTP (port &lt;code&gt;80&lt;/code&gt;) to prove you control the domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Your Public IP:80 -&amp;gt; Does challenge file exist? -&amp;gt; OK! Cert Issued!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if your ISP blocks incoming connections on port &lt;code&gt;80&lt;/code&gt; (super common on residential plans!), Let's Encrypt's request never reaches your server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Your Public IP:80 -&amp;gt; [ISP BLOCK] -&amp;gt; Challenge Failed! No Cert! :(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frustrating, right? Your quest for HTTPS seems doomed... or is it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The DNS-01 Challenge: A Different Kind of Proof&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;DNS-01&lt;/code&gt; challenge – Let's Encrypt's clever workaround. Instead of checking a file via HTTP, it asks you to prove domain ownership by creating a specific &lt;strong&gt;DNS TXT record&lt;/strong&gt; with a unique value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Checks Your Domain's DNS Records -&amp;gt; Does specific TXT record exist? -&amp;gt; OK! Cert Issued!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this validation happens entirely via DNS lookups (usually port &lt;code&gt;53&lt;/code&gt;, which is almost never blocked inbound for lookups), it completely bypasses the port &lt;code&gt;80&lt;/code&gt; problem!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Magic Combo: Traefik + AWS Route 53&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay, manually creating DNS records every ~90 days sounds tedious. This is where the dynamic duo comes in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Traefik:&lt;/strong&gt; Our smart reverse proxy knows how to talk the ACME protocol and request certificates using the DNS-01 method.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;AWS Route 53:&lt;/strong&gt; A robust, API-driven DNS service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You configure Traefik with AWS API credentials (using an IAM user with &lt;em&gt;just enough&lt;/em&gt; permission to modify Route 53 records – security first!). When it's time to issue or renew a cert, Traefik tells Route 53 (via the API) to create the temporary TXT record Let's Encrypt needs. Once Let's Encrypt verifies it, Traefik tells Route 53 to clean it up. &lt;em&gt;Chef's kiss!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Key Configuration (Traefik + Docker Compose):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your Traefik service definition within &lt;code&gt;docker-compose.yml&lt;/code&gt;, the magic lies in the command arguments for your certificate resolver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Snippet from docker-compose.yml command section for Traefik&lt;/span&gt;
&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other args ...&lt;/span&gt;
  &lt;span class="c1"&gt;# Let's Encrypt Resolver Config&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.email=your-email@example.com"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"&lt;/span&gt;
  &lt;span class="c1"&gt;# --- THE IMPORTANT PART ---&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge=true"&lt;/span&gt;          &lt;span class="c1"&gt;# Enable DNS Challenge&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53"&lt;/span&gt; &lt;span class="c1"&gt;# Tell it to use AWS Route 53&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other args ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need to securely provide your AWS credentials (Access Key ID &amp;amp; Secret) as environment variables, preferably using a &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion: Problem Solved!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By switching to the DNS-01 challenge and leveraging the automation power of Traefik integrated with the AWS Route 53 API, the infamous port &lt;code&gt;80&lt;/code&gt; block becomes irrelevant for getting your Let's Encrypt certificates. You get fully automated, secure HTTPS for your self-hosted services without hassle. Now &lt;em&gt;that's&lt;/em&gt; cool.&lt;/p&gt;

&lt;p&gt;Happy (secure) self-hosting!&lt;/p&gt;




</description>
      <category>route53</category>
      <category>dns01</category>
      <category>letsencrypt</category>
      <category>dns</category>
    </item>
    <item>
      <title>Let's Encrypt DNS-01 Challenge with Traefik and AWS Route 53</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Tue, 06 May 2025 00:10:54 +0000</pubDate>
      <link>https://dev.to/aws-builders/lets-encrypt-dns-challenge-with-traefik-and-aws-route-53-1l1f</link>
      <guid>https://dev.to/aws-builders/lets-encrypt-dns-challenge-with-traefik-and-aws-route-53-1l1f</guid>
      <description>&lt;p&gt;So, you're self-hosting awesome apps like Jellyfin, Home Assistant, or your personal blog with Docker. You want that sweet, sweet HTTPS padlock for secure connections, and Let's Encrypt is the obvious choice for free SSL certs. Awesome!&lt;/p&gt;

&lt;p&gt;You set up your reverse proxy (maybe Traefik, because it's slick!), point it to your app, and tell it to get a certificate... only to hit a wall. Why? Meet the home networker's nemesis: &lt;strong&gt;ISPs blocking incoming port 80.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Standard Way (and the Wall)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's Encrypt's default validation method, &lt;code&gt;HTTP-01&lt;/code&gt;, is simple: their servers try to access a special file on &lt;em&gt;your&lt;/em&gt; server over standard HTTP (port &lt;code&gt;80&lt;/code&gt;) to prove you control the domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Your Public IP:80 -&amp;gt; Does challenge file exist? -&amp;gt; OK! Cert Issued!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if your ISP blocks incoming connections on port &lt;code&gt;80&lt;/code&gt; (super common on residential plans!), Let's Encrypt's request never reaches your server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Your Public IP:80 -&amp;gt; [ISP BLOCK] -&amp;gt; Challenge Failed! No Cert! :(
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frustrating, right? Your quest for HTTPS seems doomed... or is it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The DNS-01 Challenge: A Different Kind of Proof&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enter the &lt;code&gt;DNS-01&lt;/code&gt; challenge – Let's Encrypt's clever workaround. Instead of checking a file via HTTP, it asks you to prove domain ownership by creating a specific &lt;strong&gt;DNS TXT record&lt;/strong&gt; with a unique value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Let's Encrypt -&amp;gt; Checks Your Domain's DNS Records -&amp;gt; Does specific TXT record exist? -&amp;gt; OK! Cert Issued!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this validation happens entirely via DNS lookups (usually port &lt;code&gt;53&lt;/code&gt;, which is almost never blocked inbound for lookups), it completely bypasses the port &lt;code&gt;80&lt;/code&gt; problem!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Magic Combo: Traefik + AWS Route 53&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay, manually creating DNS records every ~90 days sounds tedious. This is where the dynamic duo comes in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Traefik:&lt;/strong&gt; Our smart reverse proxy knows how to talk the ACME protocol and request certificates using the DNS-01 method.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;AWS Route 53:&lt;/strong&gt; A robust, API-driven DNS service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You configure Traefik with AWS API credentials (using an IAM user with &lt;em&gt;just enough&lt;/em&gt; permission to modify Route 53 records – security first!). When it's time to issue or renew a cert, Traefik tells Route 53 (via the API) to create the temporary TXT record Let's Encrypt needs. Once Let's Encrypt verifies it, Traefik tells Route 53 to clean it up. &lt;em&gt;Chef's kiss!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Key Configuration (Traefik + Docker Compose):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In your Traefik service definition within &lt;code&gt;docker-compose.yml&lt;/code&gt;, the magic lies in the command arguments for your certificate resolver:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Snippet from docker-compose.yml command section for Traefik&lt;/span&gt;
&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other args ...&lt;/span&gt;
  &lt;span class="c1"&gt;# Let's Encrypt Resolver Config&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.email=your-email@example.com"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"&lt;/span&gt;
  &lt;span class="c1"&gt;# --- THE IMPORTANT PART ---&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge=true"&lt;/span&gt;          &lt;span class="c1"&gt;# Enable DNS Challenge&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53"&lt;/span&gt; &lt;span class="c1"&gt;# Tell it to use AWS Route 53&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other args ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Environment Vars&lt;/strong&gt;&lt;br&gt;
You also need to securely provide your AWS credentials (Access Key ID &amp;amp; Secret) as environment variables, preferably using a &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Environment variables for AWS credentials (will use .env file)&lt;/span&gt;
&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_REGION&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_HOSTED_ZONE_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Complete example config,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Traefik Service (Reverse Proxy &amp;amp; SSL)&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik:v2.11"&lt;/span&gt; &lt;span class="c1"&gt;# Pin to a specific stable version&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik-proxy"&lt;/span&gt; &lt;span class="c1"&gt;# Descriptive container name&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Enable Docker provider &amp;amp; disable exposing by default&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--providers.docker=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--providers.docker.exposedbydefault=false"&lt;/span&gt;
      &lt;span class="c1"&gt;# Define HTTP (80) and HTTPS (443) entry points&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.address=:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.websecure.address=:443"&lt;/span&gt;
      &lt;span class="c1"&gt;# Enable Traefik API/Dashboard (for monitoring)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--api.dashboard=true"&lt;/span&gt;
      &lt;span class="c1"&gt;# Configure Let's Encrypt Resolver (named 'myresolver')&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.email=your-email@example.com"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE THIS with your email !!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"&lt;/span&gt;
      &lt;span class="c1"&gt;# Use DNS-01 challenge with Route53 provider&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53"&lt;/span&gt;
      &lt;span class="c1"&gt;# Global Redirect: HTTP -&amp;gt; HTTPS&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.http.redirections.entrypoint.to=websecure"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.http.redirections.entrypoint.scheme=https"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Expose port 80 for HTTP-&amp;gt;HTTPS redirect (optional if ISP blocks)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="c1"&gt;# Expose port 443 for HTTPS access (ESSENTIAL)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Mount Docker socket to detect container events&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock:ro"&lt;/span&gt;
      &lt;span class="c1"&gt;# Persist Let's Encrypt certificates&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./letsencrypt:/letsencrypt"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;proxy&lt;/span&gt; &lt;span class="c1"&gt;# Connect to our custom network&lt;/span&gt;
    &lt;span class="c1"&gt;# Environment variables for AWS credentials (will use .env file)&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_REGION&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_HOSTED_ZONE_ID&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Enable Traefik for its own dashboard&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="c1"&gt;# Dashboard Router Rule (HTTPS)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.rule=Host(`traefik.yourdomain.com`)"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE with your dashboard hostname !!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.entrypoints=websecure"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.service=api@internal"&lt;/span&gt;
      &lt;span class="c1"&gt;# Use Let's Encrypt for the dashboard domain&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.tls.certresolver=myresolver"&lt;/span&gt;
      &lt;span class="c1"&gt;# Secure the dashboard with Basic Auth&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.middlewares=auth"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.middlewares.auth.basicauth.users=user:$&amp;lt;span&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;class="math-inline"&amp;gt;apr1&amp;lt;/span&amp;gt;&amp;lt;span class="math-inline"&amp;gt;abcdefg&amp;lt;/span&amp;gt;$yourhashedpassword"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE THIS HASH !!&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion: Problem Solved!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By switching to the DNS-01 challenge and leveraging the automation power of Traefik integrated with the AWS Route 53 API, the infamous port &lt;code&gt;80&lt;/code&gt; block becomes irrelevant for getting your Let's Encrypt certificates. You get fully automated, secure HTTPS for your self-hosted services without hassle. Now &lt;em&gt;that's&lt;/em&gt; cool.&lt;/p&gt;

&lt;p&gt;Happy (secure) self-hosting!&lt;/p&gt;




</description>
      <category>route53</category>
      <category>letsencrypt</category>
      <category>dns</category>
      <category>traefik</category>
    </item>
    <item>
      <title>From Plex to Freedom: My Jellyfin Journey with Traefik &amp; AWS Route 53</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Mon, 05 May 2025 08:20:13 +0000</pubDate>
      <link>https://dev.to/kasundsilva/from-plex-to-freedom-my-jellyfin-journey-with-traefik-aws-route-53-4hgb</link>
      <guid>https://dev.to/kasundsilva/from-plex-to-freedom-my-jellyfin-journey-with-traefik-aws-route-53-4hgb</guid>
      <description>&lt;p&gt;Like many, I relied on &lt;strong&gt;Plex&lt;/strong&gt; for years to manage and stream my personal media library – hundreds of movies and countless TV show episodes. It served me well. However, recent shifts towards monetizing core features, like remote streaming, prompted me to look for alternatives. I wanted a solution that was open-source, powerful, and gave me complete control over my media and its access, without unexpected subscription requirements for basic functionality.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Jellyfin&lt;/strong&gt;. It's a fantastic, free software media system that puts you in control. But simply installing it isn't enough; I needed secure, easy remote access for myself and my family, just like I had before.&lt;/p&gt;

&lt;p&gt;This post details my journey setting up Jellyfin locally using &lt;strong&gt;Docker&lt;/strong&gt;, but making it securely accessible from anywhere using &lt;strong&gt;Traefik&lt;/strong&gt; as a reverse proxy, &lt;strong&gt;Let's Encrypt&lt;/strong&gt; for free SSL certificates, and leveraging &lt;strong&gt;AWS Route 53&lt;/strong&gt; for seamless and reliable DNS hosting. If you're comfortable with Docker and use AWS for your DNS, this guide is for you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Stack?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jellyfin:&lt;/strong&gt; Awesome open-source media server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker &amp;amp; Docker Compose:&lt;/strong&gt; Easy deployment, management, and reproducibility of services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traefik:&lt;/strong&gt; A modern, cloud-native reverse proxy that integrates beautifully with Docker. It automatically discovers services and handles SSL certificate management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let's Encrypt:&lt;/strong&gt; Free, automated SSL certificates. Essential for secure HTTPS connections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Route 53:&lt;/strong&gt; Reliable DNS hosting. Crucially, its API allows Traefik to perform the Let's Encrypt DNS-01 challenge automatically – perfect if your ISP blocks port 80 (a common issue!).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;A server or machine (like a NAS, Raspberry Pi, or home server) running &lt;strong&gt;Docker&lt;/strong&gt; and &lt;strong&gt;Docker Compose&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A registered domain name (we'll use &lt;code&gt;yourdomain.com&lt;/code&gt; as an example).&lt;/li&gt;
&lt;li&gt;Your domain's DNS hosted on &lt;strong&gt;AWS Route 53&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;AWS account&lt;/strong&gt; with IAM permissions to modify Route 53 records for &lt;code&gt;yourdomain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Basic familiarity with the command line.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Challenge: Secure Remote Access &amp;amp; The Port 80 Problem
&lt;/h2&gt;

&lt;p&gt;Running Jellyfin locally is easy, but accessing it securely from outside your network requires &lt;strong&gt;HTTPS&lt;/strong&gt;. Let's Encrypt provides free SSL certificates via the &lt;strong&gt;ACME protocol&lt;/strong&gt;. The most common validation method (HTTP-01 challenge) requires your server to be reachable from the internet on port &lt;code&gt;80&lt;/code&gt;. Unfortunately, many residential ISPs block incoming traffic on port &lt;code&gt;80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is where the &lt;strong&gt;DNS-01 challenge&lt;/strong&gt; shines. Instead of checking port &lt;code&gt;80&lt;/code&gt;, Let's Encrypt verifies domain ownership by checking for a specific TXT record in your DNS zone. Since we're using Route 53, Traefik can automatically create and remove these temporary records using the AWS API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: AWS Setup - IAM User for Traefik
&lt;/h2&gt;

&lt;p&gt;Traefik needs permission to modify your Route 53 DNS records for &lt;code&gt;yourdomain.com&lt;/code&gt;. We'll create a dedicated IAM user with &lt;em&gt;only&lt;/em&gt; the necessary permissions (Principle of Least Privilege).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Go to the &lt;strong&gt;IAM console&lt;/strong&gt; in AWS.&lt;/li&gt;
&lt;li&gt; Create a new &lt;strong&gt;User&lt;/strong&gt;. Give it a descriptive name (e.g., &lt;code&gt;traefik-route53-manager&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; Select "&lt;strong&gt;Attach policies directly&lt;/strong&gt;".&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;strong&gt;new policy&lt;/strong&gt;. Use the JSON editor and paste the following policy, replacing &lt;code&gt;YOUR_HOSTED_ZONE_ID&lt;/code&gt; with the actual Route 53 Hosted Zone ID for &lt;code&gt;yourdomain.com&lt;/code&gt; (you can find this in the Route 53 console):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"route53:GetChange"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"route53:ListHostedZonesByName"&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;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"route53:ChangeResourceRecordSets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"route53:ListResourceRecordSets"&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;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:route53:::hostedzone/YOUR_HOSTED_ZONE_ID"&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="p"&gt;]&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;p&gt;&lt;em&gt;&amp;gt; Note: Using &lt;code&gt;ListHostedZonesByName&lt;/code&gt; and filtering by resource ARN for &lt;code&gt;ChangeResourceRecordSets&lt;/code&gt; scopes down permissions significantly.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finish creating the policy (give it a name like &lt;code&gt;TraefikRoute53AccessPolicy&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Attach this new policy to the user you created.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proceed to the "&lt;strong&gt;Security credentials&lt;/strong&gt;" tab for the new user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create an "&lt;strong&gt;Access key&lt;/strong&gt;" - select "&lt;strong&gt;Application running outside AWS&lt;/strong&gt;" as the use case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Carefully copy the Access Key ID and Secret Access Key.&lt;/strong&gt; You won't see the secret key again! Store these securely for the next steps.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 2: Docker Compose Configuration
&lt;/h2&gt;

&lt;p&gt;Now, let's define our services using &lt;code&gt;docker-compose.yml&lt;/code&gt;. This file defines the Traefik reverse proxy and the Jellyfin application itself. Remember to replace the example hostnames (&lt;code&gt;jellyfin.yourdomain.com&lt;/code&gt;, &lt;code&gt;traefik.yourdomain.com&lt;/code&gt;) with your actual desired subdomains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Traefik Service (Reverse Proxy &amp;amp; SSL)&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik:v2.11"&lt;/span&gt; &lt;span class="c1"&gt;# Pin to a specific stable version&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik-proxy"&lt;/span&gt; &lt;span class="c1"&gt;# Descriptive container name&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Enable Docker provider &amp;amp; disable exposing by default&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--providers.docker=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--providers.docker.exposedbydefault=false"&lt;/span&gt;
      &lt;span class="c1"&gt;# Define HTTP (80) and HTTPS (443) entry points&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.address=:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.websecure.address=:443"&lt;/span&gt;
      &lt;span class="c1"&gt;# Enable Traefik API/Dashboard (for monitoring)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--api.dashboard=true"&lt;/span&gt;
      &lt;span class="c1"&gt;# Configure Let's Encrypt Resolver (named 'myresolver')&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.email=your-email@example.com"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE THIS with your email !!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"&lt;/span&gt;
      &lt;span class="c1"&gt;# Use DNS-01 challenge with Route53 provider&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge=true"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--certificatesresolvers.myresolver.acme.dnschallenge.provider=route53"&lt;/span&gt;
      &lt;span class="c1"&gt;# Global Redirect: HTTP -&amp;gt; HTTPS&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.http.redirections.entrypoint.to=websecure"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--entrypoints.web.http.redirections.entrypoint.scheme=https"&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Expose port 80 for HTTP-&amp;gt;HTTPS redirect (optional if ISP blocks)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="c1"&gt;# Expose port 443 for HTTPS access (ESSENTIAL)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Mount Docker socket to detect container events&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock:ro"&lt;/span&gt;
      &lt;span class="c1"&gt;# Persist Let's Encrypt certificates&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./letsencrypt:/letsencrypt"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;proxy&lt;/span&gt; &lt;span class="c1"&gt;# Connect to our custom network&lt;/span&gt;
    &lt;span class="c1"&gt;# Environment variables for AWS credentials (will use .env file)&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;
      &lt;span class="c1"&gt;# - AWS_REGION=us-east-1 # Optional: Specify if needed&lt;/span&gt;
      &lt;span class="c1"&gt;# - AWS_HOSTED_ZONE_ID=YOUR_HOSTED_ZONE_ID # Optional&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Enable Traefik for its own dashboard&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="c1"&gt;# Dashboard Router Rule (HTTPS)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.rule=Host(`traefik.yourdomain.com`)"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE with your dashboard hostname !!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.entrypoints=websecure"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.service=api@internal"&lt;/span&gt;
      &lt;span class="c1"&gt;# Use Let's Encrypt for the dashboard domain&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.tls.certresolver=myresolver"&lt;/span&gt;
      &lt;span class="c1"&gt;# Secure the dashboard with Basic Auth&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.traefik-dashboard.middlewares=auth"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.middlewares.auth.basicauth.users=user:$&amp;lt;span&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;class="math-inline"&amp;gt;apr1&amp;lt;/span&amp;gt;&amp;lt;span class="math-inline"&amp;gt;abcdefg&amp;lt;/span&amp;gt;$yourhashedpassword"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE THIS HASH !!&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="c1"&gt;# Jellyfin Service&lt;/span&gt;
  &lt;span class="na"&gt;jellyfin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lscr.io/linuxserver/jellyfin:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jellyfin&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=1000&lt;/span&gt; &lt;span class="c1"&gt;# Your user ID&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=1000&lt;/span&gt; &lt;span class="c1"&gt;# Your group ID&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=Etc/UTC&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE with Your timezone e.g. Pacific/Auckland !!&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Map Jellyfin config directory&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/path/to/jellyfin/config:/config/&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE host path to your config location !!&lt;/span&gt;
      &lt;span class="c1"&gt;# Map Media Libraries&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/path/to/tvshows:/data/tvshows&lt;/span&gt;   &lt;span class="c1"&gt;# !! REPLACE host path to your TV shows !!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/path/to/movies:/data/movies&lt;/span&gt;     &lt;span class="c1"&gt;# !! REPLACE host path to your Movies !!&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;proxy&lt;/span&gt; &lt;span class="c1"&gt;# Connect to the same network as Traefik&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Enable Traefik management for this container&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
      &lt;span class="c1"&gt;# Jellyfin Router Rule (HTTPS)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.jellyfin.rule=Host(`jellyfin.yourdomain.com`)"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE with your Jellyfin hostname !!&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.jellyfin.entrypoints=websecure"&lt;/span&gt; &lt;span class="c1"&gt;# Use HTTPS entrypoint&lt;/span&gt;
      &lt;span class="c1"&gt;# Use Let's Encrypt resolver defined above&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.jellyfin.tls.certresolver=myresolver"&lt;/span&gt;
      &lt;span class="c1"&gt;# Tell Traefik which internal port Jellyfin uses&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.services.jellyfin.loadbalancer.server.port=8096"&lt;/span&gt;

&lt;span class="c1"&gt;# Define the shared network&lt;/span&gt;
&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;proxy&lt;/span&gt;

&lt;span class="c1"&gt;# Define the volume for Let's Encrypt certificates&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;letsencrypt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Handling Secrets - The &lt;code&gt;.env&lt;/code&gt; File
&lt;/h2&gt;

&lt;p&gt;Never commit secrets directly into your &lt;code&gt;docker-compose.yml&lt;/code&gt;! We'll use a &lt;code&gt;.env&lt;/code&gt; file to store the AWS credentials.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the same directory as your &lt;code&gt;docker-compose.yml&lt;/code&gt;, create a file named &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add your AWS keys:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .env
AWS_ACCESS_KEY_ID=YOUR_ACTUAL_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=YOUR_ACTUAL_SECRET_ACCESS_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Crucially: Add .env to your .gitignore file to prevent accidentally committing it.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .gitignore
.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Docker Compose will automatically read this file and inject these variables into the Traefik container's environment, as specified in the environment: section of the &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Securing the Traefik Dashboard
&lt;/h2&gt;

&lt;p&gt;We added basic authentication to the dashboard using Traefik labels. You need to generate a password hash.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install htpasswd (usually via apache2-utils or httpd-tools).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the following, replacing admin and 'YourSecurePassword!' with your desired credentials:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;htpasswd &lt;span class="nt"&gt;-nb&lt;/span&gt; admin &lt;span class="s1"&gt;'YourSecurePassword!'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the output (e.g., admin:$apr1$somehash$morehash).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste it into the &lt;code&gt;traefik.http.middlewares.auth.basicauth.users&lt;/code&gt; label in &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;br&gt;
Remember to escape the dollar signs &lt;code&gt;($)&lt;/code&gt; by doubling them &lt;code&gt;($$)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example label in docker-compose.yml&lt;/span&gt;
&lt;span class="s"&gt;_ "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$somehash$$morehash"&lt;/span&gt; &lt;span class="c1"&gt;# !! REPLACE user:hash !!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: DNS Configuration (Route 53)
&lt;/h2&gt;

&lt;p&gt;Before starting, ensure you have A records in Route 53 pointing your chosen hostnames (e.g., &lt;code&gt;jellyfin.yourdomain.com&lt;/code&gt; and &lt;code&gt;traefik.yourdomain.com&lt;/code&gt;) to the public IP address of the server running Docker.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jellyfin.yourdomain.com&lt;/code&gt; -&amp;gt; &lt;code&gt;YOUR_SERVER_PUBLIC_IP&lt;/code&gt;&lt;br&gt;
&lt;code&gt;traefik.yourdomain.com&lt;/code&gt; -&amp;gt; &lt;code&gt;YOUR_SERVER_PUBLIC_IP&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Final Checks &amp;amp; Deployment
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Placeholders&lt;/strong&gt;: Ensure you've replaced all placeholders marked with &lt;code&gt;!! REPLACE !!&lt;/code&gt; or &lt;code&gt;YOUR_...&lt;/code&gt; in the &lt;code&gt;docker-compose.yml&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; files with your actual values (hostnames, email, paths, user IDs, timezone, password hash, AWS keys).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paths&lt;/strong&gt;: Double-check the host paths mapped in the volumes section for Jellyfin – point them to your actual config and media library locations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User/Group ID&lt;/strong&gt;: Update &lt;code&gt;PUID&lt;/code&gt; and &lt;code&gt;PGID&lt;/code&gt; in the Jellyfin environment section to match the user/group that owns your media files (use id &lt;code&gt;$USER&lt;/code&gt; on &lt;code&gt;Linux&lt;/code&gt; to find yours).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Directory&lt;/strong&gt;: Create the Let's Encrypt volume directory: &lt;code&gt;mkdir ./letsencrypt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firewall/Router&lt;/strong&gt;: Ensure port &lt;code&gt;443&lt;/code&gt; is forwarded from your router/firewall to the internal IP address of your Docker host machine. Port &lt;code&gt;80&lt;/code&gt; forwarding is optional now but recommended for the &lt;code&gt;HTTP-&amp;gt;HTTPS&lt;/code&gt; redirect to work smoothly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Launch&lt;/strong&gt;: Run &lt;code&gt;docker compose up -d&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor&lt;/strong&gt;: Check the Traefik logs, especially on the first run, to ensure successful AWS authentication and certificate acquisition: &lt;code&gt;docker compose logs -f traefik-proxy&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You should now have a fully functional Jellyfin instance accessible securely via &lt;code&gt;https://jellyfin.yourdomain.com&lt;/code&gt; (using your actual domain), with automatic SSL certificate management handled by Traefik and Let's Encrypt, leveraging the power and reliability of AWS Route 53 for DNS validation. The Traefik dashboard is also available (and password-protected) at &lt;code&gt;https://traefik.yourdomain.com&lt;/code&gt; (again, using your actual domain).&lt;/p&gt;

&lt;p&gt;This setup gives me the control and freedom I was seeking after moving from Plex. By combining powerful open-source tools like Jellyfin and Traefik with robust cloud services like AWS Route 53 and IAM, we can build secure, flexible, and non-subscription-based solutions tailored perfectly to our needs.&lt;/p&gt;

&lt;p&gt;Happy self-hosting! Let me know about your experiences in the comments below.&lt;/p&gt;

</description>
      <category>route53</category>
      <category>dns</category>
      <category>traefik</category>
      <category>jellyfin</category>
    </item>
    <item>
      <title>CodeBuild Meets GitHub Actions: A Serverless CI Workflow with Lambda</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Thu, 27 Feb 2025 23:04:27 +0000</pubDate>
      <link>https://dev.to/aws-builders/streamline-your-development-workflow-with-codebuild-hosted-github-actions-runner-307k</link>
      <guid>https://dev.to/aws-builders/streamline-your-development-workflow-with-codebuild-hosted-github-actions-runner-307k</guid>
      <description>&lt;h3&gt;
  
  
  Serverless GitHub Actions? Yes! Learn how to use AWS Lambda/ CodeBuild for Github Actions workflow execution
&lt;/h3&gt;

&lt;p&gt;GitHub Actions provides a powerful CI/CD pipeline, but sometimes you need more control over the environment where your workflows run. AWS CodeBuild now supports Lambda-based self-hosted runners, allowing you to execute GitHub Actions workflows in a cost-efficient, on-demand AWS environment. This guide will walk you through setting up a self-hosted GitHub Actions runner using AWS CodeBuild's Lambda Runner environment.&lt;/p&gt;




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

&lt;p&gt;Before getting started, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account with permissions to create CodeBuild projects and Lambda functions&lt;/li&gt;
&lt;li&gt;A GitHub repository where you want to run the actions&lt;/li&gt;
&lt;li&gt;AWS CLI and GitHub CLI installed on your local machine&lt;/li&gt;
&lt;li&gt;An IAM role with necessary permissions for CodeBuild and Lambda execution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1: Create an AWS CodeBuild Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;AWS CodeBuild will serve as our self-hosted GitHub Actions runner. Follow these steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.1 Navigate to AWS CodeBuild&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open the &lt;a href="https://console.aws.amazon.com/codebuild/home" rel="noopener noreferrer"&gt;AWS CodeBuild Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create build project&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.2 Configure Project Settings&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project Name&lt;/strong&gt;: &lt;code&gt;github-actions-runner&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: &lt;code&gt;Self-hosted GitHub Actions runner using AWS CodeBuild Lambda Runner&lt;/code&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0ckb9b44frm0dgy3tcf.png" alt="Image description" width="613" height="680"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: Select &lt;strong&gt;GitHub&lt;/strong&gt; and connect to your repository
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foskjnrt5kiljvhqi4of6.png" alt="Image description" width="617" height="675"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.3 Select Environment&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Environment Image&lt;/strong&gt;: Choose &lt;strong&gt;Managed Image&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operating System&lt;/strong&gt;: Amazon Linux 2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime&lt;/strong&gt;: AWS Lambda&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute Type&lt;/strong&gt;: Lambda Execution Environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operating System System&lt;/strong&gt;: Amazon Linux&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime&lt;/strong&gt;: Python&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image &amp;amp; Version&lt;/strong&gt;: Select the latest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq9ada3mgore9d8jgmlk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkq9ada3mgore9d8jgmlk.png" alt="Image description" width="620" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1.4 Configure IAM Role&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;New Service Role&lt;/strong&gt; or select an existing role with permissions to execute CodeBuild, interact with GitHub, and access AWS Lambda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qioil2gr0mes5dlhq5m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qioil2gr0mes5dlhq5m.png" alt="Image description" width="608" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attach the following policies if needed:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:*:*:function:*"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"codebuild:StartBuild"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&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="p"&gt;]&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;Click &lt;strong&gt;Create Build Project&lt;/strong&gt; to finalize.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2: Setup the GitHub action workflow.&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to your GitHub repository&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;Actions&lt;/code&gt; tab and create a simple workflow.&lt;/li&gt;
&lt;li&gt;To point the lambda self-hosted runner in place, update your &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; to use it:
Please note the &lt;code&gt;runs-on:&lt;/code&gt; section here that you need to at to the workflow file.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="c1"&gt;# The type of runner that the job will run on&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;codebuild-gha-runner-lambda-test-${{ github.run_id }}-${{ github.run_attempt }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a full example of the workflow file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This is a basic workflow to help you get started with Actions&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI AWS Lambda Pipeline Test&lt;/span&gt;

&lt;span class="c1"&gt;# Controls when the workflow will run&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Triggers the workflow on push or pull request events but only for the "master" branch&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;master"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;master"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# Allows you to run this workflow manually from the Actions tab&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="c1"&gt;# A workflow run is made up of one or more jobs that can run sequentially or in parallel&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# This workflow contains a single job called "build"&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# The type of runner that the job will run on&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;codebuild-gha-runner-lambda-test-${{ github.run_id }}-${{ github.run_attempt }}&lt;/span&gt;

    &lt;span class="c1"&gt;# Steps represent a sequence of tasks that will be executed as part of the job&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="c1"&gt;# Runs a single command using the runners shell&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run a one-line script&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo Hello, world!&lt;/span&gt;

      &lt;span class="c1"&gt;# Runs a set of commands using the runners shell&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run a multi-line script&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;echo Add other actions to build,&lt;/span&gt;
          &lt;span class="s"&gt;echo test, and deploy your project.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push changes to your repository, and the self-hosted runner in AWS CodeBuild will pick up the job and the lambda function will run your job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy0m7t3jxqsz9ujeo6ir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy0m7t3jxqsz9ujeo6ir.png" alt="Image description" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhm7xq52wazdkdcolcam.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhm7xq52wazdkdcolcam.png" alt="Image description" width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyzi9btivh673hmbs1n3n.png" alt="Image description" width="800" height="355"&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2.1 Limitations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Lambda compute is designed for speed, optimizing startup times for builds. However, it does have some limitations and does not support the following use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reserved Capacity&lt;/li&gt;
&lt;li&gt;Caching Across Builds&lt;/li&gt;
&lt;li&gt;Restricting Runtime with Timeouts&lt;/li&gt;
&lt;li&gt;Tools Requiring Root-User Permissions&lt;/li&gt;
&lt;li&gt;Long-Running Builds (Lambda has a maximum timeout of 15 minutes)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Using AWS CodeBuild's Lambda Runner for GitHub Actions provides a scalable, cost-efficient alternative to traditional self-hosted runners. You only pay for execution time, and the Lambda-based environment ensures seamless scaling. Try this setup for your CI/CD workflows and enjoy the flexibility of AWS CodeBuild in your GitHub Actions pipelines!&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>lambda</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Speak the Command, Execute the Lambda</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Thu, 19 Dec 2024 22:06:52 +0000</pubDate>
      <link>https://dev.to/aws-builders/triggering-aws-lambda-functions-with-voice-commands-using-amazon-alexa-35d8</link>
      <guid>https://dev.to/aws-builders/triggering-aws-lambda-functions-with-voice-commands-using-amazon-alexa-35d8</guid>
      <description>&lt;p&gt;In today's world of voice assistants and smart devices, integrating your AWS Lambda functions with Amazon Alexa opens up a world of possibilities. Imagine being able to trigger a Lambda function with a simple voice command, automating tasks like checking the weather, controlling smart devices, or querying your AWS resources. In this blog post, we’ll walk you through the steps to create a voice-activated Lambda function using Amazon Alexa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Setting Up Your AWS Lambda Function
&lt;/h2&gt;

&lt;p&gt;Before you can trigger a Lambda function with your voice, you need to create and configure the function.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Create the Lambda Function
&lt;/h3&gt;

&lt;p&gt;Log in to the AWS Management Console and navigate to the Lambda service.&lt;/p&gt;

&lt;p&gt;Create a new function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose "Author from scratch."&lt;/li&gt;
&lt;li&gt;Enter a function name (e.g., &lt;code&gt;WeatherCheckerLambda&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Choose a runtime (e.g., Python 3.9 or Node.js 18.x).&lt;/li&gt;
&lt;li&gt;Set up an execution role with basic Lambda permissions. If your function needs to access other AWS services, ensure the role has the appropriate permissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write your function code: Here’s a simple Python example that returns a weather update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Sample response to be returned by Alexa
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;outputSpeech&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PlainText&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;The weather today is sunny with a high of 25 degrees.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;shouldEndSession&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&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;
  
  
  1.2 Configure the Lambda Function
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Set up environment variables and resource limits according to your needs.&lt;/li&gt;
&lt;li&gt;Test the function using the AWS Lambda console's built-in test feature. This ensures that your function executes as expected before integrating with Alexa.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Creating an Alexa Skill
&lt;/h2&gt;

&lt;p&gt;Now that your Lambda function is ready, you’ll create an Alexa skill to trigger it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Set Up the Alexa Skill
&lt;/h3&gt;

&lt;p&gt;Log in to the &lt;a href="https://developer.amazon.com/alexa/console/ask" rel="noopener noreferrer"&gt;Alexa Developer Console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a new skill:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose “Create Skill” and select the “Custom” skill type.&lt;/li&gt;
&lt;li&gt;Set your skill name (e.g., &lt;code&gt;Weather Checker&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;other&lt;/code&gt; for the &lt;code&gt;experience&lt;/code&gt; type.&lt;/li&gt;
&lt;li&gt;Choose a template: Start from scratch or use the provided templates for a custom experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhr0ifcy7y8c5bblv2emq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhr0ifcy7y8c5bblv2emq.png" alt="Image description" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hit &lt;code&gt;Create Skill&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.2 Designing the Interaction Model
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Invocation Name:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set an invocation name for your skill (e.g., &lt;code&gt;weather checker&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;This is what users will say to start the interaction (e.g., “Alexa, ask weather checker...”).&lt;/li&gt;
&lt;li&gt;Hit &lt;code&gt;Build Skill&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create Intents:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intents represent actions users want to perform. For example, create an intent called &lt;code&gt;GetWeatherIntent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Under the &lt;code&gt;GetWeatherIntent&lt;/code&gt;, add sample utterances like:

&lt;ul&gt;
&lt;li&gt;"What is the weather today?"&lt;/li&gt;
&lt;li&gt;"Tell me the weather."&lt;/li&gt;
&lt;li&gt;"Give me today's weather forecast."&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7xkd5zz1ygcvlk5bmwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7xkd5zz1ygcvlk5bmwp.png" alt="Image description" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slots:&lt;/strong&gt; If your skill needs more specific inputs, such as a city name, you can define slots. For this example, a simple weather checker might not need them.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Configuring the Endpoint
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Link the Skill to Your Lambda Function:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Alexa Developer Console, navigate to the Endpoint section.&lt;/li&gt;
&lt;li&gt;Select AWS Lambda ARN as the service endpoint type.&lt;/li&gt;
&lt;li&gt;Paste the ARN of the Lambda function you created earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo79wqg6p0jdeu3wwxhfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo79wqg6p0jdeu3wwxhfu.png" alt="Image description" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skill Permissions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure your Lambda function’s IAM role has the necessary permissions to execute and return data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Add Lambda Trigger&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5mc5vpq1y105sjag2v0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5mc5vpq1y105sjag2v0.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add “Alexa Skills kit” from the “Add triggers” sidebar in aws console. (Shown as in screenshot above)&lt;/p&gt;

&lt;p&gt;Next you have to click on the “Alexa Skills kit”, then this will show up&lt;/p&gt;

&lt;p&gt;Add your skill ID in the above field.&lt;/p&gt;

&lt;p&gt;Moreover, make sure you add this lambda function ARN in your skill’s endpoint. Just paste the ARN in your skill’s endpoint.&lt;/p&gt;

&lt;p&gt;Build and Save it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgou5vgqxd8gq9jnff9gm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgou5vgqxd8gq9jnff9gm.png" alt="Image description" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Coding the Lambda Function to Handle Alexa Requests
&lt;/h2&gt;

&lt;p&gt;Your Lambda function needs to be able to handle requests from Alexa and respond appropriately.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Handle Alexa Requests in Your Lambda Function
&lt;/h3&gt;

&lt;p&gt;Here’s an expanded version of the Lambda function that parses the input and returns a relevant response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Extracting intent name from Alexa's request
&lt;/span&gt;    &lt;span class="n"&gt;intent_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;request&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;intent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;intent_name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GetWeatherIntent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Build response
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;outputSpeech&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PlainText&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;The weather today is sunny with a high of 25 degrees.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;shouldEndSession&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
            &lt;span class="p"&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;outputSpeech&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PlainText&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;I am not sure how to help with that.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;shouldEndSession&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&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;
  
  
  3.2 Testing the Lambda Function
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use the AWS Lambda console to trigger the function manually with test events that simulate Alexa requests.&lt;/li&gt;
&lt;li&gt;Enable detailed logging in CloudWatch to troubleshoot any issues and ensure your function handles requests correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Testing and Deploying the Alexa Skill
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Testing with the Alexa Simulator
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Alexa Developer Console and open your skill.&lt;/li&gt;
&lt;li&gt;Use the Test tab: Here, you can simulate voice commands using the Alexa Simulator. Type or speak phrases like “Alexa, ask weather checker what the weather is today.”&lt;/li&gt;
&lt;li&gt;Review responses: Ensure Alexa returns the expected responses, and debug if necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.2 Testing with a Real Device
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Enable your skill on an Alexa-enabled device, such as an Amazon Echo.&lt;/li&gt;
&lt;li&gt;Speak the invocation name and command: For example, say “Alexa, ask weather checker what the weather is today.”&lt;/li&gt;
&lt;li&gt;Refine based on feedback: Adjust your Lambda function and skill interaction model based on real-world testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: Deploying and Monitoring Your Skill
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Deploying Your Skill
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Publish your skill: Once satisfied with the functionality, you can submit your skill for certification through the Alexa Developer Console.&lt;/li&gt;
&lt;li&gt;Private or Public: Choose whether to keep the skill private for personal use or make it available to the public.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2 Monitoring and Logging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use AWS CloudWatch: Monitor logs to track Lambda execution, identify errors, and optimize performance.&lt;/li&gt;
&lt;li&gt;Skill Analytics: In the Alexa Developer Console, you can also access analytics to see how users interact with your skill.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these steps, you’ve successfully created a voice-activated Lambda function using Amazon Alexa. This setup opens the door to endless possibilities, from automating daily tasks to creating rich, voice-controlled applications. Whether you’re developing a personal project or a commercial application, integrating AWS Lambda with Alexa is a powerful way to bring voice capabilities to your cloud services.&lt;/p&gt;

&lt;p&gt;Happy coding, and enjoy the convenience of voice-triggered automation!&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Mastering AWS Step Functions Error Handling</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Thu, 01 Aug 2024 23:18:01 +0000</pubDate>
      <link>https://dev.to/aws-builders/mastering-aws-step-functions-error-handling-j39</link>
      <guid>https://dev.to/aws-builders/mastering-aws-step-functions-error-handling-j39</guid>
      <description>&lt;p&gt;AWS Step Functions is a powerful orchestration service that enables developers to build and coordinate workflows using a series of steps, such as AWS Lambda functions, ECS tasks, or other AWS services. One of the critical aspects of building robust workflows is handling errors effectively. In this blog post, we'll dive into the different error handling scenarios in AWS Step Functions and provide practical examples to illustrate how to manage them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Error Handling is Important
&lt;/h3&gt;

&lt;p&gt;Error handling ensures your workflows can gracefully handle failures and continue processing without manual intervention. This not only improves the reliability of your applications but also enhances user experience by minimizing downtime and reducing the likelihood of data corruption.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of Errors in AWS Step Functions
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;States.All Errors&lt;/strong&gt;: Catch-all for any error not explicitly caught by other patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States.Timeout&lt;/strong&gt;: Triggered when a state exceeds its allowed execution time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States.TaskFailed&lt;/strong&gt;: Raised when a task state fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States.Permissions&lt;/strong&gt;: Occurs due to IAM permission issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States.ResultPathMatchFailure&lt;/strong&gt;: When the result path doesn't match.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States.BranchFailed&lt;/strong&gt;: Raised if a parallel state fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States.NoChoiceMatched&lt;/strong&gt;: No match found for a Choice state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;States.ParameterPathFailure&lt;/strong&gt;: When a parameter path evaluation fails.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Error Handling Strategies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retry&lt;/strong&gt;: Automatically retry a failed state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catch&lt;/strong&gt;: Capture errors and redirect execution to a recovery path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout&lt;/strong&gt;: Specify a maximum time a state should run.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Workflow
&lt;/h3&gt;

&lt;p&gt;Let's create a Step Functions workflow with a few states to illustrate error handling. Our example will include a Lambda function that might fail, and we'll handle errors using retry and catch mechanisms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State Machine Graph&lt;/strong&gt;&lt;br&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%2Fuploads%2Farticles%2Fc1pgs1a7xn5pvdvcdxva.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%2Fuploads%2Farticles%2Fc1pgs1a7xn5pvdvcdxva.png" alt="Step Function"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step Function Definition&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"Comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A simple state machine to demonstrate error handling"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invoke Lambda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Invoke Lambda"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:REGION:ACCOUNT_ID:function:YOUR_LAMBDA_FUNCTION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Retry"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.ALL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"IntervalSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"MaxAttempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"BackoffRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Catch"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.ALL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Error"&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"Handle Error"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LambdaFunctionFailed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Lambda function encountered an error."&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="p"&gt;}&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;h3&gt;
  
  
  Error Handling Scenarios
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Retrying Failed States
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;Retry&lt;/code&gt; field allows you to retry a failed state. In the example above, the state will retry up to 3 times with exponential backoff if an error occurs.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"Retry"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.ALL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"IntervalSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"MaxAttempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"BackoffRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&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="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  2. Catching Errors
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;Catch&lt;/code&gt; field enables you to capture errors and redirect the workflow to a different state, like an error handler or a fallback mechanism.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"Catch"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.ALL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Error"&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="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  3. Handling Timeouts
&lt;/h4&gt;

&lt;p&gt;You can specify timeouts for states to prevent them from running indefinitely.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:REGION:ACCOUNT_ID:function:YOUR_LAMBDA_FUNCTION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"TimeoutSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&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;h3&gt;
  
  
  Advanced Error Handling
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Conditional Error Handling with Choice State
&lt;/h4&gt;

&lt;p&gt;You can use the Choice state to direct the workflow based on different error types.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"Catch"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.Timeout"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TimeoutHandler"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.TaskFailed"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TaskFailedHandler"&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="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;&lt;strong&gt;Benefits of Conditional Error Handling&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Granular Control&lt;/strong&gt;: Allows you to define different handling strategies for different error types, improving the robustness of your workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Debugging&lt;/strong&gt;: By routing specific errors to distinct states, you can more easily identify and address issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customised Recovery&lt;/strong&gt;: Enables tailored recovery actions or notifications based on the nature of the error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;State Machine Graph&lt;/strong&gt;&lt;br&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%2Fuploads%2Farticles%2Fe7bin9sf8hi4pkfae6qe.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%2Fuploads%2Farticles%2Fe7bin9sf8hi4pkfae6qe.png" alt="Timeout erros"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step Function Definition&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"Comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A simple state machine to demonstrate error handling including timeout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invoke Lambda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Invoke Lambda"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:REGION:ACCOUNT_ID:function:YOUR_LAMBDA_FUNCTION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"TimeoutSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&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;Timeout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;after&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;seconds&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Retry"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.ALL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"IntervalSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"MaxAttempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"BackoffRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Catch"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.Timeout"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Timeout"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"States.ALL"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Error"&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"Handle Timeout"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LambdaTimeoutError"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Lambda function timed out."&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;"Handle Error"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LambdaFunctionFailed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Lambda function encountered an error."&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="p"&gt;}&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;h4&gt;
  
  
  2. Parallel State Error Handling
&lt;/h4&gt;

&lt;p&gt;For workflows with parallel states, each branch can have its own error handling strategy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Parallel Tasks State:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Parallel state starts two branches: "Invoke Lambda A" and "Invoke Lambda B".&lt;/li&gt;
&lt;li&gt;Each branch handles retries, timeouts, and failures independently.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Error Handling in Each Branch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retry: Retries the task up to 3 times with exponential backoff if it fails.&lt;/li&gt;
&lt;li&gt;Timeout: If a task times out, it transitions to a specific error handler.&lt;/li&gt;
&lt;li&gt;Catch: Captures any other errors and transitions to an error handler.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Error Handling for Parallel State:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Catch block in the Parallel state catches errors from any branch and transitions to the "Handle Parallel Failure" state if any branch fails.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;State Machine Graph&lt;/strong&gt;&lt;br&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%2Fuploads%2Farticles%2Fnb86xs07ld8mk6ubs4ku.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%2Fuploads%2Farticles%2Fnb86xs07ld8mk6ubs4ku.png" alt="Parallel State Error Handling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step Function Definition&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"Comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A state machine with parallel tasks and error handling"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Parallel Tasks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Parallel Tasks"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Parallel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Branches"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invoke Lambda A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Invoke Lambda A"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:REGION:ACCOUNT_ID:function:LambdaFunctionA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"TimeoutSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Retry"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"States.ALL"&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;"IntervalSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"MaxAttempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"BackoffRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Catch"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"States.Timeout"&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;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Timeout A"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"States.ALL"&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;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Error A"&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"Handle Timeout A"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LambdaTimeoutErrorA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lambda Function A timed out."&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;"Handle Error A"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LambdaFunctionFailedA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lambda Function A failed."&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="p"&gt;}&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invoke Lambda B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Invoke Lambda B"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:REGION:ACCOUNT_ID:function:LambdaFunctionB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"TimeoutSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Retry"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"States.ALL"&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;"IntervalSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"MaxAttempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"BackoffRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Catch"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"States.Timeout"&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;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Timeout B"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"States.ALL"&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;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Error B"&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"Handle Timeout B"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LambdaTimeoutErrorB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lambda Function B timed out."&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;"Handle Error B"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LambdaFunctionFailedB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lambda Function B failed."&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="p"&gt;}&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Catch"&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ErrorEquals"&lt;/span&gt;&lt;span class="p"&gt;:&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="s2"&gt;"States.ALL"&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;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Handle Parallel Failure"&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"Handle Parallel Failure"&lt;/span&gt;&lt;span class="p"&gt;:&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;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ParallelStateFailed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Cause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"One or more parallel tasks failed."&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="p"&gt;}&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;Effective error handling in AWS Step Functions is crucial for building resilient workflows. By leveraging retry, catch, and timeout strategies, you can ensure your workflows handle failures gracefully and continue processing without manual intervention. With these techniques, you can build robust and reliable applications that can withstand various failure scenarios.&lt;/p&gt;

&lt;p&gt;Do you have any questions or additional error handling scenarios you'd like to explore? Let me know in the comments below! Happy coding in AWS!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>stepfunctions</category>
      <category>lambda</category>
      <category>aws</category>
    </item>
    <item>
      <title>De-Bugging with Amazon Q and Generative AI</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Fri, 19 Jul 2024 01:08:02 +0000</pubDate>
      <link>https://dev.to/aws-builders/de-bugging-with-amazon-q-and-generative-ai-2i9a</link>
      <guid>https://dev.to/aws-builders/de-bugging-with-amazon-q-and-generative-ai-2i9a</guid>
      <description>&lt;p&gt;Serverless functions are the superheroes of the cloud, scaling effortlessly and saving you precious server management time. But even superheroes need a good debugging sidekick, and that’s where Amazon Q steps in. This innovative service from AWS harnesses the power of generative AI to take your serverless debugging to a whole new level.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes Amazon Q So Special?
&lt;/h2&gt;

&lt;p&gt;Traditional debugging can be a challenging and time-consuming process, especially in complex codebases. Amazon Q stands out by using generative AI to assist with your code debugging. Instead of manually hunting for bugs, Q analyzes your code to identify patterns and potential issues proactively. Imagine having a smart assistant that understands your code’s nuances, offering insights and suggestions as you write, helping you catch and fix problems before they escalate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here’s How Amazon Q Can Supercharge Your Debugging:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identify Anomalies in Code&lt;/strong&gt;: Amazon Q can scan your Python code and highlight unusual patterns or potential bugs. For instance, if a specific function call tends to cause unexpected behaviour, Q can flag it for your attention, saving you valuable time in pinpointing the root cause.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predict Code Issues&lt;/strong&gt;: Leveraging generative AI, Amazon Q can learn from past code errors and identify patterns that might lead to future problems. Q can analyse your codebase and warn you of potential issues before they occur, preventing bugs and keeping your applications running smoothly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate Debugging Insights&lt;/strong&gt;: Struggling to decipher a cryptic error in your code? Q can analyse the context of the error within your codebase and generate potential explanations and solutions to help you resolve the issue faster. It can suggest fixes and improvements, making your debugging process more efficient and effective.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-world Example: Debugging a Lambda Function with a DeadLock issue and get Amazon Q to fix it.
&lt;/h2&gt;

&lt;p&gt;Let’s say you have a Lambda function that has potential issue’s with deadlocks and space for improvements, Here’s how Amazon Q can help:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problematic Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with a simple Python script that uses threading and locks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="c1"&gt;# Shared resources
&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Thread function
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;thread_routine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: attempting to acquire lock&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: acquired lock&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Simulate some processing
&lt;/span&gt;        &lt;span class="c1"&gt;# Do something with the resources
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Create threads
&lt;/span&gt;    &lt;span class="n"&gt;thread1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;thread_routine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="n"&gt;thread2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;thread_routine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread 2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;

    &lt;span class="c1"&gt;# Start threads
&lt;/span&gt;    &lt;span class="n"&gt;thread1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;thread2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Join threads to wait for their completion
&lt;/span&gt;    &lt;span class="n"&gt;thread1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;thread2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello from Lambda!&lt;/span&gt;&lt;span class="sh"&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;# Test the lambda_handler function locally
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;lambda_handler&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;
  
  
  Identifying Issues with Amazon Q
&lt;/h2&gt;

&lt;p&gt;To identify issues with the above code, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install Amazon Q in Visual Studio Code&lt;/strong&gt;: Ensure you have the &lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/q-in-IDE-setup.html" rel="noopener noreferrer"&gt;Amazon Q extension&lt;/a&gt; installed. This can be done from the Visual Studio Code Marketplace.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analyze the Code&lt;/strong&gt;: Open your Python script in Visual Studio Code. Amazon Q will automatically analyse the code and highlight potential issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4qyr61d0lyykvcd9kx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4qyr61d0lyykvcd9kx1.png" alt="Analyze the Code" width="720" height="1236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Review the Suggestions&lt;/strong&gt;: Amazon Q provides detailed suggestions and explanations. In our script, Amazon Q identifies a potential deadlock situation caused by the order in which locks are acquired in the two threads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlt0f641rcohk0hc14m9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlt0f641rcohk0hc14m9.png" alt="Review the Suggestions" width="720" height="308"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;

&lt;span class="c1"&gt;# Shared resources
&lt;/span&gt;&lt;span class="n"&gt;lock1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;lock2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Thread function that acquires locks in a consistent order
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;thread_routine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: attempting to acquire lock1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: acquired lock1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: attempting to acquire lock2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;lock2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Thread &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: acquired lock2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# Do something with the resources
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Create threads
&lt;/span&gt;    &lt;span class="n"&gt;thread1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;thread_routine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="n"&gt;thread2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;thread_routine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&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="c1"&gt;# Start threads
&lt;/span&gt;    &lt;span class="n"&gt;thread1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;thread2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Join threads to wait for their completion
&lt;/span&gt;    &lt;span class="n"&gt;thread1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;thread2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello from Lambda!&lt;/span&gt;&lt;span class="sh"&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;# Test the lambda_handler function locally
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;lambda_handler&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;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtn5fppswkfcp1ic4nd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtn5fppswkfcp1ic4nd4.png" alt="Review the Suggestions" width="720" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the refactored code, Amazon Q suggested to use a single lock to ensure that only one thread can access the shared resource at a time, preventing deadlock.&lt;/p&gt;

&lt;p&gt;Feel free to reach out if you have any questions or need further assistance with Amazon Q or any other development tools. Let’s make coding smoother and more efficient together!&lt;/p&gt;

&lt;p&gt;This is just one example of how Amazon Q can streamline your serverless debugging process. By leveraging the power of generative AI, you can spend less time wrestling with errors and more time building amazing serverless applications.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>amazonq</category>
      <category>genai</category>
    </item>
    <item>
      <title>Coding with a Cyborg: The Rise of the Amazon Q</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Fri, 10 May 2024 07:46:25 +0000</pubDate>
      <link>https://dev.to/aws-builders/coding-with-a-cyborg-the-rise-of-the-amazon-q-11a2</link>
      <guid>https://dev.to/aws-builders/coding-with-a-cyborg-the-rise-of-the-amazon-q-11a2</guid>
      <description>&lt;h3&gt;
  
  
  Introducing the Amazon Q VS Code Extension: Your AI Copilot
&lt;/h3&gt;

&lt;p&gt;Imagine having an AI assistant whispering coding insights in your ear as you write. That’s the magic of Amazon Q! It has a VS Code extension seamlessly integrates with your development environment, offering real-time code completion, error detection, and even the ability to generate code snippets based on your natural language descriptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building A Lambda function with Amazon Q’s Help
&lt;/h3&gt;

&lt;p&gt;Let’s use Amazon Q to streamline building our Lambda function. Here’s a glimpse of the workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fire Up VS Code and Install the Amazon Q Extension: This is a breeze — just search for “Amazon Q” in the &lt;a href="https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.amazon-q-vscode"&gt;VS Code extension&lt;/a&gt; marketplace and hit install.&lt;/li&gt;
&lt;li&gt;Project structure - Let's say we are going create a lambda function and deploy it via terraform. we can use the following basic project structure.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── main.tf
└── send-email-lambda
    └── send-email.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Craft Your Natural Language Request: Describe what you want the function to do, I’m going to ask:
&lt;code&gt;Write a lambda function that can be used to send notifications when certain events occur. For example, a function could be triggered to send an email when a new order is placed on an e-commerce website&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Witness the Power of AI: Amazon Q analyses your request and generates the basic Lambda function code, including boilerplate and event handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4s1bznx5j05s6z6aqdb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4s1bznx5j05s6z6aqdb.png" alt="Write Lambda code" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy the lambda code and put that in the send-email.py file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Adding SMS Functionality with Amazon Q’s Guidance
&lt;/h3&gt;

&lt;p&gt;Now, let’s extend the Lambda to send SMS notifications as well. Here’s where Amazon Q shines again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New Feature: Add a comment # Send SMS after the send email section of your code and press enter. Amazon Q will start suggesting you code blocks as you go in to new lines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqm6b6xi0rarqicfafmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqm6b6xi0rarqicfafmg.png" alt="Add SMS feature" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI to the Rescue: Amazon Q taps into its knowledge base and suggests relevant code snippets or documentation links to achieve your goal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Terraform Takes the Wheel for Deployment
&lt;/h3&gt;

&lt;p&gt;With the Lambda function primed, it’s time to deploy it using Terraform’s infrastructure as code (IaC). Terraform lets you define your infrastructure in code, ensuring consistent and automated deployments. You can use Amazon Q within VS Code to help you write the Terraform code for creating the Lambda function, IAM roles, and SNS topics needed for email and SMS notifications.&lt;/p&gt;

&lt;p&gt;Craft Your Natural Language Request: Describe what you want the function to do, and this time I’m going to ask:&lt;br&gt;
&lt;code&gt;Write a terraform code that creates a zip file of this “send-email-lambda/send-email.py” python code and deploy it to my aws account&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhr7l84cgfkyn1b0nf23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhr7l84cgfkyn1b0nf23.png" alt="Terraform code" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Final Frontier: Deployment and Beyond!
&lt;/h3&gt;

&lt;p&gt;Once the Terraform code is ready, simply run &lt;code&gt;terraform apply&lt;/code&gt; to deploy your serverless notification machine to the cloud. This is just a taste of the possibilities! With Amazon Q as your AI partner, you can craft complex applications with unprecedented ease.&lt;/p&gt;

&lt;p&gt;Remember, this is just the beginning; explore &lt;a href="https://aws.amazon.com/q/"&gt;Amazon Q&lt;/a&gt;’s capabilities and see how it can transform your coding experience!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy Coding with Amazon Q&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>amazonq</category>
      <category>genai</category>
    </item>
    <item>
      <title>Boost Your Lambdas with Powertools</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Fri, 26 Apr 2024 04:15:51 +0000</pubDate>
      <link>https://dev.to/aws-builders/turbocharge-your-lambda-functions-with-aws-lambda-powertools-for-python-fph</link>
      <guid>https://dev.to/aws-builders/turbocharge-your-lambda-functions-with-aws-lambda-powertools-for-python-fph</guid>
      <description>&lt;p&gt;AWS Lambda Powertools for Python is a comprehensive suite of utilities designed to enhance the development of serverless applications using AWS Lambda. It simplifies logging, tracing, metric gathering, and more, allowing developers to focus more on business logic rather than boilerplate code. In this blog post, we’ll explore the key features of AWS Lambda Powertools for Python and provide an example of deploying a Lambda function using Terraform with the Powertools layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features of AWS Lambda Powertools for Python
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Logger
&lt;/h3&gt;

&lt;p&gt;The Logger utility simplifies logging setup across Lambda functions, providing structured logging as JSON out of the box. It automatically captures key information like cold start and function ARN, and supports logging correlation IDs for distributed tracing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@logger.inject_lambda_context&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processing event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Tracer
&lt;/h3&gt;

&lt;p&gt;Tracer is built on top of AWS X-Ray and provides decorators to trace Lambda function handlers and methods effortlessly. It captures cold starts, annotates errors correctly, and traces downstream calls to other AWS services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Tracer&lt;/span&gt;

&lt;span class="n"&gt;tracer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@tracer.capture_lambda_handler&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Your business logic here
&lt;/span&gt;    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Metrics
&lt;/h3&gt;

&lt;p&gt;The Metrics utility provides a straightforward way to capture custom business metrics using Amazon CloudWatch. It batches and flushes the metrics at the end of the function execution to minimize the number of calls made to CloudWatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Metrics&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MetricUnit&lt;/span&gt;

&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Metrics&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@metrics.log_metrics&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SuccessfulBookings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MetricUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Utilities
&lt;/h3&gt;

&lt;p&gt;AWS Lambda Powertools also includes several other utilities like Parameters for retrieving and caching parameter values from AWS Systems Manager or AWS Secrets Manager, Idempotency to ensure Lambda functions are idempotent, and Feature Flags to manage feature toggling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying a Lambda Function with Terraform and Powertools Layer
&lt;/h2&gt;

&lt;p&gt;To deploy an AWS Lambda function with the Powertools layer using Terraform, you first need to define your infrastructure as code. Below is a basic example of how you can set up a Lambda function with the AWS Lambda Powertools layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"my_lambda"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"MyLambdaFunction"&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda_function.lambda_handler"&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.8"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_exec_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;

  &lt;span class="nx"&gt;filename&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"path_to_your_lambda_deployment_package.zip"&lt;/span&gt;

  &lt;span class="nx"&gt;layers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPython:2"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"lambda_exec_role"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda_execution_role"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&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="nx"&gt;Action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;
        &lt;span class="nx"&gt;Principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda.amazonaws.com"&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="s2"&gt;"Allow"&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"lambda_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;my_lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Terraform script sets up a basic Lambda function with the AWS Lambda Powertools layer. It defines the necessary IAM role for the Lambda function to execute and outputs the ARN of the Lambda function after deployment.&lt;/p&gt;

&lt;p&gt;AWS Lambda Powertools for Python is a powerful toolkit that can significantly simplify the development and maintenance of serverless applications on AWS. By using its features, developers can ensure that their applications are robust, scalable, and easy to manage. You can read more about AWS Lambda Powertools in the following link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read more:&lt;/strong&gt; &lt;a href="https://docs.powertools.aws.dev/lambda/python/latest/"&gt;https://docs.powertools.aws.dev/lambda/python/latest/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy Coding!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>python</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Lambda Layers: The Secret Weapon of Savvy Serverless Developers</title>
      <dc:creator>Kasun de Silva</dc:creator>
      <pubDate>Fri, 15 Mar 2024 00:04:28 +0000</pubDate>
      <link>https://dev.to/aws-builders/lambda-layers-the-secret-weapon-of-savvy-serverless-developers-5fcd</link>
      <guid>https://dev.to/aws-builders/lambda-layers-the-secret-weapon-of-savvy-serverless-developers-5fcd</guid>
      <description>&lt;p&gt;When it comes to serverless development with AWS Lambda, keeping your code clean and efficient is essential. Lambda functions themselves have size limitations, and including all your dependencies within the function code can quickly bloat them. This is where Lambda layers come in — a powerful tool for streamlining your development process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are Lambda Layers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine a Lambda layer as a self-contained zip archive. This archive can hold various things, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Library dependencies:&lt;/strong&gt; Instead of bundling libraries with your function code, store them in a layer. This keeps your deployment packages leaner and easier to manage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom runtimes:&lt;/strong&gt; Need a specific runtime environment for your function? Layers can provide that too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration files:&lt;/strong&gt; Separate your function’s core logic from configuration details by storing them in a layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits of Using Lambda Layers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smaller Deployment Packages:&lt;/strong&gt; By offloading dependencies to layers, you keep your function code concise and reduce deployment times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziq65t2pjgyweir4nqc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziq65t2pjgyweir4nqc3.png" alt="Smaller Deployment Packages" width="420" height="276"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Improved Code Maintainability:&lt;/strong&gt; Separating function code from dependencies makes it easier to update and manage each independently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcx8so0bgw4ak9q5bgpgp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcx8so0bgw4ak9q5bgpgp.png" alt="Improved Code Maintainability" width="187" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reusability:&lt;/strong&gt; Layers can be attached to multiple functions, promoting code reuse and consistency across your serverless application.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2uag9omfxnqjc965uh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2uag9omfxnqjc965uh5.png" alt="Reusability" width="357" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standardized Runtimes:&lt;/strong&gt; Manage custom runtimes through layers, continuing a consistent environment for your functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Simple Layer Example&lt;/strong&gt;&lt;br&gt;
Let’s say you have a Lambda function that needs to make API requests. You can create a layer containing the requests library. Here's a basic example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a directory:&lt;/strong&gt; Create a folder named &lt;code&gt;python&lt;/code&gt; for your layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install the library:&lt;/strong&gt; Inside the python directory, run &lt;code&gt;pip install requests -t&lt;/code&gt; . This installs the &lt;code&gt;requests&lt;/code&gt; library into the current directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zip the directory:&lt;/strong&gt; Use the &lt;code&gt;zip&lt;/code&gt; command (or your OS's equivalent) to create a zip archive of the python directory. Name it something descriptive, like &lt;code&gt;my_requests_layer.zip&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you have a layer containing the &lt;code&gt;requests&lt;/code&gt; library! You can upload this zip file to AWS Lambda and reference it in your function code.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Using the Layer in Your Lambda Function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you have uploaded your layer to AWS Lambda, follow these steps to use it in your Lambda function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to Lambda functions in the AWS console.&lt;/li&gt;
&lt;li&gt;Click on the “Layers” section from the left menu.&lt;/li&gt;
&lt;li&gt;Click “Create layer”, upload your zip file and hit “Create”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffomyh79iwo7eblpuajg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffomyh79iwo7eblpuajg7.png" alt="Create layer" width="800" height="878"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s Create a Lambda functions that using the &lt;code&gt;requests&lt;/code&gt; library from a layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

  &lt;span class="c1"&gt;# Using the requests library from the layer
&lt;/span&gt;  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;ul&gt;
&lt;li&gt;Create a new Lambda function using above code example.&lt;/li&gt;
&lt;li&gt;In the “code” tab scroll all the way to bottom and find the Layers section.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkhkyco08bpc56m55b9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkhkyco08bpc56m55b9g.png" alt="Add Layer" width="800" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on “Add Layer”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm9ccy2oonkpkwzfj74p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm9ccy2oonkpkwzfj74p.png" alt="Custom layers" width="800" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select “Custom layers” and chose the “python_requests” layer you just uploaded.&lt;/li&gt;
&lt;li&gt;Click “Add”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then the custom layer you just created will be attached to your function.&lt;/p&gt;

&lt;p&gt;In this example, the function imports requests without needing it installed within the function code itself. This keeps the deployment package lean and leverages the reusable layer.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Getting Started with AWS Lambda Layers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using Lambda layers is straightforward. You create a zip archive containing your desired dependencies or configurations, upload it to AWS, and then reference it in your Lambda function code. Layers are versioned, so you can control exactly which version of the layer your function uses.&lt;/p&gt;

&lt;p&gt;Here are some additional resources to get you started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda Layers Documentation:&lt;/strong&gt;
&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html"&gt;https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using Lambda layers to simplify your development process:&lt;/strong&gt;
&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html"&gt;https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lambda layers are a valuable asset for any serverless developer on AWS. By leveraging layers, you can create cleaner, more manageable codebases, improve deployment efficiency, and promote code reuse across your serverless applications. So next time you’re building serverless functions with AWS Lambda, consider using layers to simplify your workflow and streamline your development process.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
