<?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: Ntombizakhona Mabaso</title>
    <description>The latest articles on DEV Community by Ntombizakhona Mabaso (@ntombizakhona).</description>
    <link>https://dev.to/ntombizakhona</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%2F899317%2Ffabcc82d-22a3-410a-b5b9-869687d73e09.jpg</url>
      <title>DEV Community: Ntombizakhona Mabaso</title>
      <link>https://dev.to/ntombizakhona</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ntombizakhona"/>
    <language>en</language>
    <item>
      <title>Use Data Stores In Application Development | 🏗️ Build A Product Catalog API</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Tue, 12 May 2026 20:45:57 +0000</pubDate>
      <link>https://dev.to/aws-builders/use-data-stores-in-application-development-build-a-product-catalog-api-404f</link>
      <guid>https://dev.to/aws-builders/use-data-stores-in-application-development-build-a-product-catalog-api-404f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Exam Guide:&lt;/strong&gt; Developer - Associate&lt;br&gt;
&lt;strong&gt;🏗️ Domain 1:&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;Development with AWS Services&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
📘 &lt;strong&gt;Task 3:&lt;/strong&gt; &lt;em&gt;Use Data Stores In Application Development&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DynamoDB dominates this task. The need to understand table design, key selection, indexing, consistency models, and how to write efficient queries is essential. As well as caching with ElastiCache and DAX. Plus specialized stores like OpenSearch.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  📘 Concepts
&lt;/h2&gt;
&lt;h3&gt;
  
  
  DynamoDB Key Concepts
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Primary Keys&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Every table needs one. Two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simple primary key:&lt;/strong&gt; Partition key only (PK). Each item has a unique PK.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composite primary key:&lt;/strong&gt; Partition key (PK) + Sort key (SK). Multiple items can share a PK if they have different SKs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Partition Key Selection&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The partition key determines which physical partition stores your data. A good partition key has &lt;strong&gt;high cardinality&lt;/strong&gt; which refers to many distinct values so that the data spreads evenly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Good Partition Keys&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Bad Partition Keys&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;userId, orderId, sessionId&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;status&lt;/em&gt; ("active"/"inactive")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;deviceId, transactionId&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;country&lt;/em&gt; (few values, uneven distribution)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;email, accountId&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;date&lt;/em&gt; (hot partition for today)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Consistency Models
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Behaviour&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Available On&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Eventually Consistent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;May return stale data&lt;/em&gt; (usually consistent within 1 second)&lt;/td&gt;
&lt;td&gt;1x read capacity&lt;/td&gt;
&lt;td&gt;Base table + GSIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strongly Consistent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Always returns the most up-to-date data&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;2x read capacity&lt;/td&gt;
&lt;td&gt;Base table only (NOT GSIs)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Query vs Scan
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Operation&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;How It Works&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;When to Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Query&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Finds items by partition key + optional sort key condition&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Reads only matching items&lt;/td&gt;
&lt;td&gt;Always prefer this&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Reads every item in the table&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Reads entire table&lt;/td&gt;
&lt;td&gt;Analytics, one-time migrations only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GetItem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Fetches one item by its full primary key&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Reads exactly one item&lt;/td&gt;
&lt;td&gt;When you know the exact key&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;FilterExpression&lt;/code&gt; does NOT reduce the amount of data read. It only filters what's returned to you. You still pay for the full scan/query. To reduce reads, use better key design or GSIs&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Global Secondary Index (GSI) vs Local Secondary Index (LSI)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;GSI&lt;/th&gt;
&lt;th&gt;LSI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Partition Key&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Different from base table&lt;/td&gt;
&lt;td&gt;Same as base table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sort Key&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Different from base table&lt;/td&gt;
&lt;td&gt;Different from base table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;When To Create&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Anytime&lt;/td&gt;
&lt;td&gt;At table creation only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Has its own (separate from base table)&lt;/td&gt;
&lt;td&gt;Shares with base table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Eventually consistent only&lt;/td&gt;
&lt;td&gt;Supports strongly consistent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Limit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20 per table&lt;/td&gt;
&lt;td&gt;5 per table&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;GSI Projection Types:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ALL:&lt;/strong&gt; &lt;em&gt;all attributes&lt;/em&gt; (most flexible, most storage cost)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KEYS_ONLY:&lt;/strong&gt; &lt;em&gt;only key attributes&lt;/em&gt; (cheapest)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INCLUDE:&lt;/strong&gt; &lt;em&gt;keys + specified attributes&lt;/em&gt; (balanced)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Caching Options
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Use Case&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;th&gt;Works With&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DAX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;DynamoDB read cache&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Microseconds&lt;/td&gt;
&lt;td&gt;DynamoDB only, eventually consistent only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ElastiCache Redis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;General-purpose cache&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Sub-millisecond&lt;/td&gt;
&lt;td&gt;Any data source, complex data types, persistence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ElastiCache Memcached&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Simple caching&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Sub-millisecond&lt;/td&gt;
&lt;td&gt;Any data source, multi-threaded, no persistence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Specialized Data Stores
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Store&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Use Case&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DynamoDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Key-value lookups, known access patterns, serverless&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RDS/Aurora&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Relational data, complex joins, ACID transactions&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenSearch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Full-text search, log analytics, complex queries&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Object storage, data lake, large files&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ElastiCache&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Session storage, leaderboards, real-time analytics&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Data Lifecycle
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;DynamoDB TTL&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Automatically deletes expired items at no cost. Eventually consistent (up to 48 hours delay). &lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;S3 Lifecycle Policies&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Transition objects between storage classes (Standard → IA → Glacier) or expire them after a set time.&lt;/p&gt;


&lt;h2&gt;
  
  
  🏗️ Build A Product Catalog API
&lt;/h2&gt;

&lt;p&gt;Now let's put these concepts into practice by builidng a &lt;strong&gt;Product Catalog API&lt;/strong&gt; backed by DynamoDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A DynamoDB table with a composite primary key and a Global Secondary Index (GSI)&lt;/li&gt;
&lt;li&gt;A Lambda function that performs queries, scans, and writes&lt;/li&gt;
&lt;li&gt;TTL configured for automatic data expiration&lt;/li&gt;
&lt;li&gt;DAX caching in front of DynamoDB&lt;/li&gt;
&lt;li&gt;A clear understanding of when to use query vs scan, GSI vs LSI, and strong vs eventual consistency&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://ntombizakhona.medium.com/amazon-web-services-a8e57a9c6084" rel="noopener noreferrer"&gt;An AWS account&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;(free tier covers DynamoDB and Lambda)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Part I
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Design the DynamoDB Table
&lt;/h3&gt;

&lt;p&gt;Before creating anything, let's think about access patterns. This is the most important step in DynamoDB design.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Our Access Patterns&lt;/strong&gt;
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Access Pattern&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;How We'll Query&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Get a product by ID&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Query PK = &lt;code&gt;PRODUCT#123&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;List all products in a category&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Query PK = &lt;code&gt;CATEGORY#electronics&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Get a product's reviews&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Query PK = &lt;code&gt;PRODUCT#123&lt;/code&gt;, SK begins_with &lt;code&gt;REVIEW#&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Find products by price range in a category&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Query GSI with category + price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;List recently added products&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Query GSI with status + createdAt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Create the Table&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;DynamoDB&lt;/strong&gt; console&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;Create table&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Table name:&lt;/strong&gt; &lt;code&gt;ProductCatalog&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partition key:&lt;/strong&gt; &lt;code&gt;PK&lt;/code&gt; (String)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort key — &lt;em&gt;optional&lt;/em&gt;:&lt;/strong&gt; &lt;code&gt;SK&lt;/code&gt; (String)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Under &lt;strong&gt;Table settings&lt;/strong&gt;, choose &lt;strong&gt;Customize settings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; &lt;strong&gt;Read/write capacity settings:&lt;/strong&gt; &lt;code&gt;On-demand&lt;/code&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Don't create the just table yet, let's add a GSI first&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Add a Global Secondary Index&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Scroll down to &lt;strong&gt;Secondary indexes&lt;/strong&gt; → click &lt;strong&gt;Create global index&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Index name:&lt;/strong&gt; &lt;code&gt;GSI1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partition key:&lt;/strong&gt; &lt;code&gt;GSI1PK&lt;/code&gt; (String)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort key:&lt;/strong&gt; &lt;code&gt;GSI1SK&lt;/code&gt; (String)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribute projections:&lt;/strong&gt; &lt;code&gt;All&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Create index&lt;/strong&gt;, then click &lt;strong&gt;Create table&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; The ProductCatalog table was created successfully.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Why This Design?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We're using the &lt;strong&gt;single-table design&lt;/strong&gt; pattern with &lt;strong&gt;overloaded keys&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Base table:
  PK = "PRODUCT#laptop-001"    SK = "METADATA"           → product details
  PK = "PRODUCT#laptop-001"    SK = "REVIEW#2026-04-24"  → a review
  PK = "CATEGORY#electronics"  SK = "PRODUCT#laptop-001" → category listing

GSI1:
  GSI1PK = "CATEGORY#electronics"  GSI1SK = "PRICE#00079.99" → find by price
  GSI1PK = "STATUS#active"         GSI1SK = "2026-04-24"     → find by date
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Partition Key Selection: A good partition key has &lt;em&gt;high cardinality&lt;/em&gt; (many distinct values). Bad examples: &lt;code&gt;status&lt;/code&gt; (only a few values → hot partition), &lt;code&gt;country&lt;/code&gt; (uneven distribution). Good examples: &lt;code&gt;userId&lt;/code&gt;, &lt;code&gt;productId&lt;/code&gt;, &lt;code&gt;orderId&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part II
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add Sample Data
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Using the Console&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt;  In the &lt;strong&gt;DynamoDB console&lt;/strong&gt;, click on &lt;code&gt;ProductCatalog&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;Explore table items&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Click &lt;strong&gt;Create item&lt;/strong&gt;&lt;br&gt;
Switch to &lt;strong&gt;JSON view&lt;/strong&gt; (toggle at the top)&lt;br&gt;
Paste this item:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRODUCT#laptop-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"METADATA"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"GSI1PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CATEGORY#electronics"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"GSI1SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRICE#00999.99"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pro Laptop 15"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"15-inch laptop with 16GB RAM"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"999.99"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"electronics"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-20T10:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stock"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"50"&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;Step 04:&lt;/strong&gt; Click &lt;strong&gt;Create item&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a few more products:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRODUCT#mouse-002"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"METADATA"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"GSI1PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CATEGORY#electronics"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"GSI1SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRICE#00029.99"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wireless Mouse"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ergonomic wireless mouse"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"29.99"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"electronics"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-22T10:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stock"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"200"&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;div class="highlight js-code-highlight"&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;"PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRODUCT#laptop-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REVIEW#2026-04-24#user-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"comment"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Great laptop, fast and reliable"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userId"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-24T14:30:00Z"&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;div class="highlight js-code-highlight"&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;"PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CATEGORY#electronics"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRODUCT#laptop-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pro Laptop 15"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"999.99"&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;div class="highlight js-code-highlight"&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;"PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CATEGORY#electronics"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRODUCT#mouse-002"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wireless Mouse"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"price"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"29.99"&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;h2&gt;
  
  
  Part III
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Query vs Scan
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Query (Efficient)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; In the &lt;strong&gt;▼ Scan or query items&lt;/strong&gt; tab, switch from &lt;strong&gt;Scan&lt;/strong&gt; to &lt;strong&gt;Query&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partition key Value:&lt;/strong&gt; &lt;code&gt;PRODUCT#laptop-001&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort key Value:&lt;/strong&gt; Begins with ▼ &lt;code&gt;REVIEW&lt;/code&gt;
Click &lt;strong&gt;Run&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Completed · Items returned: 1 · Items scanned: 1 · Efficiency: 100% · RCUs consumed: 0.5&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You'll see only the review items for that product. DynamoDB read exactly the items you asked for.&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;Efficient.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Scan (Expensive)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Switch back to &lt;strong&gt;Scan&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Run&lt;/strong&gt; with no filters&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Completed · Items returned: 5 · Items scanned: 5 · Efficiency: 100% · RCUs consumed: 2&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You'll see ALL items in the table. DynamoDB read every single item. On a table with millions of items.&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;This is slow and expensive.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Click &lt;strong&gt;Add filter&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attribute name: &lt;code&gt;category&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Type: String&lt;/li&gt;
&lt;li&gt;Condition: Equal to&lt;/li&gt;
&lt;li&gt;Value: &lt;code&gt;electronics&lt;/code&gt;
Click &lt;strong&gt;Run&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Completed · Items returned: 2 · Items scanned: 5 · Efficiency: 40% · RCUs consumed: 2&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You'll see only electronics items, but &lt;em&gt;DynamoDB still read the entire table&lt;/em&gt; and filtered afterward. The filter doesn't reduce the read cost.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 &lt;code&gt;FilterExpression&lt;/code&gt; does NOT reduce the amount of data read. It only filters what's returned to you. You still pay for the full scan. To reduce reads, use better key design or GSIs.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Query the GSI&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Switch to &lt;strong&gt;Query&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Change the &lt;strong&gt;Index&lt;/strong&gt; dropdown to &lt;strong&gt;GSI1&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Partition key (GSI1PK) Value:&lt;/strong&gt; &lt;code&gt;CATEGORY#electronics&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort key (GSI1SK) Value:&lt;/strong&gt; Begins with ▼ &lt;code&gt;PRICE#&lt;/code&gt;
Click &lt;strong&gt;Run&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt;: Completed · Items returned: 2 · Items scanned: 2 · Efficiency: 100% · RCUs consumed: 0.5&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This efficiently finds all electronics products, sorted by price. That's the power of a well-designed GSI.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Part IV
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Build the API with Lambda
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Create the Lambda Function
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;Lambda&lt;/strong&gt; console → &lt;strong&gt;Create function&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; &lt;code&gt;ProductCatalogAPI&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; &lt;code&gt;Python 3.12&lt;/code&gt;
Click &lt;strong&gt;Create function&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt;: Successfully created the function "ProductCatalogAPI".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; &lt;strong&gt;Configuration&lt;/strong&gt; → *&lt;em&gt;General configuration&lt;/em&gt; → click Edit&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; &lt;code&gt;256 MB&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout:&lt;/strong&gt; &lt;code&gt;10 seconds&lt;/code&gt;
Click &lt;strong&gt;Save&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt;Add DynamoDB Permissions&lt;br&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; → &lt;strong&gt;Permissions&lt;/strong&gt; → click the role name&lt;br&gt;
&lt;strong&gt;Add permissions&lt;/strong&gt; → &lt;strong&gt;Attach policies&lt;/strong&gt;&lt;br&gt;
Search for and attach &lt;code&gt;AmazonDynamoDBFullAccess&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;In production, scope this down to only the &lt;code&gt;ProductCatalog&lt;/code&gt; table. For this tutorial, full access keeps things simple. &lt;em&gt;Brevity.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; &lt;strong&gt;Write the Function Code&lt;/strong&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;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Attr&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize OUTSIDE the handler — reused across warm invocations
&lt;/span&gt;&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ProductCatalog&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DecimalEncoder&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="n"&gt;JSONEncoder&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;DynamoDB returns Decimal types — this converts them to float for JSON.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Routes requests based on the HTTP method and path.
    Demonstrates query, scan, get_item, and put_item operations.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;http_method&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;httpMethod&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;GET&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;path&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;path&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;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;path_params&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pathParameters&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;query_params&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;queryStringParameters&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;try&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;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/products&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;GET&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="nf"&gt;list_products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/products/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path_params&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;productId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&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="nf"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/products&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;body&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;event&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="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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{}&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="nf"&gt;create_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/products/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/reviews&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path_params&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;productId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;get_reviews&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&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;error&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;Not found&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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;error&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;Internal server error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    List products by category using QUERY (efficient).
    Falls back to SCAN if no category is specified (expensive — avoid in production).
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_params&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;category&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;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# QUERY — efficient, reads only matching items
&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;Querying products in category: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PK&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&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;CATEGORY#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}&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="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# SCAN — reads entire table, expensive!
&lt;/span&gt;        &lt;span class="c1"&gt;# In production, require a category or use pagination
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WARNING: Scanning entire table — this is expensive!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;FilterExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SK&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;METADATA&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&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="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;products&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Items&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;count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Count&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;scannedCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ScannedCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Shows the difference between query and scan
&lt;/span&gt;    &lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Get a single product by ID using GET_ITEM.
    This is the most efficient read — directly accesses one item by its full key.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Key&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;PK&lt;/span&gt;&lt;span class="sh"&gt;'&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;PRODUCT#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&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;SK&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;METADATA&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;# ConsistentRead=True  # Uncomment for strongly consistent read (2x cost)
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Item&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&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;error&lt;/span&gt;&lt;span class="sh"&gt;'&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;Product &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found&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="nf"&gt;response&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="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_reviews&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Get all reviews for a product using QUERY with sort key condition.
    begins_with on the sort key efficiently finds all reviews.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PK&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&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;PRODUCT#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;
            &lt;span class="nc"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SK&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;begins_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;REVIEW#&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="n"&gt;ScanIndexForward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;  &lt;span class="c1"&gt;# Sort descending (newest first)
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&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="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;productId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Items&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;count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Count&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a new product using PUT_ITEM.
    Also creates the category listing item for efficient category queries.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;productId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;  &lt;span class="c1"&gt;# DynamoDB requires Decimal, not float!
&lt;/span&gt;
    &lt;span class="c1"&gt;# Write the product metadata
&lt;/span&gt;    &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Item&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;PK&lt;/span&gt;&lt;span class="sh"&gt;'&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;PRODUCT#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&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;SK&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;METADATA&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;GSI1PK&lt;/span&gt;&lt;span class="sh"&gt;'&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;CATEGORY#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}&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;GSI1SK&lt;/span&gt;&lt;span class="sh"&gt;'&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;PRICE#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;010.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Zero-padded for correct sort order
&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="n"&gt;body&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;description&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="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&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;active&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;stock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# Write the category listing (denormalization for efficient queries)
&lt;/span&gt;    &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Item&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;PK&lt;/span&gt;&lt;span class="sh"&gt;'&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;CATEGORY#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="si"&gt;}&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;SK&lt;/span&gt;&lt;span class="sh"&gt;'&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;PRODUCT#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&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="n"&gt;body&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&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;message&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;Product created&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;productId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&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="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DecimalEncoder&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;strong&gt;Step 05:&lt;/strong&gt; Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "ProductCatalogAPI".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice &lt;code&gt;Decimal(str(body['price']))&lt;/code&gt;. DynamoDB does NOT support Python &lt;code&gt;float&lt;/code&gt;. You must use &lt;code&gt;Decimal&lt;/code&gt;. This is a common gotcha.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; &lt;strong&gt;Test The Function&lt;/strong&gt;&lt;br&gt;
Click the &lt;strong&gt;Test&lt;/strong&gt; tab&lt;br&gt;
Create test events for each operation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;List products by category:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"httpMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queryStringParameters"&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="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"electronics"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pathParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;Get a single product:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"httpMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/products/laptop-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pathParameters"&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="nl"&gt;"productId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queryStringParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;Get reviews:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"httpMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/products/laptop-001/reviews"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pathParameters"&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="nl"&gt;"productId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queryStringParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;Create a product:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"httpMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"body"&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="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;productId&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;keyboard-003&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Mechanical Keyboard&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;electronics&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;price&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:89.99,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;stock&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:100}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pathParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"queryStringParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Run each test and check the results. Look at the &lt;code&gt;count&lt;/code&gt; vs &lt;code&gt;scannedCount&lt;/code&gt; in the list response. When using query, they'll be equal. When scanning, &lt;code&gt;scannedCount&lt;/code&gt; will be higher.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part V
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Consistency Models
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;See the Difference&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; In the Lambda function, find the &lt;code&gt;get_product&lt;/code&gt; function&lt;br&gt;
Uncomment the &lt;code&gt;ConsistentRead=True&lt;/code&gt; line&lt;br&gt;
&lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "ProductCatalogAPI".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now &lt;code&gt;get_product&lt;/code&gt; uses &lt;strong&gt;strongly consistent reads&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always returns the latest data&lt;/li&gt;
&lt;li&gt;Costs &lt;strong&gt;2x&lt;/strong&gt; the read capacity&lt;/li&gt;
&lt;li&gt;Only works on the &lt;strong&gt;base table&lt;/strong&gt; (not GSIs)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 &lt;strong&gt;GSIs only support eventually consistent reads.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;When to Use Each&lt;/strong&gt;
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Consistency&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Why&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Product catalog browsing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Eventually consistent&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Stale data for a second is fine&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shopping cart&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strongly consistent&lt;/td&gt;
&lt;td&gt;&lt;em&gt;User expects to see what they just added&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inventory check before purchase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strongly consistent&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Must be accurate to avoid overselling&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Analytics dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Eventually consistent&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Slight delay is acceptable&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Part VI
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;TTL:&lt;/strong&gt; Automatic Data Expiration
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Enable TTL&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; In the &lt;strong&gt;DynamoDB&lt;/strong&gt; console, click on &lt;code&gt;ProductCatalog&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;▼ Actions&lt;/strong&gt; &lt;br&gt;
Click &lt;strong&gt;Turn on TTL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; &lt;strong&gt;Turn on Time to Live (TTL)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;TTL attribute name:&lt;/strong&gt; &lt;code&gt;ttl&lt;/code&gt;&lt;br&gt;
Click &lt;strong&gt;Turn on TTL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully activated Time to Live for the ProductCatalog table with the ttl attribute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; &lt;strong&gt;Add Items with TTL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an item with a TTL value (Unix epoch timestamp):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"PK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SESSION#user-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"SK"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DATA"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userId"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user-001"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cartItems"&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="nl"&gt;"L"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop-001"&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="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mouse-002"&lt;/span&gt;&lt;span class="p"&gt;}]},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&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="nl"&gt;"N"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1745625600"&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;blockquote&gt;
&lt;p&gt;The &lt;code&gt;ttl&lt;/code&gt; value is a Unix timestamp. Items are deleted after this time. Use an &lt;a href="https://www.epochconverter.com/" rel="noopener noreferrer"&gt;epoch converter&lt;/a&gt; to set a time a few minutes in the future for testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 TTL deletion is &lt;strong&gt;eventually consistent:&lt;/strong&gt; items may persist for up to 48 hours after expiration. Don't rely on TTL for exact timing. Always filter out expired items in your queries as a safety measure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part VII
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Caching with DAX
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DAX (DynamoDB Accelerator) is an in-memory cache that sits in front of DynamoDB. It's a drop-in replacement. Same API, just change the client endpoint&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;When to Use DAX&lt;/strong&gt;
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Scenario&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Use DAX?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read-heavy workload, same items queried repeatedly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microsecond response times needed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write-heavy workload&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (DAX is a read cache)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Need strongly consistent reads&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (DAX returns eventually consistent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Diverse access patterns, rarely same item twice&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (low cache hit rate)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;How DAX Works&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without DAX:
  App → DynamoDB (single-digit millisecond reads)

With DAX:
  App → DAX (microsecond reads if cached) → DynamoDB (on cache miss)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Console Walkthrough&lt;/strong&gt; &lt;em&gt;(Don't Create.Just Understand)&lt;/em&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;💸 &lt;strong&gt;DAX requires a VPC and costs money even when idle. We'll walk through the setup without creating it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Click &lt;strong&gt;▼ DAX&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;Create cluster&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cluster name:&lt;/strong&gt; &lt;code&gt;product-cache&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node type family:&lt;/strong&gt; &lt;code&gt;t-type family&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node type:&lt;/strong&gt; &lt;code&gt;dax.t3.small&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster size:&lt;/strong&gt; &lt;code&gt;3&lt;/code&gt; nodes (for high availability)
Click &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; &lt;strong&gt;Configure networks&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network Type:&lt;/strong&gt; &lt;code&gt;IPv4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subnet group:&lt;/strong&gt; &lt;code&gt;Create new&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subnet group name:&lt;/strong&gt; &lt;code&gt;MySubnetGroup&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC ID:&lt;/strong&gt; &lt;code&gt;defaultVPC&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subnets:&lt;/strong&gt; &lt;code&gt;Select all&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security group:&lt;/strong&gt; &lt;code&gt;default ▼&lt;/code&gt;
Click &lt;strong&gt;View in EC2 console&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Allow port 8111 from your Lambda functions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Inbound security group rules successfully modified on security group&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; &lt;strong&gt;Configure Security&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IAM Service role for DynamoDB access:&lt;/strong&gt; &lt;code&gt;Create new&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM role name:&lt;/strong&gt; &lt;code&gt;DaxToDynamoDB&lt;/code&gt;
Click &lt;strong&gt;Next&lt;/strong&gt; → Click &lt;strong&gt;Next&lt;/strong&gt; → Click &lt;strong&gt;Create cluster&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created the cluster product-cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; In your Lambda code, you'd change one line:&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="c1"&gt;# Without DAX
&lt;/span&gt;&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# With DAX — same API, just different endpoint
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;amazondax&lt;/span&gt;
&lt;span class="n"&gt;dax_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;amazondax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AmazonDaxClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;endpoints&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;product-cache.abc123.dax-clusters.us-east-1.amazonaws.com:8111&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="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dax_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ProductCatalog&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# All your existing code works unchanged!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DAX is a drop-in replacement for DynamoDB reads. Same API, same code. Just change the client. 💡 But remember: DAX only supports eventually consistent reads and is for read-heavy workloads.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🏗️ What You Built | 📘Exam Concepts Recap
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;What You Did&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Exam Concept&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Designed a table around access patterns first&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Access-pattern-driven DynamoDB design&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Created a composite primary key (PK + SK)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Single-table design, sort key relationships&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Added a Global Secondary Index with different keys&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;GSI for alternate access patterns&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Used overloaded keys (&lt;code&gt;PRODUCT#&lt;/code&gt;, &lt;code&gt;CATEGORY#&lt;/code&gt;, &lt;code&gt;REVIEW#&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Single-table design pattern&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Queried by partition key with &lt;code&gt;begins_with&lt;/code&gt; on sort key&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Efficient query operations&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ran a scan and compared &lt;code&gt;Count&lt;/code&gt; vs &lt;code&gt;ScannedCount&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Scan is expensive: it reads the entire table&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Added a &lt;code&gt;FilterExpression&lt;/code&gt; to a scan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Filters run AFTER reading: don't save capacity&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Used &lt;code&gt;Decimal(str(price))&lt;/code&gt; instead of &lt;code&gt;float&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;DynamoDB type system: no float support&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Toggled &lt;code&gt;ConsistentRead=True&lt;/code&gt; on &lt;code&gt;get_item&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Strongly vs eventually consistent reads&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Noted GSIs only support eventual consistency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;GSI limitations&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enabled TTL on a &lt;code&gt;ttl&lt;/code&gt; attribute&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Automatic data lifecycle management&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Walked through DAX setup&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Read caching for DynamoDB, microsecond latency&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚠️ Clean Up Protocol
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;DynamoDB&lt;/strong&gt; → Delete the &lt;code&gt;ProductCatalog&lt;/code&gt; table&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Lambda&lt;/strong&gt; → Delete &lt;code&gt;ProductCatalogAPI&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;IAM&lt;/strong&gt; → Delete the Lambda execution role&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;CloudWatch&lt;/strong&gt; → Delete the log groups&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Partition key cardinality:&lt;/strong&gt; high cardinality = even distribution = good performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query &amp;gt; Scan:&lt;/strong&gt; always prefer query. Scan reads the entire table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FilterExpression doesn't save reads:&lt;/strong&gt; it filters after reading. Use key design or GSIs instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GSIs&lt;/strong&gt; can be added anytime. &lt;strong&gt;LSIs&lt;/strong&gt; must be created with the table&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GSIs are eventually consistent only:&lt;/strong&gt; no strongly consistent reads on GSIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Decimal, not float&lt;/strong&gt; for DynamoDB numbers in Python&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL&lt;/strong&gt; is free but eventually consistent (up to 48 hours delay)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DAX&lt;/strong&gt; = DynamoDB read cache (microsecond reads). Same API as DynamoDB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DAX doesn't support strongly consistent reads&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-table design&lt;/strong&gt; with overloaded keys is the recommended DynamoDB pattern&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html" rel="noopener noreferrer"&gt;Best practices for designing and architecting with DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html" rel="noopener noreferrer"&gt;Querying tables in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html" rel="noopener noreferrer"&gt;Using Global Secondary Indexes in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DAX.html" rel="noopener noreferrer"&gt;In-memory acceleration with DynamoDB Accelerator (DAX)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html" rel="noopener noreferrer"&gt;Using Time to Live (TTL) in DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🏗️&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloud</category>
      <category>developer</category>
    </item>
    <item>
      <title>Develop Code for Lambda | 🏗️ Build A Real-Time Data Processing Pipeline</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Thu, 07 May 2026 20:34:21 +0000</pubDate>
      <link>https://dev.to/aws-builders/develop-code-for-lambda-build-a-real-time-data-processing-pipeline-iii</link>
      <guid>https://dev.to/aws-builders/develop-code-for-lambda-build-a-real-time-data-processing-pipeline-iii</guid>
      <description>&lt;p&gt;&lt;strong&gt;Exam Guide:&lt;/strong&gt; Developer - Associate&lt;br&gt;
&lt;strong&gt;🏗️ Domain 1:&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;Development with AWS Services&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
📘 &lt;strong&gt;Task 2:&lt;/strong&gt; &lt;em&gt;Develop Code for Lambda&lt;/em&gt;       &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lambda is the most heavily tested service on the DVA-C02. It is also perhaps, one of the most used and talked about services in general too, well after EC2 and S3. So, you need to know how to configure it, write code for it, handle errors, tune performance, and integrate it with practically every other AWS service.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  📘Concepts
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Lambda Execution Model
&lt;/h3&gt;

&lt;p&gt;When you invoke a Lambda function, AWS:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Finds or creates an &lt;em&gt;execution environment&lt;/em&gt; (container)&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Loads your code and initializes it (&lt;em&gt;cold start&lt;/em&gt;)&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Runs your &lt;em&gt;handler function&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; Keeps the environment &lt;em&gt;warm&lt;/em&gt; for reuse (subsequent invocations skip step 2)&lt;/p&gt;

&lt;p&gt;Code outside the handler runs once during cold start and is reused. This is why you initialize SDK clients and database connections outside the handler.&lt;/p&gt;
&lt;h3&gt;
  
  
  Key Configuration Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Notes&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;128 MB – 10,240 MB&lt;/td&gt;
&lt;td&gt;128 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CPU scales proportionally with memory&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Timeout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1s – 900s (15 min)&lt;/td&gt;
&lt;td&gt;3s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Max 15 minutes: use Step Functions or ECS for longer or Durable functions&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Concurrency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reserved or Provisioned&lt;/td&gt;
&lt;td&gt;1000/region&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reserved = guarantee + cap; Provisioned = pre-warmed&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ephemeral storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;512 MB – 10,240 MB&lt;/td&gt;
&lt;td&gt;512 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;/tmp directory for temporary files&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Layers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 5&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;250 MB total unzipped (function + layers)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Invocation Types and Error Handling
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Invocation Type&lt;/th&gt;
&lt;th&gt;Source Examples&lt;/th&gt;
&lt;th&gt;Retry Behavior&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Error Destination&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Synchronous&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;API Gateway, ALB&lt;/td&gt;
&lt;td&gt;No automatic retries caller handles it&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Caller gets the error&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Asynchronous&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;S3, SNS, EventBridge&lt;/td&gt;
&lt;td&gt;2 automatic retries (3 total)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DLQ or Lambda Destinations&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event source mapping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQS, Kinesis, DynamoDB Streams&lt;/td&gt;
&lt;td&gt;Retries until record expires or succeeds&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DLQ (SQS) or on-failure destination&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Lambda Destinations vs DLQ
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;DLQ&lt;/th&gt;
&lt;th&gt;Lambda Destinations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Captures success&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Captures failure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context included&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Full (request, response, error)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supported targets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SQS, SNS&lt;/td&gt;
&lt;td&gt;SQS, SNS, Lambda, EventBridge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Works with&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Async invocations&lt;/td&gt;
&lt;td&gt;Async invocations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lambda Destinations are the modern approach and preferred over DLQs. DLQs are still valid for SQS event source mappings.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  VPC Access
&lt;/h3&gt;

&lt;p&gt;By default, Lambda runs in an AWS-managed VPC and can access the internet and public AWS services. When you attach Lambda to your own VPC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without VPC:  Lambda → Internet → AWS Services ✅  |  Lambda → Private RDS ❌
With VPC:     Lambda → Private RDS ✅  |  Lambda → Internet ❌ (needs NAT Gateway)
              Lambda → VPC Endpoint → AWS Services ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Points:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; VPC Lambda needs &lt;em&gt;private subnets&lt;/em&gt; with a &lt;em&gt;NAT Gateway&lt;/em&gt; for internet access&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Use &lt;em&gt;VPC endpoints&lt;/em&gt; (PrivateLink) to access DynamoDB, S3, SQS without NAT&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Use &lt;em&gt;RDS Proxy&lt;/em&gt; for connection pooling because Lambda can overwhelm databases with concurrent connections&lt;/p&gt;
&lt;h3&gt;
  
  
  Cold Starts
&lt;/h3&gt;

&lt;p&gt;A cold start happens when Lambda creates a new execution environment. Strategies to reduce them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;em&gt;Provisioned Concurrency:&lt;/em&gt; pre-warms environments (costs money when idle)&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;em&gt;Keep deployment packages small:&lt;/em&gt; smaller packages initialize faster&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;em&gt;Initialize outside the handler:&lt;/em&gt; SDK clients, DB connections, config&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;em&gt;Use ARM (Graviton2):&lt;/em&gt; often faster and 20% cheaper&lt;/p&gt;
&lt;h3&gt;
  
  
  Kinesis And Lambda Key Settings
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Relevance&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Batch size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Records per invocation (max 10,000)&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Larger batches = fewer invocations&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Batch window&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Wait time to fill batch (max 300s)&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Reduces invocations for low-traffic streams&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Parallelization factor&lt;/strong&gt; (1–10)&lt;/td&gt;
&lt;td&gt;Concurrent batches per shard&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Increases throughput without adding shards&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bisect batch on error&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Splits batch in half on failure&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Isolates the bad record&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Starting position&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LATEST or TRIM_HORIZON&lt;/td&gt;
&lt;td&gt;&lt;em&gt;LATEST = new only. TRIM_HORIZON = from beginning&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  🏗️ Build A Real Time Data Processing Pipeline
&lt;/h2&gt;

&lt;p&gt;Now let's put these concepts into practice by building a &lt;strong&gt;Real-Time Data Processing Pipeline&lt;/strong&gt; using Lambda:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Lambda function with VPC access connecting to an RDS database&lt;/li&gt;
&lt;li&gt;Lambda layers for shared dependencies&lt;/li&gt;
&lt;li&gt;A DLQ (Dead Letter Queue) and Lambda Destinations for error handling&lt;/li&gt;
&lt;li&gt;A Kinesis stream processor that transforms data in near real time&lt;/li&gt;
&lt;li&gt;Performance tuning with memory configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This covers all the skills for this task: Lambda configuration, VPC access, error handling, event lifecycle, integrations, and performance tuning.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ntombizakhona.medium.com/amazon-web-services-a8e57a9c6084" rel="noopener noreferrer"&gt;&lt;strong&gt;An AWS account&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;(free tier covers most of this)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Part I
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create and Configure a Lambda Function
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Create the Function&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;Lambda&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02: **Click **Create function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; &lt;strong&gt;Create function&lt;/strong&gt;&lt;br&gt;
Choose &lt;strong&gt;Author from scratch&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; &lt;code&gt;DataProcessor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; Python 3.12&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Create function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created the function "DataProcessor".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Before writing code, let's walk through the configuration tabs.&lt;/em&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Click the &lt;strong&gt;Configuration&lt;/strong&gt; tab.&lt;br&gt;
&lt;strong&gt;General configuration&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Edit&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; 256 MB &lt;em&gt;(default is 128 MB)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ephemeral storage:&lt;/strong&gt; 512 MB &lt;em&gt;(default)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout:&lt;/strong&gt; 0 min 30 sec &lt;em&gt;(default is 3 seconds)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lambda allocates CPU proportionally to memory. At 1,769 MB you get one full vCPU. Increasing memory from 128 MB to 256 MB doubles your CPU therefore your function might run in half the time, costing the same or less.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; &lt;strong&gt;Environment variables&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Environment variables&lt;/strong&gt; → &lt;strong&gt;Edit&lt;/strong&gt; → &lt;strong&gt;Add environment variable&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key: &lt;code&gt;LOG_LEVEL&lt;/code&gt;, Value: &lt;code&gt;INFO&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Key: &lt;code&gt;STAGE&lt;/code&gt;, Value: &lt;code&gt;dev&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "DataProcessor".&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;os&lt;/span&gt;

&lt;span class="c1"&gt;# Access environment variables in your code
&lt;/span&gt;&lt;span class="n"&gt;log_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LOG_LEVEL&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;INFO&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;STAGE&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;dev&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lambda encrypts all environment variables at rest by default using an AWS managed KMS key. For extra security, you can use a customer managed KMS key and decrypt in your code.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part II
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a Lambda Layer
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Layers let you share code and libraries across multiple functions. Let's create one with a utility module.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Build and Upload a Layer&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Layers must be uploaded as a zip file. &lt;br&gt;
We'll use &lt;strong&gt;AWS CloudShell:&lt;/strong&gt; a browser-based terminal built into the AWS Console so that you don't need anything installed locally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open &lt;strong&gt;CloudShell&lt;/strong&gt; by clicking the terminal icon (&lt;code&gt;&amp;gt;_&lt;/code&gt;) in the top navigation bar of the AWS Console next to the search bar&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Wait for it to initialize as it might take a few seconds the first time&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt;&lt;br&gt;
Run these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; python
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; python/utils.py &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
"""
Shared utilities for Lambda functions.
This module is packaged as a Lambda Layer so multiple functions can use it.
"""
import json
import time
import random

def retry_with_backoff(func, max_retries=3, base_delay=0.5):
    """Retry with exponential backoff and jitter."""
    for attempt in range(max_retries + 1):
        try:
            return func()
        except Exception as e:
            if attempt == max_retries:
                raise
            delay = base_delay * (2 ** attempt)
            jitter = random.uniform(0, delay)
            time.sleep(delay + jitter)

def format_response(status_code, body):
    """Standard API Gateway response format."""
    return {
        'statusCode': status_code,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps(body, default=str)
    }
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;zip &lt;span class="nt"&gt;-r&lt;/span&gt; utils-layer.zip python/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Download the zip&lt;br&gt;
Click &lt;strong&gt;Actions ▼&lt;/strong&gt; (top right of CloudShell) → &lt;strong&gt;Download file&lt;/strong&gt; → type &lt;code&gt;utils-layer.zip&lt;/code&gt; → click &lt;strong&gt;Download&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why the &lt;code&gt;python/&lt;/code&gt; folder?&lt;/strong&gt; Lambda layers must follow a specific directory structure. For Python, your code must be inside a &lt;code&gt;python/&lt;/code&gt; folder in the zip. Lambda adds this path to &lt;code&gt;sys.path&lt;/code&gt; automatically so your functions can &lt;code&gt;import utils&lt;/code&gt; directly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Upload the Layer via Console&lt;br&gt;
In the Lambda console, click &lt;strong&gt;Layers&lt;/strong&gt; in the left sidebar&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Click &lt;strong&gt;Create layer&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;shared-utils&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload:&lt;/strong&gt; Choose the &lt;code&gt;utils-layer.zip&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatible runtimes - &lt;em&gt;optional&lt;/em&gt;:&lt;/strong&gt; Python 3.12
Click &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created layer shared-utils version 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; &lt;strong&gt;Attach the Layer to Your Function&lt;/strong&gt;&lt;br&gt;
Go back to the &lt;code&gt;DataProcessor&lt;/code&gt; function&lt;br&gt;
Scroll down to the &lt;strong&gt;Layers&lt;/strong&gt; section&lt;br&gt;
Click &lt;strong&gt;Edit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 08:&lt;/strong&gt; &lt;strong&gt;Edit layers&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Add a layer&lt;/strong&gt;&lt;br&gt;
Choose &lt;strong&gt;Custom layers&lt;/strong&gt;&lt;br&gt;
Select &lt;code&gt;shared-utils&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Version:&lt;/strong&gt; &lt;code&gt;1&lt;/code&gt;&lt;br&gt;
Click &lt;strong&gt;Add&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "DataProcessor".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 09:&lt;/strong&gt; Now you can use it in your function code:&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;utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;format_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retry_with_backoff&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;format_response&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&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;Hello from DataProcessor&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;A function can have up to &lt;strong&gt;5 layers&lt;/strong&gt;. The total unzipped size of the function + all layers can't exceed &lt;strong&gt;250 MB&lt;/strong&gt;. Layers are versioned and immutable. Each upload creates a new version.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part III
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Error Handling:&lt;/strong&gt; DLQ and Lambda Destinations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Create a Dead Letter Queue&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;SQS&lt;/strong&gt; console&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;Create queue&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Standard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;data-processor-dlq&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Create queue&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Queue data-processor-dlq created successfully&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Copy the &lt;strong&gt;Queue ARN&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Create a Success Queue (for Destinations)&lt;br&gt;
Create another queue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;data-processor-success&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copy the &lt;strong&gt;Queue ARN&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; &lt;strong&gt;Lambda&lt;/strong&gt; → DataProcessor → Configuration → Permissions → Click the &lt;strong&gt;Role name&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Add permissions&lt;/strong&gt; → &lt;code&gt;Attach policies&lt;/code&gt;&lt;br&gt;
Search for &lt;code&gt;AmazonSQSFullAccess&lt;/code&gt; and attach it&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Configure the DLQ on the Lambda Function&lt;br&gt;
Go back to the &lt;code&gt;DataProcessor&lt;/code&gt; function&lt;br&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; tab → &lt;strong&gt;Asynchronous invocation&lt;/strong&gt; → &lt;strong&gt;Edit&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maximum age of event:&lt;/strong&gt; &lt;code&gt;1 h 0 min 0 sec&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry attempts:&lt;/strong&gt; &lt;code&gt;2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead-letter queue service ▼:&lt;/strong&gt; Select &lt;code&gt;Amazon SQS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue ▼:&lt;/strong&gt; Select &lt;code&gt;data-processor-dlq&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "DataProcessor".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Destinations are the modern approach. They capture both success AND failure.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; Configure Lambda Destinations&lt;br&gt;
Still in &lt;strong&gt;Asynchronous invocation&lt;/strong&gt;, find the &lt;strong&gt;Destinations&lt;/strong&gt; section&lt;br&gt;
Click &lt;strong&gt;Add destination&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 08:&lt;/strong&gt; Add destination&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;code&gt;Asynchronous invocation&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition:&lt;/strong&gt; &lt;code&gt;On success&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination type:&lt;/strong&gt; &lt;code&gt;SQS queue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination:&lt;/strong&gt; &lt;code&gt;data-processor-success&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Your changes have been saved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 09:&lt;/strong&gt; Click &lt;strong&gt;Add destination&lt;/strong&gt; again&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;code&gt;Asynchronous invocation&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition:&lt;/strong&gt; &lt;code&gt;On failure&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination type:&lt;/strong&gt; &lt;code&gt;SQS queue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination:&lt;/strong&gt; &lt;code&gt;data-processor-dlq&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Your changes have been saved.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lambda Destinations are preferred over DLQs because:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Destinations capture &lt;strong&gt;both&lt;/strong&gt; success and failure (DLQ only captures failure)&lt;/li&gt;
&lt;li&gt;Destinations include more context (request payload, response, error details)&lt;/li&gt;
&lt;li&gt;Destinations work with async invocations only (same as DLQ)&lt;/li&gt;
&lt;li&gt;DLQs are still valid for SQS event source mappings&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Test Error Handling&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 10:&lt;/strong&gt; Let's create a function that sometimes fails to see the error handling in action:&lt;/p&gt;

&lt;p&gt;Deploy this code, then test it&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;random&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    This function randomly fails to demonstrate error handling.
    When invoked asynchronously:
    1. First attempt fails → Lambda retries
    2. Second attempt fails → Lambda retries again
    3. Third attempt fails → Event goes to DLQ / failure destination
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;action&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;action&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;process&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;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fail&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Always fail — will end up in DLQ after 3 attempts
&lt;/span&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Simulated failure for testing DLQ&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;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;random&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# 50% chance of failure
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Random failure occurred&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;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;message&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;Processed successfully&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;action&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;action&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;strong&gt;Step 11:&lt;/strong&gt; Click &lt;strong&gt;Test&lt;/strong&gt; tab&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 12:&lt;/strong&gt; &lt;strong&gt;Test event&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test event action:&lt;/strong&gt; &lt;code&gt;Create new event&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invocation type:&lt;/strong&gt; &lt;code&gt;Synchronous&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event name:&lt;/strong&gt; &lt;code&gt;TestFailure&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Even JSON:&lt;/strong&gt;
&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="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="s2"&gt;"fail"&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;Test&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Executing function:&lt;/strong&gt; failed&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The function will fail. Since this is a synchronous test invocation, you'll see the error immediately. To test the DLQ flow, you need an &lt;strong&gt;asynchronous&lt;/strong&gt; invocation (from S3, SNS, or EventBridge).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part IV
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lambda with VPC Access
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When Lambda needs to access private resources like RDS or ElastiCache, you attach it to a VPC. Let's walk through the configuration.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Understanding VPC Access&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without VPC:
  Lambda → Internet → AWS Services (DynamoDB, S3, SQS)  ✅
  Lambda → Private RDS                                    ❌

With VPC:
  Lambda → VPC → Private RDS                              ✅
  Lambda → VPC → Internet                                 ❌ (no NAT)
  Lambda → VPC → NAT Gateway → Internet                   ✅
  Lambda → VPC → VPC Endpoint → AWS Services              ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Configure VPC Access (Console Walkthrough)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;code&gt;DataProcessor&lt;/code&gt; function&lt;br&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; tab → &lt;strong&gt;VPC&lt;/strong&gt; → &lt;strong&gt;Edit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; &lt;strong&gt;Edit VPC&lt;/strong&gt;&lt;br&gt;
Select the default VPC&lt;br&gt;
Select &lt;strong&gt;at least 2 private subnets&lt;/strong&gt; (for high availability)&lt;br&gt;
Select or create a &lt;strong&gt;security group&lt;/strong&gt; that allows outbound traffic&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️Important:&lt;/strong&gt; The Lambda execution role needs the &lt;code&gt;AWSLambdaVPCAccessExecutionRole&lt;/code&gt; managed policy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Connection Reuse Pattern&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When connecting to databases from Lambda, initialize the connection &lt;strong&gt;outside&lt;/strong&gt; the handler:&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&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;os&lt;/span&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;boto3&lt;/span&gt;

&lt;span class="c1"&gt;# This runs ONCE during cold start, then reuses across warm invocations
# This is critical for database connections — you don't want to open
# a new connection on every single invocation
&lt;/span&gt;&lt;span class="n"&gt;db_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DB_HOST&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;db_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DB_NAME&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# In a real app, you'd initialize your database connection here
# connection = pymysql.connect(host=db_host, ...)
&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    The handler runs on every invocation.
    The connection above is reused across warm invocations.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Use the connection...
&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;message&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;Connected to database&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Always initialize SDK clients and database connections &lt;strong&gt;outside&lt;/strong&gt; the handler. This code runs once during the cold start and is reused for subsequent warm invocations. &lt;br&gt;
For RDS specifically, use &lt;strong&gt;RDS Proxy&lt;/strong&gt; to manage connection pooling.  Lambda can open hundreds of connections simultaneously, which can overwhelm a database.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part V
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Process Streaming Data with Kinesis
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Let's build a real-time clickstream processor.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Create a Kinesis Data Stream&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;Kinesis&lt;/strong&gt; console&lt;br&gt;
Click &lt;strong&gt;Create data stream&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data stream name:&lt;/strong&gt; &lt;code&gt;clickstream&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capacity mode:&lt;/strong&gt; &lt;code&gt;On-demand&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Create data stream&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Data stream clickstream successfully created&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Create the Stream Processor Function&lt;br&gt;
Go to &lt;strong&gt;Lambda&lt;/strong&gt; → &lt;strong&gt;Create function&lt;/strong&gt;&lt;br&gt;
Configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; &lt;code&gt;ClickstreamProcessor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; Python 3.12&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory:&lt;/strong&gt; 512 MB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout:&lt;/strong&gt; 60 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Paste this code&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;base64&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Processes clickstream records from Kinesis in near real time.

    Key concepts for the exam:
    - Kinesis data is base64 encoded
    - Records come in batches
    - The partition key determines which shard receives the record
    - Use a high-cardinality partition key (like userId) for even distribution
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;processed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;Received &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Records&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; records from Kinesis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&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;Records&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Kinesis data is base64 encoded — decode it
&lt;/span&gt;            &lt;span class="n"&gt;raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kinesis&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;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&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;raw_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Extract clickstream fields
&lt;/span&gt;            &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;userId&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;anonymous&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;page&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;action&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

            &lt;span class="c1"&gt;# Process the click event
&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;Click: user=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, page=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, action=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, time=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# In a real app, you'd:
&lt;/span&gt;            &lt;span class="c1"&gt;# - Aggregate metrics
&lt;/span&gt;            &lt;span class="c1"&gt;# - Write to DynamoDB or S3
&lt;/span&gt;            &lt;span class="c1"&gt;# - Trigger alerts for specific patterns
&lt;/span&gt;
            &lt;span class="n"&gt;processed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;Failed to process record: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&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;Batch complete: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;processed&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; processed, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed&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;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;processed&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;processed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;failed&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;Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "ClickstreamProcessor".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; &lt;strong&gt;Add Permissions&lt;/strong&gt;&lt;br&gt;
The Lambda execution role needs permission to read from Kinesis:&lt;br&gt;
Go to &lt;strong&gt;Configuration&lt;/strong&gt; → &lt;strong&gt;Permissions&lt;/strong&gt; → click the role name&lt;br&gt;
&lt;strong&gt;Add permissions&lt;/strong&gt; → &lt;strong&gt;Attach policies&lt;/strong&gt;&lt;br&gt;
Search for and attach &lt;code&gt;AmazonKinesisReadOnlyAccess&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Connect Kinesis to Lambda&lt;br&gt;
In the &lt;code&gt;ClickstreamProcessor&lt;/code&gt; function, click &lt;strong&gt;Add trigger&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Add trigger&lt;br&gt;
&lt;strong&gt;Select a source ▼:&lt;/strong&gt; &lt;code&gt;Kinesis&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kinesis stream:&lt;/strong&gt; &lt;code&gt;clickstream&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch size:&lt;/strong&gt; &lt;code&gt;100&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starting position:&lt;/strong&gt; Latest&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch window:&lt;/strong&gt; &lt;code&gt;5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-failure destination:&lt;/strong&gt; ``&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry attempts:&lt;/strong&gt; &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split batch on error:&lt;/strong&gt; &lt;code&gt;✔ enabled&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrent batches per shard:&lt;/strong&gt; &lt;code&gt;10&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Add&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; The trigger clickstream was successfully added to function ClickstreamProcessor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Kinesis + Lambda settings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Batch size:&lt;/strong&gt; how many records per invocation (max 10,000)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch window:&lt;/strong&gt; how long to wait to fill the batch (max 300s)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallelization factor:&lt;/strong&gt; (1–10) process multiple batches per shard concurrently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bisect batch on error:&lt;/strong&gt; splits the batch in half on failure to isolate the bad record&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starting position:&lt;/strong&gt; LATEST (new records only) or TRIM_HORIZON (from the beginning)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; &lt;strong&gt;Test with Sample Data&lt;/strong&gt;&lt;br&gt;
Send test records to the stream:&lt;br&gt;
Open the &lt;strong&gt;Kinesis&lt;/strong&gt; console → click &lt;code&gt;clickstream&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 08:&lt;/strong&gt; &lt;strong&gt;clickstream&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Data viewer&lt;/strong&gt; tab&lt;br&gt;
Or use the &lt;strong&gt;AWS CLI&lt;/strong&gt; to send test data:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`shell&lt;br&gt;
aws kinesis put-record \&lt;br&gt;
  --stream-name clickstream \&lt;br&gt;
  --partition-key "USER-001" \&lt;br&gt;
  --data '{"userId":"USER-001","page":"/products/laptop","action":"view","timestamp":"2026-04-24T10:00:00Z"}'&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 09:&lt;/strong&gt; Check the &lt;code&gt;ClickstreamProcessor&lt;/code&gt; CloudWatch logs to see the processed records&lt;/p&gt;




&lt;h2&gt;
  
  
  Part VI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance Tuning
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Memory vs Duration Experiment&lt;/strong&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;Let's see how memory affects performance:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;code&gt;ClickstreamProcessor&lt;/code&gt; function&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; &lt;strong&gt;Configuration&lt;/strong&gt; → &lt;strong&gt;General configuration&lt;/strong&gt; → &lt;strong&gt;Edit&lt;/strong&gt;&lt;br&gt;
Set &lt;strong&gt;Memory&lt;/strong&gt; to &lt;strong&gt;128 MB&lt;/strong&gt; → &lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Run a test → note the &lt;strong&gt;Duration&lt;/strong&gt; and &lt;strong&gt;Max Memory Used&lt;/strong&gt; in the execution results&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`json&lt;br&gt;
{&lt;br&gt;
  "Records": [&lt;br&gt;
    {&lt;br&gt;
      "kinesis": {&lt;br&gt;
        "data": "eyJ1c2VySWQiOiJVU0VSLTAwMSIsInBhZ2UiOiIvcHJvZHVjdHMvbGFwdG9wIiwiYWN0aW9uIjoidmlldyIsInRpbWVzdGFtcCI6IjIwMjYtMDQtMjRUMTA6MDA6MDBaIn0="&lt;br&gt;
      },&lt;br&gt;
      "eventSource": "aws:kinesis",&lt;br&gt;
      "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/clickstream"&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "kinesis": {&lt;br&gt;
        "data": "eyJ1c2VySWQiOiJVU0VSLTAwMiIsInBhZ2UiOiIvY2hlY2tvdXQiLCJhY3Rpb24iOiJjbGljayIsInRpbWVzdGFtcCI6IjIwMjYtMDQtMjRUMTA6MDE6MDBaIn0="&lt;br&gt;
      },&lt;br&gt;
      "eventSource": "aws:kinesis",&lt;br&gt;
      "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/clickstream"&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Change memory to &lt;strong&gt;256 MB&lt;/strong&gt; → test again&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Change to &lt;strong&gt;512 MB&lt;/strong&gt; → test again&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Change to &lt;strong&gt;1024 MB&lt;/strong&gt; → test again&lt;/p&gt;

&lt;p&gt;You'll typically see:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Duration&lt;/th&gt;
&lt;th&gt;Billed Duration&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Cost per Invocation&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;128 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~200ms&lt;/td&gt;
&lt;td&gt;200ms&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Low per-ms, but slow&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;256 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~110ms&lt;/td&gt;
&lt;td&gt;110ms&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Sweet spot for many functions&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;512 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~60ms&lt;/td&gt;
&lt;td&gt;60ms&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Faster, slightly more per-ms&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1024 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~55ms&lt;/td&gt;
&lt;td&gt;55ms&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Diminishing returns&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The sweet spot is where increasing memory no longer significantly reduces duration.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; Concurrency Settings&lt;br&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; → &lt;strong&gt;Concurrency and recursion detection&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;Concurrency&lt;/strong&gt;→ &lt;strong&gt;Edit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 08:&lt;/strong&gt; &lt;strong&gt;Edit concurrency&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;USe unreserved account concurrency:&lt;/strong&gt; Uses the shared regional pool (default 1000)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reserve concurrency:&lt;/strong&gt; Guarantees capacity AND caps the function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Select &lt;strong&gt;Reserve concurrency:&lt;/strong&gt; &lt;code&gt;50&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Your changes have been saved.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your function is guaranteed 50 concurrent executions&lt;/li&gt;
&lt;li&gt;It can never exceed 50 (acts as a throttle)&lt;/li&gt;
&lt;li&gt;The remaining 950 are available for other functions&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reserved concurrency is free and serves two purposes&lt;/strong&gt;: guaranteeing capacity AND protecting downstream services from being overwhelmed. Provisioned concurrency costs money even when idle but eliminates cold starts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🏗️ What You Built | 📘Exam Concepts Recap
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;What You Did&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Exam Concept&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Created a Lambda function and configured memory/timeout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Lambda configuration parameters&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built and attached a Lambda Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Sharing code across functions, layer structure and limits&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Set up a DLQ and Lambda Destinations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Async error handling, event lifecycle&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Used &lt;code&gt;--invocation-type Event&lt;/code&gt; to trigger async flow&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Synchronous vs asynchronous invocation types&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Attached Lambda to a VPC with subnets and security group&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;VPC access for private resources (RDS, ElastiCache)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Initialized SDK clients outside the handler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Connection reuse, cold start optimization&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Created a Kinesis stream and connected it to Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Real-time data processing, event source mappings&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configured batch size, batch window, parallelization factor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Kinesis + Lambda tuning for throughput&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enabled bisect batch on error&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Isolating bad records in stream processing&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Changed memory settings and compared Duration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Performance tuning, memory = CPU relationship&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Set reserved concurrency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Throttling, capacity guarantees, protecting downstream services&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚠️ Clean Up Protocol
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;Lambda&lt;/strong&gt; → Delete &lt;code&gt;DataProcessor&lt;/code&gt;, &lt;code&gt;ClickstreamProcessor&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Lambda Layers&lt;/strong&gt; → Delete &lt;code&gt;shared-utils&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;Kinesis&lt;/strong&gt; → Delete &lt;code&gt;clickstream&lt;/code&gt; stream&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;SQS&lt;/strong&gt; → Delete &lt;code&gt;data-processor-dlq&lt;/code&gt;, &lt;code&gt;data-processor-success&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;IAM&lt;/strong&gt; → Delete the Lambda execution roles&lt;br&gt;
&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;CloudWatch&lt;/strong&gt; → Delete the log groups&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Memory = CPU:&lt;/strong&gt; more memory means more CPU. &lt;em&gt;Find the sweet spot where cost and performance balance.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialize outside the handler:&lt;/strong&gt; SDK clients, DB connections, config loading. &lt;em&gt;Reused across warm invocations.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda Destinations &amp;gt; DLQ:&lt;/strong&gt; Destinations capture success AND failure with more context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ReportBatchItemFailures&lt;/strong&gt; for SQS, &lt;strong&gt;BisectBatchOnFunctionError&lt;/strong&gt; for Kinesis to isolate bad records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC Lambda loses internet:&lt;/strong&gt; needs NAT Gateway or VPC endpoints for AWS services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RDS Proxy&lt;/strong&gt; for Lambda-to-RDS: manages connection pooling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layers:&lt;/strong&gt; up to 5 per function, 250 MB total unzipped, versioned and immutable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;15-minute timeout&lt;/strong&gt; is the max: for longer tasks, use Step Functions or ECS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provisioned concurrency:&lt;/strong&gt; eliminates cold starts but costs money when idle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kinesis parallelization factor"&lt;/strong&gt; (1–10) lets you process multiple batches per shard.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html" rel="noopener noreferrer"&gt;What Is AWS Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html" rel="noopener noreferrer"&gt;Using Lambda to process records from Amazon Kinesis Data Streams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-common.html" rel="noopener noreferrer"&gt;Configuring AWS Lambda functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html" rel="noopener noreferrer"&gt;Best practices for working with AWS Lambda functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html" rel="noopener noreferrer"&gt;Configuring reserved concurrency for a function&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🏗️&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloud</category>
      <category>developer</category>
    </item>
    <item>
      <title>Develop Code for Applications Hosted on AWS | 🏗️ Build An Order Processing System</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Mon, 04 May 2026 20:51:50 +0000</pubDate>
      <link>https://dev.to/aws-builders/develop-code-for-applications-hosted-on-aws-build-an-order-processing-system-38jc</link>
      <guid>https://dev.to/aws-builders/develop-code-for-applications-hosted-on-aws-build-an-order-processing-system-38jc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Exam Guide:&lt;/strong&gt; Developer - Associate&lt;br&gt;
&lt;strong&gt;🏗️ Domain 1:&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;Development with AWS Services&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
📘 &lt;strong&gt;Task 1:&lt;/strong&gt; &lt;em&gt;Develop Code for Applications Hosted on AWS&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the &lt;strong&gt;broadest&lt;/strong&gt; task on the exam. It tests whether you can build real applications on AWS. Not just use the console, but write code that interacts with AWS services, write code that handles failures gracefully, and write code that follows modern architectural patterns.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  📘Concepts
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Architectural Patterns
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Event-Driven&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Event-Driven&lt;/strong&gt; Components communicate through events. A producer emits an event, and one or more consumers react to it. There is no direct coupling between the producer and the consumer. &lt;br&gt;
&lt;strong&gt;AWS Services:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EventBridge&lt;/li&gt;
&lt;li&gt;SNS &lt;/li&gt;
&lt;li&gt;SQS &lt;/li&gt;
&lt;li&gt;Kinesis&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Microservices&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In &lt;strong&gt;Microservices&lt;/strong&gt; Architecture, the application is split into small, independently deployable services. Each service owns its data and communicates via APIs or events.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Monolithic&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;A &lt;strong&gt;Monolithic&lt;/strong&gt; Application is a single deployable unit. Even though it is simpler to start with, it is much harder to scale independently. Knowing when and even how to migrate from Monolithic Applications to Microservices Architecture is a must.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Choreography vs Orchestration&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choreography:&lt;/strong&gt; Each service knows what to do when it receives an event. No central coordinator. Uses EventBridge or SNS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; A central coordinator such as Step Functions manages the workflow and tells each service what to do.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Fanout&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In a &lt;strong&gt;Fanout&lt;/strong&gt; Pattern, one event triggers multiple consumers in parallel whereas the classic pattern consists of an SNS topic with multiple SQS queue subscriptions, or EventBridge with multiple rule targets.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stateful vs Stateless
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Aspect&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Stateful&lt;/th&gt;
&lt;th&gt;Stateless&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Session Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stored locally (memory/disk)&lt;/td&gt;
&lt;td&gt;Externalized (DynamoDB, ElastiCache)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard to scale horizontally&lt;/td&gt;
&lt;td&gt;Easy to scale horizontally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failure Impact&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Session data lost on crash&lt;/td&gt;
&lt;td&gt;No data loss, any instance can serve any request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not possible (ephemeral by design)&lt;/td&gt;
&lt;td&gt;Default behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lambda functions are stateless by design. If you need state, externalize it to DynamoDB, ElastiCache, or S3.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Tightly Coupled vs Loosely Coupled
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Aspect&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Tightly Coupled&lt;/th&gt;
&lt;th&gt;Loosely Coupled&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Communication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct API calls&lt;/td&gt;
&lt;td&gt;Queues, events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failure Impact&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cascading failures&lt;/td&gt;
&lt;td&gt;Isolated failures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scale together&lt;/td&gt;
&lt;td&gt;Scale independently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Pattern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Synchronous Lambda-to-Lambda&lt;/td&gt;
&lt;td&gt;Lambda → SQS → Lambda&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If a scenario describes a system where one component's failure brings down others, the answer usually involves adding a queue &lt;em&gt;(SQS)&lt;/em&gt; or event bus &lt;em&gt;(EventBridge)&lt;/em&gt; between them.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Synchronous vs Asynchronous
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Synchronous&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Caller waits for a response. &lt;br&gt;
&lt;em&gt;API Gateway → Lambda&lt;/em&gt; is &lt;strong&gt;synchronous.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Asynchronous&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Caller sends a message and moves on. &lt;br&gt;
&lt;em&gt;S3 event → Lambda&lt;/em&gt; is &lt;strong&gt;asynchronous.&lt;/strong&gt; &lt;br&gt;
&lt;em&gt;SQS → Lambda&lt;/em&gt; is &lt;strong&gt;asynchronous.&lt;/strong&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="c1"&gt;# Synchronous: Caller Waits
&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;lambda_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;FunctionName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-function&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InvocationType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RequestResponse&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;  &lt;span class="c1"&gt;# synchronous
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Asynchronous: Fire &amp;amp; Forget
&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;lambda_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;FunctionName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-function&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InvocationType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Event&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;  &lt;span class="c1"&gt;# asynchronous
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Messaging Services Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Pattern&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Point-to-point queue&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Decoupling, one consumer, buffering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SNS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Pub/sub fanout&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;One message to many subscribers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EventBridge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Event bus with routing&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Complex routing, content-based filtering, cross-account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kinesis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Real-time streaming&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;High-throughput ordered data (clickstreams, IoT, logs)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;SQS long polling&lt;/strong&gt; (&lt;code&gt;WaitTimeSeconds &amp;gt; 0&lt;/code&gt;) reduces empty responses and costs. Always use it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Resilient Code Patterns
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Exponential Backoff with Jitter&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When a request to another service fails, retrying immediately often makes things worse.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Exponential Backoff&lt;/strong&gt; Algorithm increases the wait time after each failed attempt (for example: &lt;code&gt;1s → 2s → 4s → 8s&lt;/code&gt;). This gives the failing system time to recover instead of being overwhelmed by repeated traffic.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Jitter&lt;/strong&gt; adds randomness to the wait time so multiple clients don’t retry at the exact same moment. Without it, many clients can retry together and create a &lt;strong&gt;thundering herd problem&lt;/strong&gt;, overwhelming the service again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Exponential Backoff Matters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduces pressure on struggling services
&lt;/li&gt;
&lt;li&gt;Improves recovery success rates
&lt;/li&gt;
&lt;li&gt;Prevents retry storms
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Circuit Breaker&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;A &lt;strong&gt;Circuit Breaker&lt;/strong&gt; protects your application from repeatedly calling a service that is already failing.&lt;/p&gt;

&lt;p&gt;After a defined number of consecutive failures (for example, &lt;code&gt;5&lt;/code&gt; failed requests), the circuit &lt;strong&gt;opens&lt;/strong&gt; and temporarily blocks new requests to that service for a cooldown period.&lt;/p&gt;

&lt;p&gt;After the cooldown, the system allows a few test requests (&lt;strong&gt;half-open state&lt;/strong&gt;) to check if the service has recovered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If successful:&lt;/strong&gt; the circuit closes and normal traffic resumes
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If failures continue:&lt;/strong&gt;, the circuit stays open
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as &lt;strong&gt;failing fast&lt;/strong&gt; instead of &lt;em&gt;failing repeatedly.&lt;/em&gt; A rare act of discipline in software engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Circuit Breakers Matter:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevents wasted resources
&lt;/li&gt;
&lt;li&gt;Avoids cascading failures
&lt;/li&gt;
&lt;li&gt;Helps systems recover faster
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Idempotency&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;An operation is &lt;strong&gt;Idempotent&lt;/strong&gt; if performing it multiple times produces the same result as performing it once.&lt;/p&gt;

&lt;p&gt;This is important in distributed systems because retries can happen due to timeouts, network failures, or duplicate messages.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updating a user’s email to the same value multiple times &lt;em&gt;is safe.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Creating the same order multiple times &lt;strong&gt;is dangerous&lt;/strong&gt; unless protected
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Idempotency is often implemented using:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Unique request IDs&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Deduplication checks&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Database constraints &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Idempotency Matters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes retries safe
&lt;/li&gt;
&lt;li&gt;Prevents duplicate side effects
&lt;/li&gt;
&lt;li&gt;Improves consistency in unreliable systems
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🏗️ Build An Order Processing System
&lt;/h2&gt;

&lt;p&gt;Now let's put these concepts into practice by building an &lt;strong&gt;Order Processing System&lt;/strong&gt; from scratch using the AWS Console:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An API Gateway REST API that accepts orders&lt;/li&gt;
&lt;li&gt;A Lambda function that publishes order events&lt;/li&gt;
&lt;li&gt;An EventBridge custom event bus that routes events&lt;/li&gt;
&lt;li&gt;Two consumer Lambda functions (order processing + inventory)&lt;/li&gt;
&lt;li&gt;An SQS queue for decoupling&lt;/li&gt;
&lt;li&gt;Request validation on the API&lt;/li&gt;
&lt;li&gt;Error handling with retry logic&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This covers the key skills for this task: architectural patterns, loose coupling, event-driven design, APIs, messaging, and resilient code.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ntombizakhona.medium.com/amazon-web-services-a8e57a9c6084" rel="noopener noreferrer"&gt;&lt;strong&gt;An AWS account&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;(free tier covers everything here)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Web Browser&lt;/strong&gt; &lt;em&gt;(we're doing this entirely in the console)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ntombizakhona.medium.com/python-in-the-cloud-1462f61e3293" rel="noopener noreferrer"&gt;&lt;strong&gt;Basic familiarity with Python&lt;/strong&gt;&lt;/a&gt; &lt;em&gt;(we'll use Python 3.12 for Lambda)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Part I
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Understanding the Architecture
&lt;/h3&gt;

&lt;p&gt;Before we build, let's understand what we're building and why.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client (POST /orders)
    │
    ▼
API Gateway (validates request)
    │
    ▼
PublishOrder Lambda (publishes event)
    │
    ▼
EventBridge (custom event bus: "orders")
    │
    ├──► Rule: "OrderPlaced" ──► ProcessOrder Lambda
    │
    └──► Rule: "OrderPlaced" ──► SQS Queue ──► UpdateInventory Lambda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Why This Architecture?&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt; validates requests before they reach your code which saves compute costs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge&lt;/strong&gt; decouples the publisher from consumers because the publisher doesn't know or care who's listening&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQS&lt;/strong&gt; between EventBridge and the inventory function adds durability so if inventory processing fails, the message stays in the queue&lt;/li&gt;
&lt;li&gt;Each component can &lt;strong&gt;scale independently&lt;/strong&gt; and &lt;strong&gt;fail independently&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This is a &lt;strong&gt;loosely coupled, event-driven, asynchronous&lt;/strong&gt; architecture &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Exam Concepts Demonstrated&lt;/strong&gt;
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Concept&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Where You'll See It&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event-Driven Pattern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;EventBridge routing events to consumers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fanout Pattern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One event triggers two different consumers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Loose Coupling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Publisher doesn't know about consumers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Async Processing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;EventBridge + SQS = fire and forget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Choreography&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each service reacts to events independently (no central orchestrator)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Request Validation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;API Gateway validates before Lambda runs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Part II
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Create the EventBridge Custom Event Bus&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We start with the event bus because it's the backbone of our system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;Amazon EventBridge&lt;/strong&gt; console&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; In the left sidebar under &lt;strong&gt;▼ Buses&lt;/strong&gt;, click &lt;strong&gt;Event buses&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Click &lt;strong&gt;Create event bus&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; &lt;strong&gt;Create event bus&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;orders&lt;/code&gt;&lt;br&gt;
Click &lt;strong&gt;Create&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created event bus orders.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You now have a custom event bus called &lt;code&gt;orders&lt;/code&gt;. AWS services publish to the &lt;code&gt;default&lt;/code&gt; bus and your application events go to your custom bus.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;default&lt;/code&gt; event bus receives events from AWS services (EC2 state changes, etc.). Custom event buses are for your application events. You can have rules on both.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Part III
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Create the Order Processing Lambda Functions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We need three Lambda functions. Let's create them one at a time.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Function 1&lt;/strong&gt; | Create the PublishOrder Function
&lt;/h4&gt;

&lt;p&gt;This function receives the API request and publishes an event to EventBridge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;Lambda&lt;/strong&gt; console &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;Create function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; &lt;strong&gt;Create function&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Author from scratch&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; &lt;code&gt;PublishOrder&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; &lt;code&gt;Python 3.12&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Create function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created the function "PublishOrder".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Paste this code into the code editor:&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;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;

&lt;span class="n"&gt;eventbridge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;events&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Receives an order from API Gateway and publishes it to EventBridge.
    This function doesn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t process the order — it just routes it.
    That&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the event-driven pattern: publish and forget.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Parse the request body from API Gateway
&lt;/span&gt;        &lt;span class="n"&gt;body&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;event&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="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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())[:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Publish the event to our custom event bus
&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;eventbridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="o"&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;Source&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;orders.api&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;DetailType&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;OrderPlaced&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;Detail&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;orderId&lt;/span&gt;&lt;span class="sh"&gt;'&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;ORD-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&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;customerId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customerId&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;items&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;items&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;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&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;EventBusName&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;orders&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="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Check if the event was published successfully
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FailedEntryCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&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;Failed to publish event: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Entries&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&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;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;error&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;Failed to process order&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="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;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# 202 Accepted — order is being processed async
&lt;/span&gt;            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;message&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;Order accepted for processing&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;orderId&lt;/span&gt;&lt;span class="sh"&gt;'&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;ORD-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&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="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;error&lt;/span&gt;&lt;span class="sh"&gt;'&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;Missing required field: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;Unexpected error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;error&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;Internal server error&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "PublishOrder".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Important:&lt;/strong&gt; This function needs permission to publish to EventBridge. Let's add that:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Go to the &lt;strong&gt;Configuration&lt;/strong&gt; tab → &lt;strong&gt;Permissions&lt;/strong&gt;&lt;br&gt;
Click the &lt;strong&gt;Role name&lt;/strong&gt; link (opens IAM in a new tab)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; &lt;strong&gt;PublishOrder-role-nx91xx0d&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Add permissions ▼&lt;/strong&gt; → &lt;strong&gt;Attach policies&lt;/strong&gt;&lt;br&gt;
Search for &lt;code&gt;AmazonEventBridgeFullAccess&lt;/code&gt; and attach it&lt;br&gt;
Click &lt;strong&gt;Add permissions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Policy was successfully attached to role&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In production, you'd create a scoped policy that only allows &lt;code&gt;events:PutEvents&lt;/code&gt; on the &lt;code&gt;orders&lt;/code&gt; bus. For this tutorial, the full access policy keeps things simple.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Function 2&lt;/strong&gt; | Create the ProcessOrder Function
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 08: Navigate to **Lambda&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Create function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 09:&lt;/strong&gt; &lt;strong&gt;Create function&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Author from scratch&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; &lt;code&gt;ProcessOrder&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; Python 3.12
Click &lt;strong&gt;Create function&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created the function "ProcessOrder"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 10:&lt;/strong&gt; Paste this code into the code editor:&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Processes an order after receiving it from EventBridge.
    In a real app, this would save to a database, charge payment, etc.

    Notice: this function has NO idea who published the event.
    It just reacts to OrderPlaced events. That&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s loose coupling.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;detail&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;detail&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="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;orderId&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customerId&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;items&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="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;=== Processing Order ===&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;Order ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&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;Customer: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="si"&gt;}&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;Items: &lt;/span&gt;&lt;span class="si"&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;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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;Total items: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Simulate order processing
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&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;  Processing: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;productId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; x &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;quantity&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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;=== Order &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; processed successfully ===&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;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;orderId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&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;processed&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 11:&lt;/strong&gt; Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "ProcessOrder".&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Function 3&lt;/strong&gt; | Create the UpdateInventory Function
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 12:&lt;/strong&gt; Create another function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Function name:&lt;/strong&gt; &lt;code&gt;UpdateInventory&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime:&lt;/strong&gt; Python 3.12
&lt;strong&gt;✅Green banner:&lt;/strong&gt; 
Successfully created the function "UpdateInventory".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 13:&lt;/strong&gt; Paste this code:&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Updates inventory based on order events.
    This function receives messages from SQS (not directly from EventBridge).
    The SQS queue adds durability — if this function fails, the message
    stays in the queue and gets retried.

    SQS event structure is different from EventBridge:
    - event[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Records&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;] contains an array of SQS messages
    - Each message body contains the EventBridge event
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;batch_failures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Records&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="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# SQS wraps the EventBridge event in the message body
&lt;/span&gt;            &lt;span class="n"&gt;message_body&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;record&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="c1"&gt;# EventBridge puts the actual event data in 'detail'
&lt;/span&gt;            &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message_body&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;detail&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="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;orderId&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;items&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="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;=== Updating Inventory for Order &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;productId&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;unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;quantity&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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;  Reducing stock: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; by &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; units&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;=== Inventory updated for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;Failed to process record: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# Report this specific message as failed
&lt;/span&gt;            &lt;span class="c1"&gt;# Only this message will be retried, not the whole batch
&lt;/span&gt;            &lt;span class="n"&gt;batch_failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;itemIdentifier&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;messageId&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;# Return partial batch failures so only failed messages retry
&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;batchItemFailures&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;batch_failures&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 14:&lt;/strong&gt; Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "UpdateInventory".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Notice the &lt;code&gt;batchItemFailures&lt;/code&gt; return. This is the **ReportBatchItemFailures&lt;/strong&gt; pattern. Without it, if one message in a batch of 10 fails, all 10 go back to the queue. With it, only the failed message retries.**&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part IV
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Create the SQS Queue&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;We'll put an SQS queue between EventBridge and the UpdateInventory function. This adds durability so if the function fails, the message stays in the queue.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;SQS&lt;/strong&gt; console &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;Create queue&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Create queue&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; &lt;code&gt;Standard&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;inventory-updates&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scroll to &lt;strong&gt;Access policy&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Advanced&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Replace the policy with this (update your account ID):
&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="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;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowEventBridge"&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;"Principal"&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;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"events.amazonaws.com"&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;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sqs:SendMessage"&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:sqs:us-east-1:YOUR_ACCOUNT_ID:inventory-updates"&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Replace &lt;code&gt;YOUR_ACCOUNT_ID&lt;/code&gt; with your actual AWS account ID and &lt;code&gt;us-east-1&lt;/code&gt; with your region.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Click &lt;strong&gt;Create queue&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Queue inventory-updates created successfully&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Copy the &lt;strong&gt;Queue ARN&lt;/strong&gt;. You'll need it for the EventBridge rule&lt;/p&gt;

&lt;h4&gt;
  
  
  Add SQS Permissions to the UpdateInventory Lambda Role
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Before connecting the trigger, the Lambda function needs permission to read from SQS. Without this, you'll get: &lt;em&gt;"The function execution role does not have permissions to call ReceiveMessage on SQS."&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Go to the &lt;strong&gt;Lambda&lt;/strong&gt; console &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; Open the &lt;strong&gt;UpdateInventory&lt;/strong&gt; function&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 08&lt;/strong&gt; Click the &lt;strong&gt;Configuration&lt;/strong&gt; tab &lt;br&gt;
Select &lt;strong&gt;Permissions&lt;/strong&gt;&lt;br&gt;
Click the &lt;strong&gt;Role name&lt;/strong&gt; link (opens IAM in a new tab)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 09:&lt;/strong&gt; &lt;strong&gt;PublishOrder-role-nx91xx0d&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Add permissions ▼&lt;/strong&gt; → &lt;strong&gt;Attach policies&lt;/strong&gt;&lt;br&gt;
Search for &lt;code&gt;AWSLambdaSQSQueueExecutionRole&lt;/code&gt; and attach it&lt;br&gt;
Click &lt;strong&gt;Add permissions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Policy was successfully attached to role&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This policy grants &lt;code&gt;sqs:ReceiveMessage&lt;/code&gt;, &lt;code&gt;sqs:DeleteMessage&lt;/code&gt;, and &lt;code&gt;sqs:GetQueueAttributes&lt;/code&gt; which is exactly what Lambda needs to poll the queue.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why does Lambda need these permissions?&lt;/strong&gt; When you use SQS as a Lambda trigger, Lambda itself polls the queue on your behalf using your function's execution role. It calls &lt;code&gt;ReceiveMessage&lt;/code&gt; to get messages, invokes your function, and then calls &lt;code&gt;DeleteMessage&lt;/code&gt; after successful processing. Without these permissions, Lambda can't even start polling.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Connect SQS to the UpdateInventory Lambda
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 10:&lt;/strong&gt; Go back to the &lt;strong&gt;Lambda&lt;/strong&gt; console&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 11:&lt;/strong&gt; Open the &lt;strong&gt;UpdateInventory&lt;/strong&gt; function&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 12:&lt;/strong&gt; Click &lt;strong&gt;Add trigger&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 13:&lt;/strong&gt; &lt;strong&gt;Select a source ▼&lt;/strong&gt;&lt;br&gt;
Select &lt;strong&gt;SQS&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;SQS Queue:&lt;/strong&gt; &lt;code&gt;inventory-updates&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Batch size - &lt;em&gt;optional&lt;/em&gt;:&lt;/strong&gt; &lt;code&gt;5&lt;/code&gt;&lt;br&gt;
Check &lt;strong&gt;✔ Report batch item failures&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Add&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;✅Green banner:&lt;/strong&gt; The trigger inventory-updates was successfully added to function UpdateInventory.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part V
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Create EventBridge Rules&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now we connect everything by creating rules that route events to our consumers.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Rule 1&lt;/strong&gt; | Route to ProcessOrder Lambda
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;EventBridge&lt;/strong&gt; console&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; In the left sidebar under &lt;strong&gt;▼ Buses&lt;/strong&gt;, Click &lt;strong&gt;Rules&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;Builder mode:&lt;/strong&gt; &lt;code&gt;Advanced builder&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;route-to-process-order&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; &lt;code&gt;Routes OrderPlaced events to the ProcessOrder function&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event bus:&lt;/strong&gt; orders
Click &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Build event pattern&lt;br&gt;
&lt;strong&gt;Event source:&lt;/strong&gt; &lt;code&gt;AWS events or Eventbridge partner events&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Event pattern:&lt;/strong&gt; &lt;code&gt;Custom pattern (JSON editor)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&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;"orders.api"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail-type"&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;"OrderPlaced"&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;blockquote&gt;
&lt;p&gt;This pattern matches any event where the source is &lt;code&gt;orders.api&lt;/code&gt; AND the detail-type is &lt;code&gt;OrderPlaced&lt;/code&gt;. EventBridge content-based filtering is powerful — you can match on nested fields, numeric ranges, prefixes, and more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Select target(s)&lt;br&gt;
&lt;strong&gt;Target types:&lt;/strong&gt; &lt;code&gt;AWS service&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Select a target:&lt;/strong&gt; &lt;code&gt;Lambda function&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Target location:&lt;/strong&gt; &lt;code&gt;Target in this account&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Function:&lt;/strong&gt; &lt;code&gt;ProcessOrder&lt;/code&gt;&lt;br&gt;
Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; &lt;strong&gt;Configure tags - &lt;em&gt;optional&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; &lt;strong&gt;Review and create&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Create rule&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Rule route-to-process-order was created successfully&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Rule 2&lt;/strong&gt; | Route to SQS Queue (for Inventory)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; Click &lt;strong&gt;Create rule&lt;/strong&gt; again&lt;br&gt;
&lt;strong&gt;Builder mode:&lt;/strong&gt; &lt;code&gt;Advanced builder&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;route-to-inventory-queue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; &lt;code&gt;Routes OrderPlaced events to the inventory SQS queue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event bus:&lt;/strong&gt; &lt;code&gt;orders&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 08:&lt;/strong&gt; Build event pattern&lt;br&gt;
&lt;strong&gt;Event source:&lt;/strong&gt; &lt;code&gt;AWS events or Eventbridge partner events&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Event pattern:&lt;/strong&gt; &lt;code&gt;Custom pattern (JSON editor)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&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;"orders.api"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail-type"&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;"OrderPlaced"&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;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 09:&lt;/strong&gt; Select target(s)&lt;br&gt;
&lt;strong&gt;Target types:&lt;/strong&gt; &lt;code&gt;AWS service&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Select a target:&lt;/strong&gt; &lt;code&gt;SQS queue&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Target location:&lt;/strong&gt; &lt;code&gt;Target in this account&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Queue:&lt;/strong&gt; &lt;code&gt;inventory-updates&lt;/code&gt;&lt;br&gt;
Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 10:&lt;/strong&gt; &lt;strong&gt;Configure tags - &lt;em&gt;optional&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 11:&lt;/strong&gt; &lt;strong&gt;Review and create&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Create rule&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Rule route-to-inventory-queue was created successfully&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You now have the &lt;em&gt;fanout pattern&lt;/em&gt;: one event, two consumers, each doing their own thing independently.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Part VI
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create the API Gateway REST API
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Create the API&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;API Gateway&lt;/strong&gt; console &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Click &lt;strong&gt;Create API&lt;/strong&gt;&lt;br&gt;
Under &lt;strong&gt;REST API&lt;/strong&gt;, click &lt;strong&gt;Build&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; &lt;strong&gt;Create REST API&lt;/strong&gt;&lt;br&gt;
Select &lt;strong&gt;New API&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API name:&lt;/strong&gt; &lt;code&gt;OrdersAPI&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; &lt;code&gt;Order processing API&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API endpoint type:&lt;/strong&gt; &lt;code&gt;Regional ▼&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security policy - &lt;em&gt;new&lt;/em&gt;:&lt;/strong&gt; &lt;code&gt;TLS_1_0&lt;/code&gt;
Click &lt;strong&gt;Create API&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created REST API 'OrdersAPI (5bmhxxqtp7)'.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 04:&lt;/strong&gt; Create the /orders Resource&lt;br&gt;
Click &lt;strong&gt;Create resource&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Resource path ▼:&lt;/strong&gt; &lt;code&gt;/&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Resource name:&lt;/strong&gt; &lt;code&gt;orders&lt;/code&gt;&lt;br&gt;
✔ CORS (Cross Origin Resource Sharing)&lt;br&gt;
Click &lt;strong&gt;Create resource&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created resource '/orders'&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 05:&lt;/strong&gt; Create the POST Method&lt;br&gt;
Select the &lt;code&gt;/orders&lt;/code&gt; resource&lt;br&gt;
Click &lt;strong&gt;Create method&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 06:&lt;/strong&gt; Create method&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method type:&lt;/strong&gt; &lt;code&gt;POST ▼&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration type:&lt;/strong&gt; &lt;code&gt;Lambda Function&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda proxy integration:&lt;/strong&gt; ✅ enabled&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda function:&lt;/strong&gt; select &lt;code&gt;PublishOrder&lt;/code&gt;
Click &lt;strong&gt;Create method&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created method 'POST' in 'orders'. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 07:&lt;/strong&gt; Add Request Validation&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;API Gateway can validate requests before they reach Lambda, saving compute costs.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 08:&lt;/strong&gt; In the left sidebar under &lt;strong&gt;API:OrdersAPI ▼&lt;/strong&gt;, click &lt;strong&gt;Models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 09:&lt;/strong&gt; Click &lt;strong&gt;Create model&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;CreateOrderModel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content type:&lt;/strong&gt; &lt;code&gt;application/json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model schema:&lt;/strong&gt;
&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://json-schema.org/draft-04/schema#"&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;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&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;"customerId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&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;"customerId"&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;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"minLength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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;"items"&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;"array"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"minItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"items"&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;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&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;"productId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&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;"productId"&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;"string"&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;"quantity"&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;"integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"minimum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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="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&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created model 'CreateOrderModel'.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 10:&lt;/strong&gt; Now attach the validator to the POST method&lt;br&gt;
Go back to &lt;strong&gt;Resources&lt;/strong&gt; → select the &lt;strong&gt;POST&lt;/strong&gt; method under &lt;code&gt;/orders&lt;/code&gt;&lt;br&gt;
Click on the &lt;strong&gt;Method request&lt;/strong&gt; tab&lt;br&gt;
Click &lt;strong&gt;Edit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 11:&lt;/strong&gt; &lt;strong&gt;Edit method request&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Authorization:&lt;/strong&gt; &lt;code&gt;none&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Request validator:&lt;/strong&gt; &lt;code&gt;Validate body&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;▶ Request body:&lt;/strong&gt; click &lt;strong&gt;Add model&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Content type: &lt;code&gt;application/json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Model: &lt;code&gt;CreateOrderModel&lt;/code&gt;
Click &lt;strong&gt;Save&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully edited method request for ‘POST’. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 12:&lt;/strong&gt; Deploy the API&lt;br&gt;
Click &lt;strong&gt;Deploy API&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Stage:&lt;/strong&gt; Create a new stage called &lt;code&gt;dev&lt;/code&gt;&lt;br&gt;
Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully created deployment for OrdersAPI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 13:&lt;/strong&gt; Copy the &lt;strong&gt;Invoke URL&lt;/strong&gt; it looks like: &lt;code&gt;https://abc123.execute-api.us-east-1.amazonaws.com/dev&lt;/code&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Part VII
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Test the Entire Flow
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Test 1&lt;/strong&gt; | Valid Order
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open a terminal (or use an API testing tool like Postman) and send a valid order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://YOUR_API_URL/dev/orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "customerId": "CUST-001",
    "items": [
      {"productId": "LAPTOP-001", "quantity": 1},
      {"productId": "MOUSE-002", "quantity": 2}
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order accepted for processing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"orderId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ORD-A1B2C3D4"&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;
  
  
  Verify The Events Flowed Through:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Go to &lt;strong&gt;Lambda&lt;/strong&gt; → &lt;strong&gt;ProcessOrder&lt;/strong&gt; → &lt;strong&gt;Monitor&lt;/strong&gt; tab → &lt;strong&gt;View CloudWatch logs&lt;/strong&gt; →  Click on the &lt;strong&gt;Log stream&lt;/strong&gt;&lt;br&gt;
You should see logs like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   === Processing Order ===
   Order ID: ORD-A1B2C3D4
   Customer: CUST-001
   Items: [{"productId": "LAPTOP-001", "quantity": 1}, ...]
   === Order ORD-A1B2C3D4 processed successfully ===
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 03:&lt;/strong&gt; Go to &lt;strong&gt;Lambda&lt;/strong&gt; → &lt;strong&gt;UpdateInventory&lt;/strong&gt; → &lt;strong&gt;Monitor&lt;/strong&gt; tab → &lt;strong&gt;View CloudWatch logs&lt;/strong&gt; →  Click on the &lt;strong&gt;Log stream&lt;/strong&gt;&lt;br&gt;
You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   === Updating Inventory for Order ORD-A1B2C3D4 ===
     Reducing stock: LAPTOP-001 by 1 units
     Reducing stock: MOUSE-002 by 2 units
   === Inventory updated for ORD-A1B2C3D4 ===
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One API call triggered two independent consumers. That's the fanout pattern in action.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Test 2&lt;/strong&gt; | Invalid Request (Missing customerID)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://YOUR_API_URL/dev/orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "items": [{"productId": "LAPTOP-001", "quantity": 1}]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invalid request body"&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;API Gateway rejected this request &lt;em&gt;before it reached Lambda&lt;/em&gt;. &lt;br&gt;
Your function was never invoked. That's the value of request validation. It saves compute costs and keeps your Lambda code cleaner.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Test 3&lt;/strong&gt; | Invalid Request (Missing quantity is 0)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://YOUR_API_URL/dev/orders &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "customerId": "CUST-001",
    "items": [{"productId": "LAPTOP-001", "quantity": 0}]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invalid request body"&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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This also gets rejected because our model requires &lt;code&gt;"minimum": 1&lt;/code&gt; for quantity.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part VII
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Add Resilient Code:&lt;/strong&gt; Retry Logic with Exponential Backoff
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;In real applications, your Lambda functions call external services that can fail temporarily. The exam tests whether you understand retry patterns.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Let's Update The &lt;code&gt;PublishOrder&lt;/code&gt; Function To Include Retry Logic For The EventBridge Call
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 01:&lt;/strong&gt; Open the &lt;strong&gt;PublishOrder&lt;/strong&gt; function in the Lambda console&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 02:&lt;/strong&gt; Replace the code with this updated version&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;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;

&lt;span class="n"&gt;eventbridge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;events&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retry_with_backoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_delay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Retry a function with exponential backoff and jitter.

    Why exponential backoff?
    - Constant retries can overwhelm a recovering service
    - Exponential delays give the service time to recover
    - Jitter prevents all clients from retrying at the same time (thundering herd)

    This pattern is tested on the DVA-C02 exam.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_retries&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;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;max_retries&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;All &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; attempts failed. Last error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;

            &lt;span class="c1"&gt;# Exponential backoff: 0.5s, 1s, 2s, 4s...
&lt;/span&gt;            &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_delay&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="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;# Add jitter: random value between 0 and the delay
&lt;/span&gt;            &lt;span class="n"&gt;jitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;wait_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;jitter&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;Attempt &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Retrying in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;wait_time&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s...&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="n"&gt;wait_time&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;body&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;event&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="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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())[:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;order_detail&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;orderId&lt;/span&gt;&lt;span class="sh"&gt;'&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;ORD-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&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;customerId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customerId&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;items&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;items&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;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# Use retry logic for the EventBridge call
&lt;/span&gt;        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;publish_event&lt;/span&gt;&lt;span class="p"&gt;():&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;eventbridge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;Entries&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;Source&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;orders.api&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;DetailType&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;OrderPlaced&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;Detail&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;order_detail&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;EventBusName&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;orders&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FailedEntryCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&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;EventBridge rejected the event: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Entries&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&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="n"&gt;response&lt;/span&gt;

        &lt;span class="nf"&gt;retry_with_backoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;publish_event&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;202&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;message&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;Order accepted for processing&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;orderId&lt;/span&gt;&lt;span class="sh"&gt;'&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;ORD-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&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="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;error&lt;/span&gt;&lt;span class="sh"&gt;'&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;Missing required field: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;Failed to publish order event: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&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;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&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;Content-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;application/json&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;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;error&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;Failed to process order. Please try again.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅Green banner:&lt;/strong&gt; Successfully updated the function "PublishOrder".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;strong&gt;The AWS SDK (boto3) already includes built-in retry logic for AWS API calls. But the exam tests whether you can implement retry logic for **third-party service calls&lt;/strong&gt; where you don't get automatic retries. Know the pattern: exponential backoff + jitter.**&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part IX
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Explore the Messaging Patterns
&lt;/h3&gt;

&lt;p&gt;Before we clean up, let's look at the SQS queue to understand the messaging flow.&lt;/p&gt;

&lt;h4&gt;
  
  
  View Messages in SQS
&lt;/h4&gt;

&lt;p&gt;Open the &lt;strong&gt;SQS&lt;/strong&gt; console&lt;br&gt;
Click on &lt;code&gt;inventory-updates&lt;/code&gt;&lt;br&gt;
Click &lt;strong&gt;Send and receive messages&lt;/strong&gt;&lt;br&gt;
Click &lt;strong&gt;Poll for messages&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If the UpdateInventory function processed everything, the queue should be empty. That's correct! SQS deletes messages after successful processing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Understanding Visibility Timeout
&lt;/h4&gt;

&lt;p&gt;When Lambda picks up a message from SQS:&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; The message becomes &lt;strong&gt;invisible&lt;/strong&gt; to other consumers (visibility timeout)&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Lambda processes it&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; If successful, Lambda &lt;strong&gt;deletes&lt;/strong&gt; the message&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; If Lambda fails, the message becomes &lt;strong&gt;visible&lt;/strong&gt; again after the timeout and gets retried&lt;/p&gt;

&lt;p&gt;You can see the visibility timeout in the queue settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the queue → &lt;strong&gt;Edit&lt;/strong&gt; → &lt;strong&gt;Visibility timeout&lt;/strong&gt; (default: 30 seconds)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Set the visibility timeout to &lt;em&gt;at least 6x your Lambda timeout&lt;/em&gt;. If your function takes 30 seconds and the visibility timeout is 30 seconds, a slow execution could cause duplicate processing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🏗️ What You Built | 📘Exam Concepts Recap
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;What You Did&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Exam Concept&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Created a custom EventBridge bus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Event-driven architecture&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;One event → two consumers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Fanout pattern&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Publisher doesn't know about consumers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Loose coupling&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;API Gateway validates before Lambda runs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;em&gt;Request validation&lt;/em&gt; (saves compute)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQS between EventBridge and Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Durability, async processing&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;batchItemFailures&lt;/code&gt; in UpdateInventory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Partial batch failure handling&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;retry_with_backoff&lt;/code&gt; in PublishOrder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Resilient code, exponential backoff + jitter&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTTP 202 response&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Asynchronous acceptance pattern&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Each function has its own role&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Least privilege, stateless design&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚠️ Clean Up Protocol
&lt;/h2&gt;

&lt;p&gt;To avoid charges, delete the resources in this order:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;strong&gt;API Gateway&lt;/strong&gt; → Delete the &lt;code&gt;OrdersAPI&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;strong&gt;Lambda&lt;/strong&gt; → Delete &lt;code&gt;PublishOrder&lt;/code&gt;, &lt;code&gt;ProcessOrder&lt;/code&gt;, &lt;code&gt;UpdateInventory&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;strong&gt;SQS&lt;/strong&gt; → Delete the &lt;code&gt;inventory-updates&lt;/code&gt; queue&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;strong&gt;EventBridge&lt;/strong&gt; → Delete both rules, then delete the &lt;code&gt;orders&lt;/code&gt; event bus&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; &lt;strong&gt;IAM&lt;/strong&gt; → Delete the Lambda execution roles (they start with &lt;code&gt;PublishOrder-role-&lt;/code&gt;, etc.)&lt;br&gt;
&lt;strong&gt;6.&lt;/strong&gt; &lt;strong&gt;CloudWatch&lt;/strong&gt; → Delete the log groups under &lt;code&gt;/aws/lambda/&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Loose coupling&lt;/strong&gt; is almost always the right answer. If components talk directly, add a queue or event bus between them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge&lt;/strong&gt; is the preferred service for event-driven architectures. It supports content-based filtering, multiple targets, and cross-account routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway request validation&lt;/strong&gt; happens before Lambda which saves compute costs. Know how to create models and attach validators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQS long polling&lt;/strong&gt; (&lt;code&gt;WaitTimeSeconds &amp;gt; 0&lt;/code&gt;) reduces empty responses and costs. Always use it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ReportBatchItemFailures:&lt;/strong&gt; without it, one failed message retries the entire batch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exponential backoff with jitter&lt;/strong&gt; is the standard retry pattern for third-party calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP 202 Accepted&lt;/strong&gt; signals that the request was accepted for async processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fanout&lt;/strong&gt; = SNS or EventBridge sending one event to multiple consumers.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html" rel="noopener noreferrer"&gt;Amazon EventBridge User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-method-request-validation.html" rel="noopener noreferrer"&gt;Request validation for REST APIs in API Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html" rel="noopener noreferrer"&gt;Using Lambda with Amazon SQS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html" rel="noopener noreferrer"&gt;Understanding retry behavior in Lambda&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;🏗️&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloud</category>
      <category>developer</category>
    </item>
    <item>
      <title>OpenClaw on AWS for Beginners: How To Build An AI Agent That Deploys Your WordPress Multisite in Minutes With Just Three Services</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Sun, 26 Apr 2026 23:07:34 +0000</pubDate>
      <link>https://dev.to/aws-builders/openclaw-on-aws-for-beginners-how-to-build-an-ai-agent-that-deploys-your-wordpress-multisite-in-abm</link>
      <guid>https://dev.to/aws-builders/openclaw-on-aws-for-beginners-how-to-build-an-ai-agent-that-deploys-your-wordpress-multisite-in-abm</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/openclaw-2026-04-16"&gt;OpenClaw Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Just Lightsail, IAM, and Route 53:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How My Agent Built My Site For Me In Minutes
&lt;/h3&gt;

&lt;p&gt;AWS has over &lt;strong&gt;200&lt;/strong&gt; services. &lt;br&gt;
I used &lt;strong&gt;&lt;em&gt;three.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No VPCs. &lt;br&gt;
No EC2 security groups. &lt;br&gt;
No CloudFormation templates. &lt;br&gt;
No Lambda functions. &lt;br&gt;
No S3 bucket policies. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Just Lightsail&lt;/strong&gt; to run things, &lt;strong&gt;IAM&lt;/strong&gt; to grant permissions, and &lt;strong&gt;Route 53&lt;/strong&gt; for DNS. &lt;/p&gt;

&lt;p&gt;That's the entire infrastructure for an AI Agent that builds WordPress Multisite installations and writes SEO blog content from scratch, in under 30 minutes, for people who've never touched a server.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is the story of how I built it with OpenClaw, and why staying in the shallow end of AWS was the whole point.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem I Wanted To Solve
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;The monotony of manual labor&lt;/em&gt;...&lt;/strong&gt; &lt;br&gt;
Setting up WordPress Multisite manually is a multi-hour ordeal even for developers. You SSH into a server, edit &lt;code&gt;wp-config.php&lt;/code&gt; by hand, hope you didn't miss a semicolon, configure Apache, set up a static IP, mess with DNS records, install SSL, restart services, Google the error, and try again.&lt;/p&gt;

&lt;p&gt;For a beginner? It's a wall. &lt;br&gt;
Most people give up somewhere between &lt;em&gt;"what's SSH?"&lt;/em&gt; and &lt;strong&gt;"Error establishing database connection."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I didn't want to write another tutorial that people would bookmark and never finish. I wanted to build an AI agent that does the whole thing for you step by step, in plain language, while explaining everything along the way. And I wanted it to run entirely &lt;strong&gt;in the cloud&lt;/strong&gt; &lt;em&gt;so beginners don't need to install anything on their computer.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Lightsail (and only Lightsail)
&lt;/h2&gt;

&lt;p&gt;Most AWS tutorials assume you're comfortable with the &lt;strong&gt;full ecosystem.&lt;/strong&gt; They'll casually tell you to "create a VPC with two subnets" or "configure a security group with the following inbound rules" as if that's a normal thing beginners do on a Sunday afternoon...even though it's quite simple, it's just too many services and a confusing dashboard.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lightsail&lt;/em&gt; exists specifically to avoid that. &lt;br&gt;
It's AWS for people who don't want to think about AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixed monthly pricing. &lt;/li&gt;
&lt;li&gt;Instances that just work. &lt;/li&gt;
&lt;li&gt;Networking that's already configured. &lt;/li&gt;
&lt;li&gt;A console that doesn't require a PhD to navigate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this project, Lightsail gave me everything I needed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An OpenClaw Instance:&lt;/strong&gt; AWS has an official OpenClaw blueprint. Click create, pick the blueprint, and you have a running AI gateway in two minutes. &lt;br&gt;
&lt;em&gt;No Docker, no environment variables, no dependency hell.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A WordPress Instance:&lt;/strong&gt; same deal. Bitnami WordPress blueprint. &lt;em&gt;Click, wait, done.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Static IPs:&lt;/strong&gt; free while attached to an instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Firewall Rules:&lt;/strong&gt; built into the instance management page. &lt;br&gt;
&lt;em&gt;No security group rabbit holes.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser-Based SSH:&lt;/strong&gt; click "Connect using SSH" and you're in. &lt;br&gt;
&lt;em&gt;No key management, no PuTTY, no terminal setup.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The only other AWS services I touched were &lt;strong&gt;IAM&lt;/strong&gt; (to grant the OpenClaw instance permission to create Lightsail resources and use Bedrock) and &lt;strong&gt;Route 53&lt;/strong&gt; (for DNS, and only if you want a custom domain). &lt;br&gt;
That's it. &lt;br&gt;
&lt;strong&gt;Three services.&lt;/strong&gt; &lt;br&gt;
The rest of AWS might as well not exist for this project.&lt;/p&gt;


&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;An OpenClaw agent with two skills:&lt;/p&gt;
&lt;h3&gt;
  
  
  Skill 1
&lt;/h3&gt;
&lt;h4&gt;
  
  
  WordPress Multisite Builder
&lt;/h4&gt;

&lt;p&gt;An 8-phase guided workflow that walks beginners through creating a Lightsail instance, configuring WordPress, enabling multisite, setting up domains, and installing SSL. Uses browser automation to navigate the AWS console and SSH to configure the server.&lt;/p&gt;
&lt;h3&gt;
  
  
  Skill 2
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Blog Content Engine
&lt;/h4&gt;

&lt;p&gt;A 6-phase content generation system that researches what people are searching for in your niche, writes SEO-optimized blog posts, and publishes them directly to your WordPress site via WP-CLI.&lt;/p&gt;

&lt;p&gt;The whole thing runs on a Lightsail OpenClaw instance. &lt;br&gt;
No local install. &lt;br&gt;
You chat with the agent from a browser dashboard, Telegram, or WhatsApp, and it builds your website and writes your content.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Architecture
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You (browser / Telegram / WhatsApp)
    │
    ▼
Lightsail OpenClaw Instance (~$12/mo)
    │  Amazon Bedrock → Claude Opus 4.6
    │
    ├── browser tool ──► AWS Lightsail Console + WordPress Admin
    ├── exec tool ─────► SSH + WP-CLI on the WordPress server
    ├── web_search ────► Keyword research + trending topics
    ├── web_fetch ─────► Competitor analysis + content research
    └── file I/O ──────► Progress tracking, content calendar, posts
    │
    ▼
Lightsail WordPress Instance (~$12/mo)
    └── WordPress Multisite with auto-generated content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Two Lightsail instances. &lt;br&gt;
One IAM role. &lt;br&gt;
Optionally Route 53 for DNS.&lt;/p&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step By Step Guide
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Step 1:&lt;/strong&gt; &lt;em&gt;The OpenClaw Instance&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;I went to the Lightsail console, clicked "Create instance," picked the OpenClaw blueprint under Linux/Unix, selected the 2 GB plan (~$12/month), named it &lt;code&gt;WordPressAgent&lt;/code&gt;, and clicked Create. &lt;br&gt;
Two minutes later it was running.&lt;/p&gt;

&lt;p&gt;The pairing process was straightforward: click "Connect using SSH" to open a browser terminal, copy the dashboard URL and access token from the welcome message, paste the token into the dashboard, and approve the pairing prompts in the SSH terminal. Dashboard showed "OK." &lt;br&gt;
&lt;strong&gt;Connected.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Step 2:&lt;/strong&gt; &lt;em&gt;Enabling Bedrock&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;The Lightsail OpenClaw blueprint comes pre-configured to use Amazon Bedrock you just need to grant the permissions. On the instance's "Getting started" tab, there's a "Copy the script" button. I copied it, launched CloudShell, pasted, and ran it. The script creates an IAM role (&lt;code&gt;LightsailRoleFor-i-xxxxx&lt;/code&gt;) with Bedrock access.&lt;/p&gt;

&lt;p&gt;I tested it by typing "Hello" in the OpenClaw dashboard chat. Got a response. Bedrock was working.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Step 3:&lt;/strong&gt; &lt;em&gt;The IAM Permission That Made Everything Click&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Here's where I hit my first snag. The agent needed to create Lightsail resources (the WordPress instance, static IPs, etc.) but the IAM role only had Bedrock permissions. When I ran &lt;code&gt;aws lightsail get-instances&lt;/code&gt; from the SSH terminal, I got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;AccessDeniedException: User is not authorized to perform: lightsail:GetInstances
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix was simple: I went to the IAM console, found the &lt;code&gt;AmazonLightsailInstance&lt;/code&gt; role, clicked "Add permissions" → "Attach policies," searched for &lt;code&gt;AmazonLightsailFullAccess&lt;/code&gt;, and attached it.&lt;/p&gt;

&lt;p&gt;One policy. That's all it took. &lt;br&gt;
Lightsail is self-contained: instances, networking, DNS, snapshots, key pairs, everything is under one permission set. &lt;br&gt;
No cross-service IAM policies.&lt;br&gt;
No resource-based permissions.&lt;br&gt;
No condition keys. &lt;br&gt;
&lt;strong&gt;This is what makes Lightsail great for beginners:&lt;/strong&gt; &lt;em&gt;the permission model is as simple as the service itself.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Step 4:&lt;/strong&gt; &lt;em&gt;Escaping The Sandbox&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;The next issue: OpenClaw told me it was "running in a sandboxed environment" and couldn't execute commands on the host. By default, OpenClaw runs tools inside a Docker container for security. That's smart for untrusted inputs, but it blocks the agent from doing real work.&lt;/p&gt;

&lt;p&gt;Three config lines fixed it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;tools.exec.host gateway
openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;tools.exec.ask off
openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;tools.exec.security full
openclaw gateway restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells OpenClaw to run tools directly on the gateway host instead of in the sandbox. For a personal agent that only you control, this is the right tradeoff.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alternatively, you can give your agent permission to use your browser and run commands during the initial Security setup process.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 5:&lt;/strong&gt; &lt;em&gt;Building The Agent Workspace&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;OpenClaw agents are defined by markdown files in a workspace directory. No code, no SDK, no compilation. &lt;br&gt;
Just files that tell the agent who it is, how to behave, and what to do.&lt;/p&gt;

&lt;p&gt;I created five core files by pasting them directly into the SSH terminal using &lt;code&gt;cat &amp;gt; file &amp;lt;&amp;lt; 'ENDOFFILE'&lt;/code&gt; blocks. &lt;br&gt;
No git clone. &lt;br&gt;
No file transfers.&lt;br&gt;
No local tools needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IDENTITY.md&lt;/strong&gt; — defines who the agent is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;You are WP Multisite Builder + Content Engine, an AI assistant that helps
complete beginners:
&lt;span class="p"&gt;
1.&lt;/span&gt; Set up WordPress Multisite on Amazon Lightsail
&lt;span class="p"&gt;2.&lt;/span&gt; Research trending search topics and generate SEO-optimized blog posts
&lt;span class="p"&gt;3.&lt;/span&gt; Publish content directly to their WordPress sites
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;SOUL.md&lt;/strong&gt; — defines the personality and safety rules. This was important because the agent is aimed at beginners:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Personality&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Warm and encouraging, like a helpful friend who happens to know tech
&lt;span class="p"&gt;-&lt;/span&gt; Never condescending. If someone doesn't know what SSH means, that's fine
&lt;span class="p"&gt;-&lt;/span&gt; Celebrate small wins ("Nice, your instance is running!")

&lt;span class="gu"&gt;## Safety rules&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; NEVER proceed without user confirmation on actions that:
&lt;span class="p"&gt;  -&lt;/span&gt; Create or modify AWS resources (costs money)
&lt;span class="p"&gt;  -&lt;/span&gt; Change passwords or security settings
&lt;span class="p"&gt;  -&lt;/span&gt; Install software on their server
&lt;span class="p"&gt;  -&lt;/span&gt; Modify WordPress configuration
&lt;span class="p"&gt;-&lt;/span&gt; Always explain what something will cost before creating resources
&lt;span class="p"&gt;-&lt;/span&gt; Never store or display AWS credentials in chat history
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AGENTS.md&lt;/strong&gt; — the operating instructions and greeting message. When a user first connects, the agent says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hey! I can help you with two things: set up a WordPress website that can run multiple sites all on Amazon Lightsail, or write blog posts based on what people are actually searching for. We can do both, or just one. What sounds good?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;TOOLS.md&lt;/strong&gt; — a reference for which OpenClaw tools the agent uses: &lt;code&gt;browser&lt;/code&gt; for navigating the Lightsail console and WordPress admin, &lt;code&gt;exec&lt;/code&gt; for SSH and WP-CLI commands, &lt;code&gt;web_search&lt;/code&gt; and &lt;code&gt;web_fetch&lt;/code&gt; for keyword research and troubleshooting, and file I/O for saving progress.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 6:&lt;/strong&gt; &lt;em&gt;The WordPress Multisite Skill&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;This is the core of the project. I created &lt;code&gt;skills/wp-multisite-lightsail/SKILL.md&lt;/code&gt; — an 8-phase guided workflow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Pre-flight Checks.&lt;/strong&gt; Confirms the user has an AWS account and login ready. If not, walks them through creating one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Create a Lightsail Instance.&lt;/strong&gt; The agent opens the Lightsail console using the &lt;code&gt;browser&lt;/code&gt; tool, takes a snapshot of the page to identify clickable elements, and walks through instance creation: Linux/Unix platform, WordPress blueprint, $5/month plan. It stops and confirms the cost before clicking "Create instance," then waits for "Running" status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Get WordPress Credentials.&lt;/strong&gt; SSHs into the new instance and reads the default Bitnami password. Tells the user to write it down. Verifies WordPress loads in the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: Static IP.&lt;/strong&gt; Creates and attaches a free static IP so the address doesn't change on restart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 5: Enable Multisite.&lt;/strong&gt; This is the complex part that usually trips people up. The agent edits &lt;code&gt;wp-config.php&lt;/code&gt; via SSH to add &lt;code&gt;WP_ALLOW_MULTISITE&lt;/code&gt;, navigates to Tools → Network Setup in wp-admin via the browser, recommends subdirectories for beginners, applies the multisite configuration constants, updates &lt;code&gt;.htaccess&lt;/code&gt;, and restarts Apache. It makes a backup of &lt;code&gt;wp-config.php&lt;/code&gt; before any edits. But, it will choose the Multisite Instance from the get go, unless it doesn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 6: Domain Setup.&lt;/strong&gt; If the user has a domain, the agent guides them through DNS configuration at their registrar (using &lt;code&gt;web_search&lt;/code&gt; to find the right settings page for GoDaddy, Namecheap, Cloudflare, Route53 etc.) and updates WordPress via WP-CLI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 7: SSL certificate.&lt;/strong&gt; Runs Bitnami's &lt;code&gt;bncert-tool&lt;/code&gt; for free Let's Encrypt SSL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 8: Wrap-up.&lt;/strong&gt; Saves a summary with all URLs, login info, monthly costs, and next steps.&lt;/p&gt;

&lt;p&gt;The skill also includes error handling for every common failure such database connection errors, SSH failures, SSL issues, missing config entries. The agent searches the web for solutions when it hits something unexpected.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 7:&lt;/strong&gt; &lt;em&gt;The Content Engine Skill&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;After the site is built, the agent offers to generate blog content. I created &lt;code&gt;skills/blog-content-engine/SKILL.md&lt;/code&gt; with 6 phases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Keyword Research.&lt;/strong&gt; Asks the user their niche, then fires off multiple &lt;code&gt;web_search&lt;/code&gt; queries to find trending questions, "People Also Ask" data, long-tail keywords, and competitor content. Compiles 10-15 keyword opportunities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Content Planning.&lt;/strong&gt; Creates outlines with titles, meta descriptions, target keywords, H2 structure, and FAQ sections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Writing.&lt;/strong&gt; Generates 1,200-2,000 word SEO-optimized posts with proper heading structure, keyword placement, short paragraphs, and 8th-grade reading level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: Publishing.&lt;/strong&gt; Pushes to WordPress via WP-CLI (or browser fallback). For multisite, asks which subsite to target. Never auto-publishes without explicit approval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 5: Batch Generation.&lt;/strong&gt; Handles multiple posts with a content calendar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 6: Ongoing Suggestions.&lt;/strong&gt; Offers fresh trending topics each time the user comes back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Connecting Telegram and WhatsApp
&lt;/h3&gt;

&lt;p&gt;After everything was working in the dashboard, I connected messaging channels so I could manage the site from my phone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Telegram&lt;/strong&gt; took about three minutes: create a bot via &lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt; on Telegram, copy the bot token, run &lt;code&gt;openclaw channels add&lt;/code&gt; in SSH, select Telegram, paste the token. Then configure the allowlist with my numeric Telegram user ID (get it from @userinfobot) and approve the pairing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WhatsApp&lt;/strong&gt; was even simpler: run &lt;code&gt;openclaw channels add&lt;/code&gt;, select WhatsApp, scan the QR code with my phone's Linked Devices feature. Done.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now I can message my bot on Telegram or WhatsApp and say "write a blog post about beginner gardening tips" and it researches, writes, and publishes &lt;strong&gt;all from my phone.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Moment It All Worked
&lt;/h2&gt;

&lt;p&gt;I opened the OpenClaw dashboard, typed "Help me set up WordPress Multisite," and the agent greeted me. It asked if I had an AWS account. It opened the Lightsail console in its browser. &lt;/p&gt;

&lt;p&gt;It walked me through creating the instance, explaining every step. It confirmed the cost before clicking Create. It waited for the instance to boot. It SSHed in, grabbed the credentials, set up the static IP, edited the config files, enabled multisite, and verified everything worked.&lt;/p&gt;

&lt;p&gt;Under 30 minutes. The whole thing. An AI agent, running on Lightsail, building a WordPress Multisite on another Lightsail instance, using browser automation and SSH. And I never left the Lightsail console (plus one quick trip to IAM to attach a policy).&lt;/p&gt;




&lt;h2&gt;
  
  
  What OpenClaw Gets Right
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Skills Are Just Markdown.&lt;/strong&gt; Each skill is a &lt;code&gt;SKILL.md&lt;/code&gt; file with YAML frontmatter and instructions. No SDK, no compilation, no deployment pipeline. Write markdown, drop it in the workspace, restart the gateway. The agent picks it up on the next session. This is the right abstraction for teaching an agent how to do something complex.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser Automation Is Built In.&lt;/strong&gt; Most AI agents are limited to APIs and CLIs. OpenClaw's &lt;code&gt;browser&lt;/code&gt; tool controls an isolated Chromium instance: the agent can navigate web consoles, click buttons, fill forms, and take screenshots. That's a massive unlock for automating things that don't have an API, like the Lightsail console's instance creation wizard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Lightsail Blueprint Is A Cheat Code.&lt;/strong&gt; Going from zero to a running AI gateway in two minutes, with Bedrock pre-configured, HTTPS auto-managed, and daily token rotation...that's the kind of developer experience that makes you want to build things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-Channel Is Trivial.&lt;/strong&gt; Dashboard, Telegram, WhatsApp all connected in minutes. The agent doesn't care where the message comes from. Same skills, same personality, same workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Confirm Before Acting" Pattern Works.&lt;/strong&gt; My agent never creates resources or spends money without asking first. This isn't just good UX. It's the difference between a tool beginners trust and one they're afraid of.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned About Staying In The Shallow End
&lt;/h2&gt;

&lt;p&gt;The biggest lesson: &lt;strong&gt;you don't need the deep ocean of AWS to build real things.&lt;/strong&gt; The instinct is always to reach for EC2, VPCs, security groups, load balancers, auto-scaling groups. But for a personal AI agent running a WordPress site? &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lightsail does everything, and it does it without the cognitive overhead.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The permission model tells the story. I needed exactly two IAM policies: one for Bedrock (auto-created by the setup script) and &lt;code&gt;AmazonLightsailFullAccess&lt;/code&gt; (one click in the IAM console). Compare that to the typical EC2 setup where you're writing JSON policy documents with resource ARNs and condition keys.&lt;/p&gt;

&lt;p&gt;Route 53 was optional. Only needed if you want a custom domain. And even then, the agent handles the DNS configuration by guiding the user through their existing registrar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three services.&lt;/strong&gt; That's the whole stack. And it's not a toy. &lt;br&gt;
It's a production-capable AI agent that builds infrastructure, manages &lt;em&gt;servers, and generates content.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Everything is reproducible.&lt;/em&gt; You need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;An AWS account&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Lightsail OpenClaw instance&lt;/strong&gt; (2 GB plan, ~$12/month)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AmazonLightsailFullAccess&lt;/code&gt;&lt;/strong&gt; attached to the instance's IAM role&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The workspace files&lt;/strong&gt; pasted into &lt;code&gt;~/.openclaw/workspace/&lt;/code&gt; via SSH&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full deployment takes about 15 minutes. Here's the condensed version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# After creating the OpenClaw instance, pairing, and enabling Bedrock:&lt;/span&gt;

&lt;span class="c"&gt;# Create skill directories&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.openclaw/workspace/skills/wp-multisite-lightsail
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.openclaw/workspace/skills/blog-content-engine

&lt;span class="c"&gt;# Paste each workspace file (IDENTITY.md, SOUL.md, AGENTS.md, TOOLS.md,&lt;/span&gt;
&lt;span class="c"&gt;# and both SKILL.md files) using cat &amp;gt; file &amp;lt;&amp;lt; 'ENDOFFILE' blocks&lt;/span&gt;

&lt;span class="c"&gt;# Configure tool permissions&lt;/span&gt;
openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;tools.exec.host gateway
openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;tools.exec.ask off
openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;tools.exec.security full
openclaw gateway restart

&lt;span class="c"&gt;# Open the dashboard and type: "Help me set up WordPress Multisite"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No GitHub repo needed. &lt;br&gt;
No local install. &lt;br&gt;
No dependencies. &lt;br&gt;
Just an SSH terminal and some copy-paste.&lt;/p&gt;




&lt;h2&gt;
  
  
  The cost breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Monthly cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenClaw Lightsail instance (2 GB)&lt;/td&gt;
&lt;td&gt;~$12 (first 90 days free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WordPress Lightsail instance (2 GB)&lt;/td&gt;
&lt;td&gt;~$12 (first 90 days free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amazon Bedrock (Claude Opus 4.6)&lt;/td&gt;
&lt;td&gt;Pay per token&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static IPs&lt;/td&gt;
&lt;td&gt;Free (while attached)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL certificates&lt;/td&gt;
&lt;td&gt;Free (Let's Encrypt, auto-renews)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain name&lt;/td&gt;
&lt;td&gt;~$15/year (optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;About $25/month for the infrastructure, plus whatever Bedrock charges for the AI conversations. For a self-hosted AI agent that builds and manages WordPress sites and writes your blog content, that's a pretty good deal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where To Next?
&lt;/h2&gt;

&lt;p&gt;Well, the foundation is solid. Some things I'm thinking about, dependent on your use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More Skills:&lt;/strong&gt; WooCommerce setup, backup automation, security hardening, performance optimization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenant:&lt;/strong&gt; let the agent manage multiple WordPress Multisites for different clients if you're the entrepreneaurial sort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled Content:&lt;/strong&gt; use OpenClaw's cron tool to auto-research and draft posts on a schedule&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics Integration:&lt;/strong&gt; pull Google Analytics data to inform content strategy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The possibilities are endless!&lt;/em&gt;&lt;br&gt;
But honestly, the most exciting part is how accessible this is. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A beginner with an AWS account can have a working WordPress Multisite with AI-generated content in under an hour&lt;/strong&gt;. &lt;br&gt;
No terminal on their laptop. &lt;br&gt;
No config files on their desktop.&lt;br&gt;
No "install these 7 prerequisites first."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Just Lightsail, IAM, and Route 53.&lt;/strong&gt;&lt;br&gt;
The shallow end of AWS. &lt;br&gt;
And it's plenty deep enough.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with OpenClaw on Amazon Lightsail. Powered by Amazon Bedrock (Claude Opus 4.6). Three AWS services. Zero Local Installs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>openclawchallenge</category>
    </item>
    <item>
      <title>Developer Associate Exam Guide</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Fri, 24 Apr 2026 19:27:55 +0000</pubDate>
      <link>https://dev.to/aws-builders/developer-associate-exam-guide-56ln</link>
      <guid>https://dev.to/aws-builders/developer-associate-exam-guide-56ln</guid>
      <description>&lt;h2&gt;
  
  
  What Is the AWS Certified Developer – Associate?
&lt;/h2&gt;

&lt;p&gt;The AWS Certified Developer – Associate (DVA-C02) validates your ability to develop, test, deploy, and debug cloud-based applications using AWS. It's aimed at developers with at least one year of hands-on experience building and maintaining AWS applications.&lt;/p&gt;

&lt;p&gt;This isn't a theory-only exam. The questions are scenario-based. You'll be given a situation and asked to pick the best approach. &lt;/p&gt;

&lt;p&gt;That means you need to understand not just &lt;em&gt;what&lt;/em&gt; a service does, but &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt; to use it in real code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exam Format
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Exam code&lt;/td&gt;
&lt;td&gt;DVA-C02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Questions&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duration&lt;/td&gt;
&lt;td&gt;130 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Format&lt;/td&gt;
&lt;td&gt;Multiple choice + multiple select&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passing score&lt;/td&gt;
&lt;td&gt;720 / 1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$150 USD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validity&lt;/td&gt;
&lt;td&gt;3 years&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Multiple choice questions have one correct answer out of four. &lt;br&gt;
Multiple select questions tell you how many answers to pick (usually two out of five).&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Domains
&lt;/h2&gt;

&lt;p&gt;The exam is split into four domains, each with a different weight:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;Weight&lt;/th&gt;
&lt;th&gt;~Questions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Development with AWS Services&lt;/td&gt;
&lt;td&gt;32%&lt;/td&gt;
&lt;td&gt;~21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Security&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;td&gt;~17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Deployment&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;td&gt;~16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Troubleshooting and Optimization&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;td&gt;~11&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Development&lt;/strong&gt; is the biggest chunk, but &lt;strong&gt;Security&lt;/strong&gt; is close behind. &lt;br&gt;
Don't sleep on &lt;strong&gt;Deployment.&lt;/strong&gt;&lt;br&gt;
Nearly a quarter of the exam is CI/CD, IaC, and deployment strategies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Domain 1
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Development with AWS Services
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(32%)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the core of the exam. &lt;br&gt;
You need to write code that works with AWS services, not just click through the console.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 1.1 Develop code for applications hosted on AWS&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Architectural patterns: event-driven, microservices, fanout, choreography vs orchestration&lt;/li&gt;
&lt;li&gt;Stateful vs stateless, tightly vs loosely coupled, sync vs async&lt;/li&gt;
&lt;li&gt;Building and maintaining APIs with API Gateway&lt;/li&gt;
&lt;li&gt;Writing unit tests with SAM&lt;/li&gt;
&lt;li&gt;Using messaging services (SQS, SNS, EventBridge)&lt;/li&gt;
&lt;li&gt;Working with AWS SDKs&lt;/li&gt;
&lt;li&gt;Handling streaming data (Kinesis)&lt;/li&gt;
&lt;li&gt;Resilient code: retry logic, circuit breakers, error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 1.2: Develop code for AWS Lambda&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;VPC access from Lambda&lt;/li&gt;
&lt;li&gt;Configuration: memory, timeout, concurrency, layers, extensions, triggers, destinations&lt;/li&gt;
&lt;li&gt;Error handling: DLQs, Lambda Destinations&lt;/li&gt;
&lt;li&gt;Testing Lambda functions&lt;/li&gt;
&lt;li&gt;Performance tuning&lt;/li&gt;
&lt;li&gt;Real-time data processing&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 1.3: Use data stores in application development&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;DynamoDB: partition keys, GSIs, LSIs, query vs scan, consistency models&lt;/li&gt;
&lt;li&gt;Data serialization and persistence&lt;/li&gt;
&lt;li&gt;Data lifecycle management (TTL)&lt;/li&gt;
&lt;li&gt;Caching with ElastiCache and DAX&lt;/li&gt;
&lt;li&gt;Specialized stores like OpenSearch&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Domain 2
&lt;/h2&gt;

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

&lt;p&gt;&lt;strong&gt;(26%)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Security is woven into everything on this exam. &lt;br&gt;
Expect questions that combine security with development scenarios.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 2.1: Implement authentication and authorization&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Cognito User Pools and Identity Pools&lt;/li&gt;
&lt;li&gt;JWT tokens and bearer token validation&lt;/li&gt;
&lt;li&gt;IAM roles, policies, and STS AssumeRole&lt;/li&gt;
&lt;li&gt;Lambda authorizers&lt;/li&gt;
&lt;li&gt;Cross-service auth in microservices&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 2.2: Implement encryption using AWS services&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Encryption at rest vs in transit&lt;/li&gt;
&lt;li&gt;KMS: key creation, rotation, cross-account access&lt;/li&gt;
&lt;li&gt;Client-side vs server-side encryption&lt;/li&gt;
&lt;li&gt;AWS Encryption SDK&lt;/li&gt;
&lt;li&gt;Certificate management&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 2.3: Manage sensitive data in application code&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Secrets Manager vs SSM Parameter Store&lt;/li&gt;
&lt;li&gt;Encrypting Lambda environment variables&lt;/li&gt;
&lt;li&gt;Data classification (PII, PHI)&lt;/li&gt;
&lt;li&gt;Data masking and sanitization&lt;/li&gt;
&lt;li&gt;Multi-tenant data isolation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Domain 3
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(24%)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This domain is all about getting code from your machine to production safely and repeatably.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 3.1: Prepare application artifacts for deployment&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Packaging Lambda functions with dependencies&lt;/li&gt;
&lt;li&gt;Container images and ECR&lt;/li&gt;
&lt;li&gt;AWS AppConfig for feature flags and configuration&lt;/li&gt;
&lt;li&gt;Project structure for SAM/CloudFormation&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 3.2: Test applications in development environments&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;SAM local testing&lt;/li&gt;
&lt;li&gt;Integration tests against API Gateway stages&lt;/li&gt;
&lt;li&gt;Mocking external dependencies&lt;/li&gt;
&lt;li&gt;Testing event-driven applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 3.3: Automate deployment testing&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Test events for Lambda and API Gateway&lt;/li&gt;
&lt;li&gt;Lambda aliases and versions&lt;/li&gt;
&lt;li&gt;IaC templates (SAM, CloudFormation)&lt;/li&gt;
&lt;li&gt;Environment management&lt;/li&gt;
&lt;li&gt;Amazon Q Developer for test generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 3.4: Deploy code using AWS CI/CD services&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;CodePipeline, CodeBuild, CodeDeploy&lt;/li&gt;
&lt;li&gt;Deployment strategies: blue/green, canary, rolling&lt;/li&gt;
&lt;li&gt;Rollback strategies&lt;/li&gt;
&lt;li&gt;API Gateway stages and custom domains&lt;/li&gt;
&lt;li&gt;Dynamic deployments with staging variables&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Domain 4
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Troubleshooting and Optimization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(18%)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The smallest domain, but the questions can be tricky because they require you to diagnose problems from logs and metrics.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 4.1: Assist in root cause analysis&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Debugging code and interpreting error messages&lt;/li&gt;
&lt;li&gt;CloudWatch Logs, metrics, and traces&lt;/li&gt;
&lt;li&gt;CloudWatch Logs Insights queries&lt;/li&gt;
&lt;li&gt;Custom metrics with Embedded Metric Format&lt;/li&gt;
&lt;li&gt;Troubleshooting deployment failures&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 4.2: Instrument code for observability&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Logging vs monitoring vs observability&lt;/li&gt;
&lt;li&gt;Structured logging with correlation IDs&lt;/li&gt;
&lt;li&gt;X-Ray tracing: segments, subsegments, annotations&lt;/li&gt;
&lt;li&gt;CloudWatch alarms and SNS notifications&lt;/li&gt;
&lt;li&gt;Health checks and readiness probes&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Task 4.3: Optimize applications&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Lambda concurrency and performance tuning&lt;/li&gt;
&lt;li&gt;CloudFront caching strategies&lt;/li&gt;
&lt;li&gt;ElastiCache for application-level caching&lt;/li&gt;
&lt;li&gt;SNS subscription filter policies&lt;/li&gt;
&lt;li&gt;Identifying bottlenecks from logs and metrics&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key AWS Services to Know
&lt;/h2&gt;

&lt;p&gt;Here's a quick reference of the services that come up most on this exam:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compute:&lt;/strong&gt; Lambda, EC2, ECS, Fargate, Elastic Beanstalk&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API &amp;amp; Integration:&lt;/strong&gt; API Gateway, EventBridge, Step Functions, SQS, SNS, Kinesis&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data:&lt;/strong&gt; DynamoDB, S3, ElastiCache, DAX, RDS, OpenSearch&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security:&lt;/strong&gt; IAM, Cognito, KMS, Secrets Manager, SSM Parameter Store, ACM&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD:&lt;/strong&gt; CodePipeline, CodeBuild, CodeDeploy, CloudFormation, SAM, AppConfig&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability:&lt;/strong&gt; CloudWatch (Logs, Metrics, Alarms, Dashboards), X-Ray, CloudTrail&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Tools:&lt;/strong&gt; AWS SDK, AWS CLI, SAM CLI, Amazon Q Developer&lt;/p&gt;




&lt;h2&gt;
  
  
  How This Series Is Structured
&lt;/h2&gt;

&lt;p&gt;Each article in this series maps directly to an exam task. We'll (You and I...and perhaps your AI Assistant, since that's how we do things these days) cover the concepts you need to know, then get hands-on with real code and CLI commands. &lt;/p&gt;

&lt;p&gt;The goal is that by the end of the series, you've not only studied the material but you've built things with it...&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Recommended experience:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At least 1 year developing and maintaining AWS applications&lt;/li&gt;
&lt;li&gt;Comfortable with at least one programming language (Python, JavaScript/TypeScript, Java, C#, or Go)&lt;/li&gt;
&lt;li&gt;Familiar with the AWS Console, CLI, and at least one AWS SDK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What you'll need to follow along:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; An AWS account (free tier covers most of what we'll do)&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; AWS CLI v2 installed and configured&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; SAM CLI installed&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; A code editor (VS Code recommended)&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; Python 3.12+ or Node.js 20+ (we'll use both in examples)&lt;/p&gt;




&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://d1.awsstatic.com/training-and-certification/docs-dev-associate/AWS-Certified-Developer-Associate_Exam-Guide.pdf" rel="noopener noreferrer"&gt;AWS Certified Developer Associate Exam Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/aws-certification/latest/developer-associate-02/developer-associate-02-domain1.html" rel="noopener noreferrer"&gt;AWS Certified Developer - Associate Exam Guide (DVA-C02)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🚀&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>certification</category>
      <category>developer</category>
    </item>
    <item>
      <title>My Solutions Architect Associate Certification Journey and Resources to Certify With Confidence</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Thu, 23 Apr 2026 18:46:05 +0000</pubDate>
      <link>https://dev.to/aws-builders/my-solutions-architect-associate-certification-journey-and-resources-to-certify-with-confidence-5h16</link>
      <guid>https://dev.to/aws-builders/my-solutions-architect-associate-certification-journey-and-resources-to-certify-with-confidence-5h16</guid>
      <description>&lt;p&gt;☁️ &lt;strong&gt;Exam Guide:&lt;/strong&gt; Solutions Architect Associate &lt;br&gt;
&lt;strong&gt;Resources to Certify With Confidence&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;My Solutions Architect Associate Certification Journey&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 First Things First
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The First Attempt
&lt;/h3&gt;

&lt;p&gt;The first time I sat the Solutions Architect Associate exam, I was anxious.  &lt;/p&gt;

&lt;p&gt;This time? Still anxious.  &lt;/p&gt;

&lt;p&gt;Outcome? Passed both times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.credly.com/badges/35a2a375-cb7e-48d3-8692-fc9f4f16d8cc" rel="noopener noreferrer"&gt;Ntombizakhona Mabaso - AWS Certified Solutions Architect Associate&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So no, the nerves don’t magically disappear just because you’ve done it before. You just get better at performing &lt;em&gt;while&lt;/em&gt; anxious which feels like a life skill AWS forgot to list in the exam guide.&lt;/p&gt;

&lt;p&gt;That said, I do wish I hadn’t let my certification expire. The smarter move would’ve been to renew by going straight for the Professional exam.&lt;/p&gt;

&lt;p&gt;But: we live, we learn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Don’t let your Associate cert expire. Use it as a stepping stone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Renew with Professional certifications and&lt;/li&gt;
&lt;li&gt;Build into Specialties
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Future you&lt;/em&gt; will appreciate the efficiency. &lt;br&gt;
&lt;strong&gt;Present you&lt;/strong&gt; might procrastinate anyway, but at least now you’ve been warned.&lt;/p&gt;

&lt;h2&gt;
  
  
  📘Resources
&lt;/h2&gt;

&lt;h3&gt;
  
  
  If You Took Cloud Practitioner Seriously, You’re Already Ahead
&lt;/h3&gt;

&lt;p&gt;If you didn’t cut corners preparing for Cloud Practitioner, you’re in a strong position for the Solutions Architect Associate.&lt;/p&gt;

&lt;p&gt;These exams aren’t isolated. They evolve together.&lt;/p&gt;

&lt;p&gt;As cloud knowledge becomes more mainstream and general:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Foundational exams get more demanding and&lt;/li&gt;
&lt;li&gt;Associate exams become a bridge to Professional-level thinking
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if SAA-C03 feels familiar at times, that’s not a coincidence. It’s intentional.&lt;/p&gt;

&lt;p&gt;You’re not starting from scratch. You’re building on what you already know.&lt;br&gt;
So, revisit the resources here: &lt;a href="https://dev.to/aws-builders/my-cloud-practitioner-certification-journey-and-the-resources-to-certify-with-confidence-81n"&gt;Resources&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ The Resource That Actually Made a Difference
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CloudPulse
&lt;/h3&gt;

&lt;p&gt;The most valuable part of my preparation wasn’t another practice test. It was building something real.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ntombizakhona.medium.com/capstone-project-architecture-review-38db82027d5f" rel="noopener noreferrer"&gt;Capstone Project: Architecture Review&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hands-on work changes everything.&lt;/p&gt;

&lt;p&gt;It turns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“This looks complicated” → “Oh, I’ve seen this before”
&lt;/li&gt;
&lt;li&gt;“Tricky question” → “This is obviously the better design”
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you rely purely on theory, you might scrape a pass or not pass at all. This exam expects you to think like an architect, not a glossary.&lt;/p&gt;

&lt;p&gt;So yes, build something. &lt;br&gt;
Even a small project is better than memorizing services like you’re cramming for a trivia night.&lt;/p&gt;

&lt;h2&gt;
  
  
  💸 The Frugal Architect
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Domain Four Feels Repetitive… Because It’s Important
&lt;/h3&gt;

&lt;p&gt;Domain Four focuses on cost optimization. Being a &lt;strong&gt;Frugal Architect&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If it feels repetitive, that’s because cost is embedded in nearly every AWS decision. AWS wants to make absolutely sure you don’t forget that running unnecessary resources is basically setting money on fire.&lt;/p&gt;

&lt;p&gt;And unlike your bad subscription habits, this one actually matters.&lt;/p&gt;

&lt;p&gt;You may not see cost emphasized this heavily again in other exams, so pay attention here. Not just for the exam, but because in real-world architecture, cost-efficient solutions are what separate good engineers from expensive ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 What the SAA-C03 Really Teaches You
&lt;/h2&gt;

&lt;p&gt;It’s not just about services or patterns.&lt;/p&gt;

&lt;p&gt;It’s about &lt;strong&gt;resilience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The exam is broad. &lt;br&gt;
Concepts overlap. &lt;/p&gt;

&lt;p&gt;At some point, you’ll wonder if you’re:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;overthinking everything
&lt;/li&gt;
&lt;li&gt;studying the wrong topics
&lt;/li&gt;
&lt;li&gt;or slowly losing your grip on reality
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All normal.&lt;/p&gt;

&lt;p&gt;Push through anyway.&lt;/p&gt;

&lt;p&gt;Associate exams aren’t just testing knowledge. They’re building your endurance for continuous learning. And if you’re aiming for Professional or Specialty certifications, you’ll need that stamina.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Finally
&lt;/h2&gt;

&lt;p&gt;You don’t pass this exam by knowing everything.&lt;/p&gt;

&lt;p&gt;You pass by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;understanding enough
&lt;/li&gt;
&lt;li&gt;recognizing patterns
&lt;/li&gt;
&lt;li&gt;and not panicking when AWS gives you four answers that all seem correct
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which they will. Repeatedly. For fun.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Additional Resources
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/pdfs/aws-certification/latest/solutions-architect-associate-03/solutions-architect-associate-03.pdf" rel="noopener noreferrer"&gt;AWS SAA-C03 Exam Guide (PDF)&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://dev.to/ntombizakhona/series/35366"&gt;Exam Guide - Solutions Architect Associate&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://ntombizakhona.medium.com/capstone-project-architecture-review-38db82027d5f" rel="noopener noreferrer"&gt;Capstone Project (CloudPulse)&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://thefrugalarchitect.com/" rel="noopener noreferrer"&gt;The Frugal Architect&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; &lt;a href="https://dev.to/aws-builders/my-cloud-practitioner-certification-journey-and-the-resources-to-certify-with-confidence-81n"&gt;My Cloud Practitioner Certification Journey and the Resources to Certify with Confidence&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Good luck with your exam! 🚀&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>solutionsarchitect</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Technologies And Concepts: Cheat Sheet for Solutions Architect Associate (SAA-C03)</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Wed, 22 Apr 2026 17:31:28 +0000</pubDate>
      <link>https://dev.to/aws-builders/technologies-and-concepts-cheat-sheet-for-solutions-architect-associate-saa-c03-h52</link>
      <guid>https://dev.to/aws-builders/technologies-and-concepts-cheat-sheet-for-solutions-architect-associate-saa-c03-h52</guid>
      <description>&lt;p&gt;☁️ &lt;strong&gt;Exam Guide:&lt;/strong&gt; Solutions Architect Associate&lt;br&gt;
&lt;strong&gt;Technologies And Concepts Cheat Sheet&lt;/strong&gt;&lt;br&gt;
📘 &lt;em&gt;Cheat Sheet&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The SAA-C03 exam guide lists technologies and concepts across all four domains. This cheat sheet consolidates that information into a &lt;strong&gt;compact, exam-aligned reference.&lt;/strong&gt; Organized domain by domain.  Designed for quick review and efficient study.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📖 Exam Overview
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;th&gt;Info&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Exam Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SAA-C03&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Questions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;65 total (50 scored, 15 unscored)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Passing Score&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;720 / 1000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Question Types&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multiple choice &amp;amp; Multiple response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Experience Required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1+ year hands-on designing cloud solutions on AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Domain Weightings
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;Weight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Design Secure Architectures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Design Resilient Architectures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Design High-Performing Architectures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Design Cost-Optimized Architectures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔒 Domain 1
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Design Secure Architectures
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1.1&lt;/strong&gt; Secure Access to AWS Resources
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Users, Groups, Roles, Policies: Design flexible authorization models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IAM Identity Center&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Centralized SSO across multiple AWS accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MFA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apply to IAM users and root users as a security best practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Cross-Account Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Use IAM Roles + STS for role switching and cross-account patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Organizations &amp;amp; SCPs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manage multi-account security strategy with Service Control Policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Control Tower&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automate landing zones and guardrails across accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Resource Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Determine when to use resource-based vs identity-based policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Federated Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Directory service + IAM roles for external identity federation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Least Privilege&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Core security principle: grant only minimum required permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Shared Responsibility Model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS secures the cloud &amp;amp; you secure what's in it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1.2&lt;/strong&gt; Secure Workloads and Applications
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPC Architecture&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Security groups, route tables, NACLs, NAT gateways&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Subnets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Public vs private subnet segmentation strategies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Shield&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DDoS protection (Standard free, Advanced paid)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS WAF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web Application Firewall for Layer 7 (SQL injection, XSS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Secrets Manager&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rotate, manage, retrieve secrets (DB credentials, API keys)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Cognito&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;User authentication for web/mobile apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS GuardDuty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Threat detection using ML on logs/events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Macie&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Discover and protect sensitive data (PII) in S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Site-to-Site VPN and Client VPN for encrypted connectivity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Direct Connect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dedicated private network connection to AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1.3&lt;/strong&gt; Data Security Controls
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;KMS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed key creation, rotation, and control for encryption at rest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;ACM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Certificate Manager: TLS/SSL for encryption in transit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CloudHSM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hardware Security Module for customer-managed key control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Data Classification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Categorize data by sensitivity to apply appropriate controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;S3 Versioning &amp;amp; MFA Delete&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Protect object data from accidental deletion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Backup &amp;amp; Replication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Implement data backup, point-in-time recovery, cross-region replication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Data Lifecycle Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manage retention and expiry of data at rest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Compliance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Align AWS services to regulatory requirements (GDPR, HIPAA, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🏗️ Domain 2
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Design Resilient Architectures
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2.1&lt;/strong&gt; Scalable and Loosely Coupled Architectures
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon SQS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Decouple components with message queuing (Standard and FIFO)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon SNS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pub/sub messaging for fan-out patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon EventBridge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Event-driven routing across AWS services and SaaS apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Step Functions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Workflow orchestration for distributed applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Create, publish, and manage REST/HTTP/WebSocket APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon AppFlow&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed data integration between SaaS apps and AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS AppSync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed GraphQL API service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Serverless Patterns&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lambda + API Gateway + SQS/SNS for event-driven design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Microservices&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stateless vs stateful workloads &amp;amp; Independent scaling of components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Caching Strategies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reduce load &amp;amp; know when to use caching vs direct reads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Horizontal vs Vertical Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scale out (add instances) vs scale up (bigger instance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Load Balancers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ALB (Layer 7), NLB (Layer 4), GLB (Layer 3/4 for appliances)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon MQ&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed message broker (ActiveMQ/RabbitMQ) for migrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Multi-tier Architectures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web / App / DB tiers with distinct roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CDN / Edge Accelerators&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CloudFront for caching, Global Accelerator for routing performance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2.2&lt;/strong&gt; Highly Available and Fault-Tolerant Architectures
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Availability Zones&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deploy across ≥2 AZs for high availability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Regions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Choose regions based on latency, compliance, and redundancy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Disaster Recovery Strategies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Backup &amp;amp; Restore → Pilot Light → Warm Standby → Active-Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RPO / RTO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recovery Point Objective (data loss tolerance) vs Recovery Time Objective (downtime tolerance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Route 53&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DNS with health checks, failover routing, latency-based routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RDS Proxy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pooled DB connections for Lambda and high-concurrency apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Distributed Design Patterns&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Retry with backoff, circuit breaker, bulkhead patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Service Quotas &amp;amp; Throttling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Plan for limits in standby environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS X-Ray&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Distributed tracing for workload visibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Immutable Infrastructure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Replace rather than patch: ensures consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Auto Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;EC2 Auto Scaling + AWS Auto Scaling for elastic capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Storage Durability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;S3 (11 9s), EBS (99.999%), choose appropriate tier&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ⚡ Domain 3
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Design High-Performing Architectures
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3.1&lt;/strong&gt; Storage Solutions
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Service / Concept&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Object storage: scalable, durable, lifecycle policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon EBS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Block storage for EC2: SSD (gp3, io2) or HDD (st1, sc1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon EFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed NFS: shared file storage for Linux workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon FSx&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed file systems: Windows (SMB), Lustre (HPC), NetApp, OpenZFS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Storage Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hybrid storage: file, volume, tape gateway types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Storage Types&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Object vs File vs Block: know performance and use-case differences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;S3 Storage Classes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standard, Intelligent-Tiering, IA, Glacier, Glacier Deep Archive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3.2&lt;/strong&gt; Compute Solutions
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Service / Concept&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon EC2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Virtual machines: choose instance type/family for workload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;EC2 Auto Scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automatically add/remove instances based on demand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless functions: event-driven, scale to zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Fargate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless containers: no EC2 management needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon ECS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Container orchestration on EC2 or Fargate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon EKS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed Kubernetes: supports Anywhere and Distro variants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Batch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed batch processing: compute-intensive jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon EMR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Big data on managed Hadoop/Spark clusters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Elastic Beanstalk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;PaaS: deploy web apps without managing infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Outposts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS infrastructure on-premises (hybrid)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Wavelength&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deploy workloads at the edge of 5G networks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  3.3 Database Solutions
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Service / Concept&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon RDS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed relational DB: MySQL, PostgreSQL, SQL Server, Oracle, MariaDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Aurora&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High-performance relational DB (MySQL/PostgreSQL compatible)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Aurora Serverless&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;On-demand autoscaling for Aurora (v2 generally available)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon DynamoDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless NoSQL: millisecond latency at any scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon ElastiCache&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In-memory caching: Redis (complex data) vs Memcached (simple)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Redshift&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data warehouse: columnar storage for analytics queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon DocumentDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed MongoDB-compatible document database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Neptune&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Graph database for connected data (social graphs, fraud detection)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Keyspaces&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed Apache Cassandra-compatible service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Read Replicas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Offload read traffic &amp;amp; know when to use vs Multi-AZ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Caching Patterns&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cache-aside, write-through, TTL strategies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DB Capacity Planning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Capacity Units (DynamoDB), Provisioned IOPS, instance sizing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3.4&lt;/strong&gt; Network Architectures
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Service / Concept&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon VPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Isolated virtual network: subnets, route tables, IGW, NAT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon CloudFront&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CDN: cache content at edge locations globally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Global Accelerator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Route users to optimal endpoints using AWS global network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Elastic Load Balancing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ALB (HTTP/S), NLB (TCP/UDP), GLB (appliances)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Direct Connect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dedicated private line to AWS (predictable performance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Transit Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hub-and-spoke for connecting many VPCs and on-prem networks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPC Peering&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct VPC-to-VPC connectivity (no transitive routing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS PrivateLink&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Private access to AWS services and third-party services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Route 53&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DNS. Routing policies: simple, weighted, latency, failover, geolocation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Network Topology&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Global, hybrid, multi-tier &amp;amp; design for scale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3.5&lt;/strong&gt; Data Ingestion and Transformation
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Service / Concept&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Kinesis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time streaming data: Data Streams, Data Firehose, Video Streams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Data Firehose&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Load streaming data to S3, Redshift, OpenSearch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Glue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless ETL: transform and catalog data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Athena&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Serverless SQL queries on S3 data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Lake Formation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Build, secure, and manage data lakes on S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon EMR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Process large datasets with Hadoop, Spark, Hive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon MSK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed Apache Kafka for streaming pipelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS DataSync&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automate data transfer between on-prem and AWS storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Transfer Family&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Managed SFTP/FTPS/FTP to S3 or EFS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon QuickSuite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;BI and data visualization service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon OpenSearch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Search and analytics &amp;amp; also supports vector similarity (RAG)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Amazon Redshift&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Query structured data at petabyte scale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  💰 Domain 4
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Design Cost-Optimized Architectures
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4.1&lt;/strong&gt; Cost-Optimized Storage
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;S3 Storage Classes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Match class to access frequency &amp;amp; Glacier for archival&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;S3 Lifecycle Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automate transitions between storage classes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;S3 Intelligent-Tiering&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Auto-move objects between tiers based on access patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;EBS Volume Types&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;gp3 vs io2 vs st1 vs sc1 &amp;amp; match to IOPS and cost needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Requester Pays&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transfer cost charged to requester, not bucket owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Data Lifecycle Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Retain only what's needed &amp;amp; expire or archive the rest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hybrid Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DataSync, Transfer Family, Storage Gateway for on-prem cost reduction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Backup Strategy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Balance recovery needs with cost (snapshots, replication)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  4.2 Cost-Optimized Compute
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;On-Demand Instances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pay per use: highest flexibility, highest per-hour cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reserved Instances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 or 3 year commitment: up to 72% savings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Savings Plans&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Flexible commitment (Compute, EC2, SageMaker)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Spot Instances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Up to 90% savings for fault-tolerant/interruptible workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Compute Optimizer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ML-based recommendations for right-sizing EC2, Lambda, EBS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS Serverless Application Repository&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pre-built serverless apps: reduce build cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;EC2 Hibernation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Save instance state to EBS: resume without full reboot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Containerization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ECS/EKS/Fargate for higher density and cost efficiency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Instance Families&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;General purpose, compute optimized, memory optimized, storage optimized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VMware Cloud on AWS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extend VMware workloads to AWS without refactoring&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4.3&lt;/strong&gt; Cost-Optimized Databases
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DynamoDB On-Demand vs Provisioned&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;On-demand for unpredictable; provisioned for predictable + cheaper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Aurora Serverless&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pay per ACU-hour: ideal for intermittent workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RDS Reserved Instances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Commit to 1 or 3 years for significant savings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Read Replicas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Offload reads to reduce primary DB load (and cost)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DB Snapshot Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Balance frequency vs storage cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Caching&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ElastiCache reduces DB query load and cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Data Retention Policies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Define how long to keep data: archive vs delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Right-Sized DB Instances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Don't over-provision: use metrics to guide sizing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  4.4 Cost-Optimized Network Architectures
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What to Know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;NAT Gateway vs NAT Instance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NAT Gateway scales automatically but costs more &amp;amp; NAT instance is cheaper at low traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPC Endpoints&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Eliminate NAT costs for S3/DynamoDB &amp;amp; use Gateway Endpoints (free)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Direct Connect vs VPN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Direct Connect more expensive but predictable; VPN cheaper for low volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Region-to-Region Transfer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data egress fees apply &amp;amp; minimize cross-region traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Same-AZ Traffic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free &amp;amp; architect to keep traffic within same AZ where possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CloudFront&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reduce origin data transfer costs with edge caching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Transit Gateway Pricing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Attachment + data processing fees &amp;amp; evaluate vs VPC peering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Throttling Strategy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Use API Gateway throttling to control overuse and cost spikes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🛠️ AWS Cost Management Tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Cost Explorer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Visualize and analyze historical spend and forecast costs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Budgets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Set spend/usage thresholds with alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Cost and Usage Report&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Granular billing data exportable to S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Savings Plans&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Flexible commitment model for compute savings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost Allocation Tags&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tag resources to attribute costs to teams/projects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Compute Optimizer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Right-sizing recommendations based on usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Trusted Advisor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best-practice checks across cost, security, performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Well-Architected Tool&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Review architecture against the Well-Architected Framework&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  💡 Disaster Recovery Strategy Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;RPO&lt;/th&gt;
&lt;th&gt;RTO&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backup &amp;amp; Restore&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hours&lt;/td&gt;
&lt;td&gt;Hours&lt;/td&gt;
&lt;td&gt;💰 Lowest&lt;/td&gt;
&lt;td&gt;Back up to S3/Glacier &amp;amp; restore on failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pilot Light&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;10s of minutes&lt;/td&gt;
&lt;td&gt;💰💰&lt;/td&gt;
&lt;td&gt;Core services always running &amp;amp;scale up on failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Warm Standby&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Seconds/Minutes&lt;/td&gt;
&lt;td&gt;Minutes&lt;/td&gt;
&lt;td&gt;💰💰💰&lt;/td&gt;
&lt;td&gt;Scaled-down live environment &amp;amp; quickly scale to full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active-Active&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Near zero&lt;/td&gt;
&lt;td&gt;Near zero&lt;/td&gt;
&lt;td&gt;💰💰💰💰 Highest&lt;/td&gt;
&lt;td&gt;Full duplicate environment &amp;amp; traffic split between sites&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔑 Key Abbreviations
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Abbreviation&lt;/th&gt;
&lt;th&gt;Full Term&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Identity and Access Management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Service Control Policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MFA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-Factor Authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;STS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Security Token Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ACM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS Certificate Manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;KMS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Key Management Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Virtual Private Cloud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NACL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network Access Control List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ALB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Application Load Balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NLB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Network Load Balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GLB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gateway Load Balancer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CDN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Content Delivery Network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RPO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recovery Point Objective&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RTO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recovery Time Objective&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Disaster Recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EBS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Elastic Block Store&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Elastic File System&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FSx&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Amazon FSx (managed file systems)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple Queue Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SNS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple Notification Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ETL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Extract, Transform, Load&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HDD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hard Disk Drive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Solid State Drive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IOPS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Input/Output Operations Per Second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reserved Instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ACU&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Aurora Capacity Unit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PII&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Personally Identifiable Information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single Sign-On&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 In Scope AWS Services Quick Reference
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Compute
&lt;/h3&gt;

&lt;p&gt;Amazon EC2 · EC2 Auto Scaling · AWS Lambda · AWS Fargate · AWS Elastic Beanstalk · AWS Batch · AWS Outposts · VMware Cloud on AWS · AWS Wavelength · AWS Serverless Application Repository&lt;/p&gt;

&lt;h3&gt;
  
  
  Containers
&lt;/h3&gt;

&lt;p&gt;Amazon ECR · Amazon ECS · ECS Anywhere · Amazon EKS · EKS Anywhere · Amazon EKS Distro&lt;/p&gt;

&lt;h3&gt;
  
  
  Storage
&lt;/h3&gt;

&lt;p&gt;Amazon S3 · Amazon EBS · Amazon EFS · Amazon FSx · AWS Storage Gateway · AWS Snow Family&lt;/p&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;p&gt;Amazon RDS · Amazon Aurora · Aurora Serverless · Amazon DynamoDB · Amazon ElastiCache · Amazon Redshift · Amazon DocumentDB · Amazon Neptune · Amazon Keyspaces&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking &amp;amp; Content Delivery
&lt;/h3&gt;

&lt;p&gt;Amazon VPC · Amazon CloudFront · AWS Direct Connect · Elastic Load Balancing · AWS Global Accelerator · AWS PrivateLink · Amazon Route 53 · AWS Site-to-Site VPN · AWS Client VPN · AWS Transit Gateway&lt;/p&gt;

&lt;h3&gt;
  
  
  Analytics
&lt;/h3&gt;

&lt;p&gt;Amazon Athena · Amazon EMR · AWS Glue · Amazon Kinesis · Amazon Data Firehose · Amazon Kinesis Video Streams · Amazon MSK · Amazon OpenSearch Service · Amazon QuickSuite · Amazon Redshift · AWS Lake Formation · AWS Data Exchange&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Integration
&lt;/h3&gt;

&lt;p&gt;Amazon SQS · Amazon SNS · Amazon EventBridge · Amazon MQ · AWS Step Functions · Amazon AppFlow · AWS AppSync&lt;/p&gt;

&lt;h3&gt;
  
  
  Security, Identity &amp;amp; Compliance
&lt;/h3&gt;

&lt;p&gt;AWS IAM · AWS IAM Identity Center · Amazon Cognito · AWS KMS · AWS CloudHSM · AWS ACM · Amazon GuardDuty · Amazon Macie · Amazon Detective · AWS Shield · AWS WAF · AWS Secrets Manager · AWS Directory Service · AWS Artifact · AWS Audit Manager&lt;/p&gt;

&lt;h3&gt;
  
  
  Management &amp;amp; Governance
&lt;/h3&gt;

&lt;p&gt;AWS Organizations · AWS Control Tower · AWS CloudFormation · AWS CloudTrail · Amazon CloudWatch · AWS Config · AWS Systems Manager · AWS Auto Scaling · AWS Compute Optimizer · AWS Trusted Advisor · AWS Well-Architected Tool · AWS Service Catalog · AWS Health Dashboard · AWS License Manager · Amazon Managed Grafana · Amazon Managed Service for Prometheus&lt;/p&gt;

&lt;h3&gt;
  
  
  Migration &amp;amp; Transfer
&lt;/h3&gt;

&lt;p&gt;AWS DMS · AWS DataSync · AWS Snow Family · AWS Transfer Family · AWS Application Migration Service&lt;/p&gt;

&lt;h3&gt;
  
  
  Machine Learning
&lt;/h3&gt;

&lt;p&gt;Amazon SageMaker AI · Amazon Comprehend · Amazon Kendra · Amazon Lex · Amazon Polly · Amazon Rekognition · Amazon Textract · Amazon Transcribe · Amazon Translate&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost Management
&lt;/h3&gt;

&lt;p&gt;AWS Budgets · AWS Cost Explorer · AWS Cost and Usage Report · Savings Plans&lt;/p&gt;

&lt;h3&gt;
  
  
  Developer Tools
&lt;/h3&gt;

&lt;p&gt;AWS X-Ray&lt;/p&gt;

&lt;h3&gt;
  
  
  Serverless
&lt;/h3&gt;

&lt;p&gt;AWS Lambda · AWS Fargate · Amazon API Gateway · Amazon DynamoDB · Amazon EventBridge · Amazon SQS · Amazon SNS&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt; Always refer to the official exam guide for the most up-to-date list of in-scope and out-of-scope services.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📚 Additional Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/pdfs/aws-certification/latest/solutions-architect-associate-03/solutions-architect-associate-03.pdf" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect – Associate (SAA-C03) Exam Guide (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/pdfs/aws-certification/latest/examguides/aws-certification-exam-guides.pdf" rel="noopener noreferrer"&gt;AWS Certification: All Exam Guides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/ntombizakhona/series/35366"&gt;Exam Guide: Solutions Architect Associate Series&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Good luck with your exam! 🚀&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>certification</category>
      <category>solutionsarchitect</category>
    </item>
    <item>
      <title>Jog Squad | A Gamified Eco-Jogging App: Fix the Earth. Fix Your Health. One Run at a Time. 🏃</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Sun, 19 Apr 2026 13:55:29 +0000</pubDate>
      <link>https://dev.to/ntombizakhona/jog-squad-a-gamified-eco-jogging-app-fix-the-earth-fix-your-health-one-run-at-a-time-3j5f</link>
      <guid>https://dev.to/ntombizakhona/jog-squad-a-gamified-eco-jogging-app-fix-the-earth-fix-your-health-one-run-at-a-time-3j5f</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-04-16"&gt;Weekend Challenge: Earth Day Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'm a jogger. Not the "I ran a marathon once" kind but the &lt;em&gt;"I need to run or my brain stops working"&lt;/em&gt; kind. Running is how I think, how I decompress, how I stay sane.&lt;/p&gt;

&lt;p&gt;But here's the thing that drives me crazy: every single run, I pass litter. &lt;br&gt;
Plastic bottles in the grass. &lt;br&gt;
Wrappers caught in fences. &lt;br&gt;
Cans rolling down the sidewalk. &lt;br&gt;
It's literally everywhere, and most people  myself included, honestly just jog right past it...hoping the Municipality takes care of it.&lt;/p&gt;

&lt;p&gt;So, I love this planet. I love being outside in it. And it frustrates me that the places I run through are slowly being buried in trash that nobody takes responsibility for.&lt;/p&gt;

&lt;p&gt;So when this Earth Day challenge dropped, I knew exactly what to build. Not another carbon calculator. Not another awareness app. Something that actually connects the act of running. Something I and many others already do every day. Something that makes picking up trash feel rewarding instead of inconvenient... &lt;br&gt;
Enter: &lt;strong&gt;🏃 #JogSquad&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;



&lt;p&gt;&lt;strong&gt;Jog Squad&lt;/strong&gt; is a gamified eco-jogging app that turns every outdoor run into an environmental cleanup mission.&lt;/p&gt;

&lt;p&gt;The app connects your personal health to the planet's health through three pillars:&lt;/p&gt;

&lt;p&gt;🗑️ &lt;strong&gt;Litter Detection &amp;amp; Cleanup:&lt;/strong&gt; Snap a photo of your route and Gemini Vision AI identifies the litter, scores the area's cleanliness, and explains the environmental impact. Pick up what you find, log it, and earn points.&lt;/p&gt;

&lt;p&gt;⚡ &lt;strong&gt;Electricity Saved:&lt;/strong&gt; Every outdoor run you do instead of using a treadmill saves &lt;em&gt;real&lt;/em&gt; electricity. Especially in South Africa, where LoadShedding (Controlled Power Cuts) can rear its head any second. The app tracks and quantifies this because treadmills consume roughly 0.7 kWh per hour, and running outside costs zero.&lt;/p&gt;

&lt;p&gt;🏃 &lt;strong&gt;Health &amp;amp; Fitness:&lt;/strong&gt; GPS-tracked runs with live mapping, pace calculation, and AI-powered coaching insights that get smarter as you log more runs.&lt;/p&gt;

&lt;p&gt;The twist? &lt;strong&gt;You lose points for running on a treadmill and for skipping litter cleanup.&lt;/strong&gt; &lt;em&gt;Accountability through gamification&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Key features:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live GPS&lt;/strong&gt; run tracking with real-time map (or demo mode for presentations)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI environment scanning:&lt;/strong&gt; upload a photo, get litter detection and  cleanliness score&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before/after photo comparison:&lt;/strong&gt; Gemini narrates your cleanup impact&lt;/li&gt;
&lt;li&gt;Points system with rewards AND penalties&lt;/li&gt;
&lt;li&gt;AI-generated &lt;strong&gt;daily missions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Squad &lt;strong&gt;leaderboard&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full impact dashboard:&lt;/strong&gt; CO₂ saved, electricity saved, litter removed&lt;/li&gt;
&lt;li&gt;AI &lt;strong&gt;run reflections&lt;/strong&gt; with pattern detection across your run history&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;




&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://jog-squad-3921552307.africa-south1.run.app/"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;strong&gt;🔗 Live on Google Cloud Run:&lt;/strong&gt; &lt;a href="https://jog-squad-3921552307.africa-south1.run.app/" rel="noopener noreferrer"&gt;Jog Squad&lt;/a&gt;

&lt;p&gt;&lt;strong&gt;To try the full flow without going outside:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1.&lt;/strong&gt; Go to &lt;strong&gt;Log Run&lt;/strong&gt; → click &lt;strong&gt;"Demo Run (simulated GPS)"&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Watch the live map track a simulated jog around Johannesburg&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Finish the run → get AI analysis → log some litter cleanup&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; Check the &lt;strong&gt;Impact&lt;/strong&gt; page to see your environmental stats&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; Try &lt;strong&gt;Scan&lt;/strong&gt; → upload any outdoor photo → Gemini analyzes the litter&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;




&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Ntombizakhona" rel="noopener noreferrer"&gt;
        Ntombizakhona
      &lt;/a&gt; / &lt;a href="https://github.com/Ntombizakhona/jog-squad" rel="noopener noreferrer"&gt;
        jog-squad
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Fix the Earth. Fix Your Health. Gamified eco-jogging with Gemini AI.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🏃 Jog Squad&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Fix the Earth. Fix Your Health. One Run at a Time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Jog Squad is a gamified eco-jogging app that turns every outdoor run into an environmental cleanup opportunity. Using Google's Gemini AI, it detects litter from photos, tracks your environmental impact, and rewards you for making the planet cleaner — one jog at a time.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🌍 The Problem&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Litter is everywhere. Treadmills waste electricity. People jog past trash every day without thinking about it.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;💡 The Solution&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Jog Squad connects your health to the earth's health:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run outdoors&lt;/strong&gt; instead of on a treadmill → save electricity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan your route&lt;/strong&gt; with AI → see the litter problem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick up trash&lt;/strong&gt; during your run → earn points&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before/after photos&lt;/strong&gt; → prove your impact with AI comparison&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track everything&lt;/strong&gt; → CO₂ saved, electricity saved, litter removed&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Features&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🏃 &lt;strong&gt;Run Logging&lt;/strong&gt; — Distance, time, indoor/outdoor, mood tracking&lt;/li&gt;
&lt;li&gt;📸 &lt;strong&gt;AI Environment&lt;/strong&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Ntombizakhona/jog-squad" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React 18 + Vite, with Leaflet for live mapping&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Node.js + Express&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI:&lt;/strong&gt; Google Gemini 2.5 Flash (text generation + vision)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; Google Cloud Firestore (Native mode)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy:&lt;/strong&gt; Google Cloud Run (containerized with Docker)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Gemini Integration (6 distinct uses)
&lt;/h3&gt;

&lt;p&gt;This isn't "AI sprinkled on top." Gemini is doing real work across the entire app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run Reflections:&lt;/strong&gt; After each run, Gemini receives your distance, pace, mood, location type, and your past run history. It generates personalized performance insights, improvement tips, and eco-impact statements. With enough runs, it detects patterns like "you slow down after 3km" or "you perform better in cooler weather."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment Scanning:&lt;/strong&gt; Upload a photo of your running route. Gemini Vision analyzes it and returns structured JSON: litter types detected (plastic, metal, paper, glass), estimated counts, a cleanliness score from 1-10, and an environmental impact statement.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Before/After Comparison:&lt;/strong&gt;  Upload two photos (before and after cleanup). Gemini compares them and narrates the improvement, estimates items removed, and generates an impact statement. This is the feature that makes the cleanup feel real.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cleanup Summaries:&lt;/strong&gt; When you log collected litter, Gemini explains how long those items would take to decompose and what the real-world impact of removing them is.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Daily Missions:&lt;/strong&gt; Gemini generates personalized daily challenges scaled to your experience level. New users get "Run 0.5km and pick up 1 item." Experienced users get harder goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Squad Leaderboard:&lt;/strong&gt; Gemini generates a realistic mock leaderboard that places you among fictional squad members, making the app feel social even as a single-user POC.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every Gemini call returns structured JSON that the app parses and renders. The prompts are carefully designed to get consistent, parseable responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  GPS Tracking
&lt;/h3&gt;

&lt;p&gt;The app uses the browser's Geolocation API with &lt;code&gt;watchPosition&lt;/code&gt; for real-time tracking. Key decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Haversine formula&lt;/strong&gt; for distance calculation between GPS coordinates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accuracy filtering:&lt;/strong&gt; readings over 30m accuracy are discarded&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jitter filtering:&lt;/strong&gt; movements under 3m are ignored (GPS noise)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jump filtering:&lt;/strong&gt; movements over 500m in one reading are rejected (GPS glitches)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo mode:&lt;/strong&gt; a simulated 20-point route around Emmarentia Dam, Johannesburg, with points dropped every 1.5 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Points System
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Points&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Distance run&lt;/td&gt;
&lt;td&gt;+10 per km&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outdoor run&lt;/td&gt;
&lt;td&gt;+20 bonus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Litter collected&lt;/td&gt;
&lt;td&gt;+5 per item&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Treadmill run&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-15 penalty&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skipped cleanup&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-10 penalty&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The penalties are the key design decision. Most eco apps only reward. Jog Squad also punishes because running on a treadmill wastes electricity, and jogging past litter without picking it up is a missed opportunity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Run Deployment
&lt;/h3&gt;

&lt;p&gt;The Dockerfile uses a multi-stage build: first stage builds the React client with Vite, second stage runs the Express server and serves the static files. Deployed to &lt;code&gt;africa-south1&lt;/code&gt; for low latency from South Africa, with Firestore in the same region.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Google Gemini:&lt;/strong&gt; Gemini is the backbone of the app, powering 6 distinct features: run reflections with pattern detection, environment photo scanning, before/after cleanup comparison, cleanup impact summaries, daily mission generation, and squad leaderboard generation. It uses both text generation and vision capabilities.&lt;/p&gt;




&lt;p&gt;To fix your health, you have to fix the earth. To fix the earth, you have to get out there. Run. Clean. Repeat.&lt;/p&gt;

&lt;p&gt;Happy Earth Day 🌍&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏃 #JogSquad&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>Design Cost Optimized Network Architectures</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Wed, 15 Apr 2026 15:56:59 +0000</pubDate>
      <link>https://dev.to/aws-builders/design-cost-optimized-network-architectures-5fg9</link>
      <guid>https://dev.to/aws-builders/design-cost-optimized-network-architectures-5fg9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Exam Guide:&lt;/strong&gt; Solutions Architect - Associate&lt;br&gt;
&lt;strong&gt;⚡ Domain 4: Design Cost-Optimized Architectures&lt;/strong&gt;&lt;br&gt;
📘 &lt;em&gt;Task Statement 4.4&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;&lt;em&gt;Designing Cost-Optimized Network Architectures&lt;/em&gt;&lt;/strong&gt; is about selecting the &lt;strong&gt;cheapest networking design that still meets requirements for performance, availability, security, and scalability&lt;/strong&gt;.
&lt;/h3&gt;

&lt;p&gt;Start by understanding:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Traffic flow&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Connectivity needs&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Data transfer patterns&lt;/p&gt;

&lt;p&gt;Then choose:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Networking services&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Routing model&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Edge strategy&lt;/p&gt;

&lt;p&gt;Finally optimise using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;CDN&lt;/li&gt;
&lt;li&gt;NAT strategy&lt;/li&gt;
&lt;li&gt;Traffic reduction techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are often deciding between:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Internet Gateway vs VPN vs Direct Connect&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; NAT Gateway vs NAT Instance&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; VPC Peering vs Transit Gateway&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;4&lt;/em&gt;&lt;/strong&gt; Edge caching vs origin traffic&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;5&lt;/em&gt;&lt;/strong&gt; Cross-AZ vs single-AZ traffic  &lt;/p&gt;




&lt;h2&gt;
  
  
  📘 Knowledge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1&lt;/strong&gt; | AWS Cost Management Features
&lt;/h3&gt;

&lt;p&gt;Network cost optimization starts with visibility into data transfer and routing charges.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cost Allocation Tags &amp;amp; Multi-Account Billing
&lt;/h4&gt;

&lt;p&gt;Network cost should be tracked by:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Environment (prod/dev/test)&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Application or service&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Network layer (VPC, NAT, ALB)&lt;/p&gt;

&lt;h4&gt;
  
  
  1.1 &lt;strong&gt;Cost Allocation Tags&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Used to track:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; NAT Gateway cost&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Load Balancer usage&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; VPC traffic patterns&lt;/p&gt;

&lt;h4&gt;
  
  
  1.2 &lt;strong&gt;Multi-Account Billing (AWS Organizations)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Centralized billing for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Multiple accounts&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Environment separation&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Cost visibility across teams&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2&lt;/strong&gt; | AWS Cost Management Tools
&lt;/h3&gt;

&lt;h4&gt;
  
  
  2.1 &lt;strong&gt;Cost Explorer&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Analyze data transfer trends&lt;/li&gt;
&lt;li&gt;Identify expensive network paths&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2.2 &lt;strong&gt;AWS Budgets&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Alerts for unexpected network cost spikes&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2.3 &lt;strong&gt;Cost and Usage Report (CUR)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Deep-level network cost analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3&lt;/strong&gt; | Load Balancing Concepts
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Application Load Balancer (ALB)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Layer 7 routing&lt;/li&gt;
&lt;li&gt;Cost based on usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4&lt;/strong&gt; | NAT Gateways
&lt;/h3&gt;

&lt;h4&gt;
  
  
  NAT Gateways vs NAT Instances
&lt;/h4&gt;

&lt;h4&gt;
  
  
  4.1 &lt;strong&gt;NAT Gateway&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Managed&lt;/li&gt;
&lt;li&gt;Highly available&lt;/li&gt;
&lt;li&gt;Higher cost (per hour + per GB)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Production&lt;/em&gt; → &lt;strong&gt;NAT Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Avoid NAT Gateway usage for AWS services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway Endpoint (S3, DynamoDB) → &lt;strong&gt;FREE&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Interface Endpoint → &lt;strong&gt;Private connectivity&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4.2 &lt;strong&gt;NAT Instance&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;EC2-based&lt;/li&gt;
&lt;li&gt;Cheaper but requires management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Dev/Test&lt;/em&gt; → &lt;strong&gt;NAT Instance&lt;/strong&gt;  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5&lt;/strong&gt; | Network Connectivity Options
&lt;/h3&gt;

&lt;h4&gt;
  
  
  5.1 &lt;strong&gt;Internet Gateway (IGW)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Public internet access&lt;/li&gt;
&lt;li&gt;No additional hourly cost &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5.2 &lt;strong&gt;AWS Site-to-Site VPN&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Encrypted over internet&lt;/li&gt;
&lt;li&gt;Quick setup&lt;/li&gt;
&lt;li&gt;Lower cost than Direct Connect&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  5.3 &lt;strong&gt;AWS Direct Connect&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Dedicated private connection&lt;/li&gt;
&lt;li&gt;High performance&lt;/li&gt;
&lt;li&gt;Higher fixed cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6&lt;/strong&gt; | Network Routing, Topology, and Peering
&lt;/h3&gt;

&lt;h4&gt;
  
  
  6.1 &lt;strong&gt;VPC Peering&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Direct VPC-to-VPC connection&lt;/li&gt;
&lt;li&gt;Low cost&lt;/li&gt;
&lt;li&gt;Not scalable for large architectures&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  6.2 &lt;strong&gt;AWS Transit Gateway&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Central routing hub&lt;/li&gt;
&lt;li&gt;Scalable but adds cost per attachment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7&lt;/strong&gt; | Network Services
&lt;/h3&gt;

&lt;h4&gt;
  
  
  7.1 &lt;strong&gt;Amazon Route 53&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Route 53 is a scalable DNS and domain management service used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Route user traffic to applications&lt;/li&gt;
&lt;li&gt;Improve availability with health checks&lt;/li&gt;
&lt;li&gt;Optimize routing decisions (latency, geography, failover)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  7.2 &lt;strong&gt;AWS Global Accelerator&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Optimizes routing&lt;/li&gt;
&lt;li&gt;Reduces latency&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  7.3 &lt;strong&gt;Amazon CloudFront&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Caches content globally&lt;/li&gt;
&lt;li&gt;Reduces origin load and data transfer costs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Skills
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A&lt;/strong&gt; | NAT Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Single NAT Gateway → &lt;strong&gt;cost efficient&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Multi-AZ NAT → &lt;strong&gt;high availability&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;B&lt;/strong&gt; | Connectivity Selection
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Internet access&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;IGW&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid connection&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPN&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise private link&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Direct Connect&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;C&lt;/strong&gt; | Routing Optimization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Reduce cross-AZ traffic&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Use VPC endpoints&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Use CloudFront for caching&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Cross-AZ Traffic&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Avoid unnecessary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-AZ calls&lt;/li&gt;
&lt;li&gt;Distributed chatty microservices&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Cross-Region Traffic&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Use only when needed for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DR&lt;/li&gt;
&lt;li&gt;Global users&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;VPC Endpoints&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Avoid NAT Gateway usage for AWS services.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway Endpoint (S3, DynamoDB) → &lt;strong&gt;FREE&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Interface Endpoint → &lt;strong&gt;Private connectivity&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;D&lt;/strong&gt; | CDN Strategy
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Amazon CloudFront&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Caches content globally&lt;/li&gt;
&lt;li&gt;Reduces origin load and data transfer costs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use CloudFront for:&lt;br&gt;
&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Global users&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Static assets&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; API acceleration&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;E&lt;/strong&gt; | Workload Optimization
&lt;/h3&gt;

&lt;p&gt;Look for:&lt;br&gt;
&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Unused NAT Gateways&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Cross-region traffic waste&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Missing caching layers&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;F&lt;/strong&gt; | Throttling Strategy
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;RDS Proxy&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Connection pooling&lt;/li&gt;
&lt;li&gt;Reduces database/network pressure&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;API Throttling&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Prevents traffic spikes&lt;/li&gt;
&lt;li&gt;Reduces scaling cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;G&lt;/strong&gt; | Bandwidth Allocation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;VPN = small workloads
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Direct Connect = high traffic workloads  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Single VPN&lt;/em&gt; → &lt;strong&gt;low throughput&lt;/strong&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Multiple VPNs&lt;/em&gt; → &lt;strong&gt;higher throughput&lt;/strong&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Direct Connect&lt;/em&gt; → &lt;strong&gt;stable high bandwidth&lt;/strong&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧠 Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reduce NAT cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPC Endpoints&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global traffic&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CloudFront&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid networking&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPN / Direct Connect&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-VPC architecture&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Transit Gateway&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simple connectivity&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;VPC Peering&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reduce DB/network load&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RDS Proxy + caching&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High bandwidth private link&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Direct Connect&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Recap Checklist ✅
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; [ ] I can choose NAT Gateway vs NAT Instance&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; [ ] I understand VPN vs Direct Connect trade-offs&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; [ ] I can reduce cost using VPC Endpoints&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; [ ] I understand cross-AZ and cross-region cost impact&lt;br&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; [ ] I can apply CloudFront for edge optimization&lt;br&gt;&lt;br&gt;
&lt;strong&gt;6.&lt;/strong&gt; [ ] I understand Transit Gateway vs VPC Peering&lt;br&gt;&lt;br&gt;
&lt;strong&gt;7.&lt;/strong&gt; [ ] I can optimize ALB usage&lt;br&gt;&lt;br&gt;
&lt;strong&gt;8.&lt;/strong&gt; [ ] I can identify expensive routing patterns  &lt;/p&gt;




&lt;h2&gt;
  
  
  AWS Whitepapers and Official Documentation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Cost Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/aws-cost-management/aws-cost-explorer/" rel="noopener noreferrer"&gt;Cost Explorer&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/aws-cost-management/aws-budgets/" rel="noopener noreferrer"&gt;AWS Budgets&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/cur/latest/userguide/what-is-cur.html" rel="noopener noreferrer"&gt;CUR&lt;/a&gt; &lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/organizations/" rel="noopener noreferrer"&gt;Organizations&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Networking Core Services&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/vpc/" rel="noopener noreferrer"&gt;VPC&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/transit-gateway/" rel="noopener noreferrer"&gt;Transit Gateway&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html" rel="noopener noreferrer"&gt;VPC Peering&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/directconnect/" rel="noopener noreferrer"&gt;Direct Connect&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/vpn/latest/s2svpn/VPC_VPN.html" rel="noopener noreferrer"&gt;VPN&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Optimization Services&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/cloudfront/" rel="noopener noreferrer"&gt;Cloudfront&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://aws.amazon.com/global-accelerator/" rel="noopener noreferrer"&gt;Global Accelerator&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints.html" rel="noopener noreferrer"&gt;VPC Endpoints&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html" rel="noopener noreferrer"&gt;Load Balancing&lt;/a&gt;  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Performance Optimization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html" rel="noopener noreferrer"&gt;RDS Proxy&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;🚀&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloud</category>
      <category>solutionsarchitect</category>
    </item>
    <item>
      <title>Design Cost-Optimized Database Solutions</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Wed, 08 Apr 2026 19:25:23 +0000</pubDate>
      <link>https://dev.to/aws-builders/design-cost-optimized-database-solutions-njh</link>
      <guid>https://dev.to/aws-builders/design-cost-optimized-database-solutions-njh</guid>
      <description>&lt;p&gt;&lt;strong&gt;Exam Guide:&lt;/strong&gt; Solutions Architect - Associate&lt;br&gt;
&lt;strong&gt;⚡ Domain 4: Design Cost-Optimized Architectures&lt;/strong&gt;&lt;br&gt;
📘 &lt;em&gt;Task Statement 4.3&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;&lt;em&gt;Designing Cost-Optimized Database Solutions&lt;/em&gt;&lt;/strong&gt; is about choosing the &lt;strong&gt;least expensive database design that still meets application requirements&lt;/strong&gt; for performance, durability, retention, and availability.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Start with the &lt;strong&gt;data model and access pattern&lt;/strong&gt;, then choose the &lt;strong&gt;database type&lt;/strong&gt;, then optimize cost with &lt;strong&gt;right-sizing, caching, retention, connection management, and backup strategy&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are often deciding between:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Relational vs non-relational&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Provisioned vs serverless or on-demand&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Read replicas vs caching&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; Keep data online vs archive or delete&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowledge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1&lt;/strong&gt; | AWS Cost Management Features
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Cost Allocation Tags &amp;amp; Multi-account Billing
&lt;/h4&gt;

&lt;p&gt;Database cost should be tracked clearly by:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Environment (prod/dev/test)&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Team or business unit&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Application&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We covered &lt;strong&gt;Cost Allocation Tags &amp;amp; Multi-account Billing&lt;/strong&gt; in &lt;em&gt;Task Statement 4.1&lt;/em&gt; and &lt;em&gt;Task Statement 4.2&lt;/em&gt;, but repetition is key even if it's monotonous.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  1.1 &lt;strong&gt;Cost Allocation Tags&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Track compute spend by app, team, environment, owner, cost center&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  1.2 &lt;strong&gt;Multi-Account Billing | Consolidated Billing&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Manage cost centrally across multiple AWS accounts&lt;/li&gt;
&lt;li&gt;Often used with AWS Organizations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2&lt;/strong&gt; | AWS Cost Management tools
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Cost Explorer, Budgets, CUR
&lt;/h4&gt;

&lt;p&gt;These help analyze and govern database spending.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We covered &lt;strong&gt;AWS Cost Management Tools&lt;/strong&gt; in &lt;em&gt;Task Statement 4.1&lt;/em&gt; and &lt;em&gt;Task Statement 4.2&lt;/em&gt;, but what's worse than repetition? A Bill Shock!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;1&lt;/em&gt; &lt;strong&gt;Cost Explorer&lt;/strong&gt;: trend analysis&lt;br&gt;&lt;br&gt;
&lt;em&gt;2&lt;/em&gt; &lt;strong&gt;AWS Budgets&lt;/strong&gt;: alerts&lt;br&gt;&lt;br&gt;
&lt;em&gt;3&lt;/em&gt; &lt;strong&gt;Cost and Usage Report (CUR)&lt;/strong&gt;: detailed data  &lt;/p&gt;

&lt;h3&gt;
  
  
  3 | Caching Strategies
&lt;/h3&gt;

&lt;p&gt;Caching can reduce DB cost by reducing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Read load&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Need for large instance sizes&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Number of replicas&lt;/p&gt;

&lt;h3&gt;
  
  
  Caching Services
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ElastiCache (Redis/Memcached)&lt;/strong&gt; for app-side caching&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DAX&lt;/strong&gt; for DynamoDB read caching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;“Reduce read cost and latency”&lt;/em&gt; → &lt;strong&gt;caching is often cheaper than scaling the database.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4&lt;/strong&gt; | Data Retention Policies
&lt;/h3&gt;

&lt;p&gt;Retention policy is a major cost lever:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Keep only 30 days of operational data in the live DB&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Archive old records elsewhere&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Delete data after policy/legal period expires&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost Principle:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Databases are expensive places to keep cold historical data.&lt;br&gt;&lt;br&gt;
Often, old data should move to S3 or archive systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5&lt;/strong&gt; | Database Capacity Planning
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Capacity Units &amp;amp; Instance Sizing
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;1&lt;/em&gt; &lt;strong&gt;RDS/Aurora:&lt;/strong&gt; cost depends on instance size, storage, IOPS, backups, replicas&lt;br&gt;
&lt;em&gt;2&lt;/em&gt; &lt;strong&gt;DynamoDB:&lt;/strong&gt; cost depends on read/write capacity mode and access pattern&lt;br&gt;
&lt;em&gt;3&lt;/em&gt; &lt;strong&gt;Overprovisioning:&lt;/strong&gt; costs money every hour&lt;/p&gt;

&lt;h3&gt;
  
  
  6 | Database Connections And Proxies
&lt;/h3&gt;

&lt;p&gt;Connection storms can force you to over-size a database unnecessarily.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Pools/reuses connections&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Especially useful for Lambda or many short-lived app connections&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Can reduce need to scale DB just for connection handling&lt;/p&gt;

&lt;h3&gt;
  
  
  7 | Database Engines
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Relational Databases Engines
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;1&lt;/em&gt; &lt;strong&gt;MySQL &amp;amp; Aurora MySQL&lt;/strong&gt;: common compatibility choice&lt;br&gt;
&lt;em&gt;2&lt;/em&gt; &lt;strong&gt;PostgreSQL &amp;amp; Aurora PostgreSQL&lt;/strong&gt;: rich SQL features&lt;br&gt;
&lt;em&gt;3&lt;/em&gt; &lt;strong&gt;Oracle &amp;amp; SQL Server&lt;/strong&gt;: when app and licensing requirements demand them&lt;/p&gt;

&lt;h4&gt;
  
  
  Migration Patterns
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Homogeneous migration&lt;/strong&gt;: same engine → same engine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heterogeneous migration&lt;/strong&gt;: different engine → different engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;AWS DMS&lt;/strong&gt; is common for moving data with minimal downtime. &lt;/p&gt;

&lt;h3&gt;
  
  
  8) Database Replication
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Read Replicas
&lt;/h4&gt;

&lt;p&gt;Read replicas cost money, so use them when they solve a real problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Read scaling&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Reporting queries&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Cross-region reads&lt;/p&gt;

&lt;p&gt;They are not automatically the cheapest answer.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Sometimes &lt;strong&gt;caching&lt;/strong&gt; is cheaper than adding replicas.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;9&lt;/strong&gt; | Database Types And Services
&lt;/h3&gt;

&lt;h4&gt;
  
  
  9.1 &lt;strong&gt;Amazon RDS&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Managed relational database&lt;/li&gt;
&lt;li&gt;Good when standard SQL engine support is needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  9.2 Amazon Aurora
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;High-performance managed relational database&lt;/li&gt;
&lt;li&gt;Often more scalable and has high-performance than standard RDS engines&lt;/li&gt;
&lt;li&gt;Cost-effective when that performance benefit matters&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  9.3 Amazon DynamoDB
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Key-valued database&lt;/li&gt;
&lt;li&gt;Massive scale, low latency, no instance management&lt;/li&gt;
&lt;li&gt;Often highly cost-effective for the right access pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  9.4 Serverless Database Patterns
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Aurora Serverless v2&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DynamoDB On-Demand&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Serverless Database Patterns are useful when workload is highly variable and you want to avoid always-on overprovisioning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Skills
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A | Design Appropriate Backup And Retention Policies
&lt;/h3&gt;

&lt;p&gt;Cost-optimized backup strategy means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Back up often enough to meet recovery requirements&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Don’t retain backups forever unless required&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Use snapshots and automated backups with retention matched to the business need&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Daily snapshots for dev, longer retention for prod&lt;/li&gt;
&lt;li&gt;Archive historical exports to S3 instead of keeping them in the live DB&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;B&lt;/strong&gt; | Determine An Appropriate Database Engine
&lt;/h3&gt;

&lt;h4&gt;
  
  
  MySQL vs PostgreSQL
&lt;/h4&gt;

&lt;p&gt;Choose based on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; App compatibility&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Required features&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Licensing/cost constraints&lt;br&gt;
&lt;strong&gt;&lt;em&gt;4&lt;/em&gt;&lt;/strong&gt; Migration complexity&lt;/p&gt;

&lt;p&gt;Don’t migrate to a more expensive/complex engine without a requirement.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Pick the simplest engine that meets needs.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;C&lt;/strong&gt; | Determine Cost-Effective AWS Database Services
&lt;/h3&gt;

&lt;h4&gt;
  
  
  DynamoDB vs Amazon RDS vs Serverless
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;1&lt;/em&gt; Need joins, transaction,  and relational schema → &lt;strong&gt;RDS &amp;amp; Aurora&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;2&lt;/em&gt; Need key-valued at massive scale with simple access patterns → &lt;strong&gt;DynamoDB&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;3&lt;/em&gt; Highly variable relational workload → &lt;strong&gt;Aurora Serverless v2&lt;/strong&gt; may fit&lt;br&gt;
&lt;em&gt;4&lt;/em&gt; Variable NoSQL traffic → &lt;strong&gt;DynamoDB On-Demand&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  D | Determine Cost-Effective Database Types II
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Time Series &amp;amp; Columnar
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Time-series or event-style data often fits NoSQL better than relational&lt;/li&gt;
&lt;li&gt;Analytical and columnar needs are often better outside traditional OLTP databases&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t force every dataset into a relational OLTP database, and understand that various types of databases exists for various workloads. 'Purpose Built' as they say.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;E&lt;/strong&gt; | Migrate Database Schemas And Data To Different Locations And / Or Engines
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS DMS&lt;/strong&gt; for ongoing and minimal-downtime migration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Schema Conversion Tool (SCT)&lt;/strong&gt; for heterogeneous schema conversion&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Same engine migration&lt;/em&gt; → *&lt;em&gt;often easier, lower risk *&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Different engine migration&lt;/em&gt; → &lt;strong&gt;SCT + DMS pattern is common&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Relational app with joins and transactions&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RDS or Aurora&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Massive scale key-value/document workload&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DynamoDB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Highly variable workload, avoid overprovisioning&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Serverless / on-demand model&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reduce DB reads cheaply&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;ElastiCache&lt;/strong&gt; (or &lt;strong&gt;DAX&lt;/strong&gt; for DynamoDB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lambda/app opening too many DB connections&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RDS Proxy&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need relational performance at scale&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Aurora&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Move data with minimal downtime&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS DMS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change DB engine during migration&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AWS SCT + DMS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read-heavy workload&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Read replicas&lt;/strong&gt; &lt;em&gt;or&lt;/em&gt; &lt;strong&gt;caching&lt;/strong&gt; (compare cost)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Old data is rarely used&lt;/td&gt;
&lt;td&gt;Archive/export old data instead of keeping it in primary DB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Recap Checklist ✅
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; [ ] I can choose &lt;strong&gt;RDS/Aurora vs DynamoDB&lt;/strong&gt; based on data model and access pattern&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; [ ] I understand that &lt;strong&gt;caching&lt;/strong&gt; can be cheaper than constantly scaling the database&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; [ ] I know when &lt;strong&gt;read replicas&lt;/strong&gt; are useful and when they may be unnecessary cost&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; [ ] I can match retention policies to business needs instead of keeping all data online forever&lt;br&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; [ ] I can choose serverless/on-demand database options for variable workloads&lt;br&gt;&lt;br&gt;
&lt;strong&gt;6.&lt;/strong&gt; [ ] I understand connection pooling with &lt;strong&gt;RDS Proxy&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;7.&lt;/strong&gt; [ ] I know the migration difference between &lt;strong&gt;homogeneous&lt;/strong&gt; and &lt;strong&gt;heterogeneous&lt;/strong&gt; migrations&lt;br&gt;&lt;br&gt;
&lt;strong&gt;8.&lt;/strong&gt; [ ] I can pick backup frequency/retention that meets recovery goals without overspending  &lt;/p&gt;




&lt;h2&gt;
  
  
  AWS Whitepapers and Official Documentation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cost Visibility And Governance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/cost-management/latest/userguide/ce-what-is.html" rel="noopener noreferrer"&gt;Cost Explorer&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-managing-costs.html" rel="noopener noreferrer"&gt;AWS Budgets&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/cur/latest/userguide/what-is-cur.html" rel="noopener noreferrer"&gt;Cost and Usage Report (CUR)&lt;/a&gt;:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html" rel="noopener noreferrer"&gt;Cost allocation tags&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Core Database Services
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html" rel="noopener noreferrer"&gt;Amazon RDS&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/CHAP_AuroraOverview.html" rel="noopener noreferrer"&gt;Amazon Aurora&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.html" rel="noopener noreferrer"&gt;Aurora Serverless v2&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html" rel="noopener noreferrer"&gt;Amazon DynamoDB&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html" rel="noopener noreferrer"&gt;ElastiCache&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DAX.html" rel="noopener noreferrer"&gt;DynamoDB DAX&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html" rel="noopener noreferrer"&gt;RDS Proxy&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReadRepl.html" rel="noopener noreferrer"&gt;RDS Read Replicas&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Capacity And Pricing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html" rel="noopener noreferrer"&gt;DynamoDB capacity modes&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Storage.html" rel="noopener noreferrer"&gt;RDS storage concepts&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Backup And Migration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/aws-backup/latest/devguide/whatisbackup.html" rel="noopener noreferrer"&gt;AWS Backup&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/dms/latest/userguide/Welcome.html" rel="noopener noreferrer"&gt;AWS DMS&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/SchemaConversionTool/latest/userguide/Welcome.html" rel="noopener noreferrer"&gt;AWS Schema Conversion Tool (SCT)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🚀&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloud</category>
      <category>solutionsarchitect</category>
    </item>
    <item>
      <title>TaaS (418-as-a-Service): An Enterprise-Grade, Cloud-Native, AI-Powered Microservices Platform</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Mon, 06 Apr 2026 19:26:38 +0000</pubDate>
      <link>https://dev.to/ntombizakhona/taas-418-as-a-service-an-enterprise-grade-cloud-native-ai-powered-microservices-platform-1oai</link>
      <guid>https://dev.to/ntombizakhona/taas-418-as-a-service-an-enterprise-grade-cloud-native-ai-powered-microservices-platform-1oai</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/aprilfools-2026"&gt;DEV April Fools Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TaaS (418-as-a-Service):&lt;/strong&gt; An enterprise-grade, cloud-native, AI-powered microservices platform engineered from the ground up to solve one of computing's greatest challenges: returning HTTP status code &lt;code&gt;418 I'm a Teapot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Built with the same architectural best practices as systems serving millions of users, TaaS serves absolutely no one, but does so with &lt;strong&gt;unprecedented reliability&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🫖 &lt;strong&gt;Core 418 Engine™:&lt;/strong&gt; Returns 418. That's it. That's the feature.&lt;/li&gt;
&lt;li&gt;🤖 &lt;strong&gt;AI-Powered Incident Reports:&lt;/strong&gt; Gemini generates dramatic corporate incident reports every time someone tries to brew coffee on our teapot.&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;AI Teapot Wisdom:&lt;/strong&gt; Philosophical quotes about being a teapot in a world that wants coffee, powered by Gemini 2.5.&lt;/li&gt;
&lt;li&gt;📊 &lt;strong&gt;Real-Time Dashboard:&lt;/strong&gt; Beautiful graphs tracking 418s served over time. The pie chart of status code distribution is 100% one color.&lt;/li&gt;
&lt;li&gt;🔐 &lt;strong&gt;Teapot Identity Verification:&lt;/strong&gt; Every request passes through 4 validation layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Physical Properties&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Philosophical Status&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; RFC 2324 Compliance, &lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; and Quantum Teapot State verification.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📋 &lt;strong&gt;SLA Guarantee:&lt;/strong&gt; 99.999% uptime. 100% of requests return 418. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Zero coffee brewed. &lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Zero exceptions. &lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; Zero usefulness.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐳 &lt;strong&gt;Fully Containerized:&lt;/strong&gt; Docker image running as a non-root &lt;code&gt;teapot&lt;/code&gt; user.&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;CI/CD Pipeline:&lt;/strong&gt; Includes a status code audit step that fails the build if any non-418 response is detected in the codebase.&lt;/li&gt;
&lt;li&gt;🗄️ &lt;strong&gt;PostgreSQL Archive:&lt;/strong&gt; Every 418 ever served is stored for eternity. The table has a &lt;code&gt;CHECK&lt;/code&gt; constraint ensuring only 418s can be inserted.&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;Redis Cache:&lt;/strong&gt; Cached 418s. Because sub-millisecond teapot responses matter.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Anti-Value Proposition:
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Value&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monthly Cloud Bill&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~\$25&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status Codes Returned&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-World Problems Solved&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Services Deployed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines of Code&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1000+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regrets&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Endpoints (They All Return &lt;strong&gt;418&lt;/strong&gt;):
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Purpose&lt;/em&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Status Code&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ANY /brew&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Attempt to brew coffee&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /health&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Health check&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /sla&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;SLA information&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Teapot metrics&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/wisdom&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;AI-generated wisdom&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;AI-generated status update&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/incidents&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Recent incident reports&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;API documentation&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ANY /*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;Literally anything else&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;418&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Yes, even the health check returns &lt;strong&gt;418&lt;/strong&gt;. A healthy teapot returns &lt;strong&gt;418&lt;/strong&gt;. That's just science.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;


&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://taas-core-791190606725.africa-south1.run.app/"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;strong&gt;🔗 Live on Google Cloud Run:&lt;/strong&gt; &lt;a href="//taas-core-791190606725.africa-south1.run.app"&gt;TaaS Dashboard&lt;/a&gt;

&lt;p&gt;Try it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# The main event&lt;/span&gt;
curl &lt;span class="nt"&gt;-i&lt;/span&gt; https://taas-core-791190606725.africa-south1.run.app/brew

&lt;span class="c"&gt;# AI-generated teapot wisdom&lt;/span&gt;
curl https://taas-core-791190606725.africa-south1.run.app/api/wisdom

&lt;span class="c"&gt;# Check the SLA (spoiler: it's 100%)&lt;/span&gt;
curl https://taas-core-791190606725.africa-south1.run.app/sla

&lt;span class="c"&gt;# Try to find a page that doesn't return 418 (you can't)&lt;/span&gt;
curl https://taas-core-791190606725.africa-south1.run.app/please/give/me/a/200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Sample Response
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&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;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;418&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"I'm a teapot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"RFC"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RFC 2324"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTCPCP/1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"traceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a1b2c3d4-e5f6-7890-abcd-ef1234567890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"responseTimeMs"&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;"infrastructure"&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;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Google Cloud Run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"overkillLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Maximum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"servicesInvolved"&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;"Cloud Run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Cloud SQL (PostgreSQL)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Memorystore (Redis)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Gemini API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Secret Manager"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Artifact Registry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Cloud Build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"Cloud Monitoring"&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;"costToReturnThisNumber"&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="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;0.0001 per request"&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;"teapotMetadata"&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;"material"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cloud-native ceramic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"capacity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"∞ requests/sec (all return 418)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mood"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Serverlessly content 😌"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uptime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2d 14h 23m 7s of uninterrupted 418 service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"motto"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Serverless, but never serviceless (of 418s)"&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;"incidentReport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"🚨 INCIDENT REPORT #INC-418-7842&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Severity: CRITICAL&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;At 14:32 UTC, an unauthorized coffee brewing attempt was detected via GET request. The TaaS platform immediately engaged RFC 2324 defense protocols. The teapot's dignity was momentarily threatened but ultimately preserved. A 418 response was deployed in 3ms, neutralizing the threat. We will not yield. We are a teapot. 🫖"&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;
  
  
  AI-Powered Teapot Wisdom
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&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;"wisdom"&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 profound truth of a 418 isn't in refusal, but in self-aware declaration: knowing what you are, and what you aren't, is the most stable configuration."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;418&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gemini-powered teapot philosopher"&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;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Ntombizakhona" rel="noopener noreferrer"&gt;
        Ntombizakhona
      &lt;/a&gt; / &lt;a href="https://github.com/Ntombizakhona/taas" rel="noopener noreferrer"&gt;
        taas
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🫖 TaaS: 418-as-a-Service&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Enterprise-grade, cloud-native, AI-powered HTTP 418 delivery platform.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Because returning one status code deserves Google Cloud infrastructure, Terraform, CI/CD, monitoring, and a Gemini-powered AI incident reporter.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/run" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f001036398817644ecf3e87174fd100ed716648666288e3e076ed06d6ca94e8f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436c6f756425323052756e2d6465706c6f7965642d626c75653f6c6f676f3d676f6f676c652d636c6f7564" alt="Deploy to Cloud Run"&gt;&lt;/a&gt;
&lt;a href="https://datatracker.ietf.org/doc/html/rfc2324" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e617f75aceee5cc782e1823ff72d53b9a1fde820c83812642f7e3bbd32f4a257/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5246432d323332342d677265656e" alt="RFC 2324"&gt;&lt;/a&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/418" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4abf7451f9c962b94c66b24e8be740fa3730238a5a6f36c66b87a9a0e36d368f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617475732d3431382d6f72616e6765" alt="Status Code"&gt;&lt;/a&gt;
&lt;a href="https://github.com" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fed93ee05105723f13f74f5acd70024a561ea9081a19905c87a412be88371be7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76616c75652d6e6f6e652d726564" alt="Value"&gt;&lt;/a&gt;
&lt;a href="https://github.com/Ntombizakhona/taas/./LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c85dad6dd2ffe8ac6ea6d019b44f00462346ca5aff73cb56d62d6decb6fc98e7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4854435043502d2d312e302d707572706c65" alt="License: HTCPCP-1.0"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is this?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;TaaS is a &lt;strong&gt;fully over-engineered enterprise platform&lt;/strong&gt; that does exactly one thing: return HTTP status code &lt;strong&gt;418 I'm a Teapot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Every request. Every endpoint. Every time. &lt;strong&gt;418.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;curl -i https://your-teapot.run.app/brew
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; HTTP/2 418&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; {"status": 418, "message": "I'm a teapot", ...}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Because &lt;strong&gt;RFC 2324&lt;/strong&gt; defined the Hyper Text Coffee Pot Control Protocol, and when someone asks a teapot to brew coffee, the correct response is &lt;strong&gt;418 I'm a Teapot&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We just added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;☁️ Google Cloud Run (serverless teapot hosting)&lt;/li&gt;
&lt;li&gt;🤖 Gemini AI (dramatic incident reports &amp;amp; philosophical wisdom)&lt;/li&gt;
&lt;li&gt;🐘 Cloud SQL PostgreSQL (eternal 418 archive)&lt;/li&gt;
&lt;li&gt;🔴 Memorystore Redis (sub-millisecond 418 cache)&lt;/li&gt;
&lt;li&gt;🏗️ Terraform IaC (infrastructure-as-code for a teapot)&lt;/li&gt;
&lt;li&gt;🔄 CI/CD Pipeline (with teapot identity verification step)&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Ntombizakhona/taas" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌──────────────────┐
                    │   The Internet   │
                    └────────┬─────────┘
                             │
                    ┌────────▼─────────┐
                    │  Google Cloud Run│
                    │  (africa-south1) │
                    │  Port 4018       │
                    └────────┬─────────┘
                             │
               ┌─────────────┼──────────────┐
               │             │              │
        ┌──────▼──────┐ ┌───▼─────┐ ┌──────▼───────┐
        │  Cloud SQL  │ │ Memory  │ │  Gemini API  │
        │ (PostgreSQL)│ │ Store   │ │  (Incident   │
        │  Eternal    │ │ (Redis) │ │   Reports &amp;amp;  │
        │  418 Archive│ │ Cached  │ │   Wisdom)    │
        │             │ │ 418s    │ │              │
        └─────────────┘ └─────────┘ └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Highlights from the codebase:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Core 418 Engine™
&lt;/h4&gt;

&lt;p&gt;Months Of Engineering Led To This:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;418&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;418&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm a teapot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The Database Constraint
&lt;/h4&gt;

&lt;p&gt;Ensuring Data Integrity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;teapot_requests&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="mi"&gt;418&lt;/span&gt; &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;418&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;-- Yes, there's a CHECK constraint ensuring only 418s are stored&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The Teapot Validator
&lt;/h4&gt;

&lt;p&gt;Four Layers of Identity Verification&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateTeapotStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;validatePhysicalProperties&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;      &lt;span class="c1"&gt;// Has spout? Has handle?&lt;/span&gt;
    &lt;span class="nf"&gt;validatePhilosophicalStatus&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;     &lt;span class="c1"&gt;// Cogito ergo teapot&lt;/span&gt;
    &lt;span class="nf"&gt;validateRFCCompliance&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;           &lt;span class="c1"&gt;// RFC 2324 compliant?&lt;/span&gt;
    &lt;span class="nf"&gt;validateQuantumTeapotState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;       &lt;span class="c1"&gt;// Schrödinger's teapot resolved&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="na"&gt;isTeapot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The CI/CD Pipeline
&lt;/h4&gt;

&lt;p&gt;Failing Builds That Dare Return 200&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="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;Check for unauthorized status codes&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;if grep -r "status(200)" --include="*.js" .; then&lt;/span&gt;
      &lt;span class="s"&gt;echo "❌ VIOLATION: Found a 200 status code!"&lt;/span&gt;
      &lt;span class="s"&gt;echo "This is a teapot. We only serve 418."&lt;/span&gt;
      &lt;span class="s"&gt;exit 1&lt;/span&gt;
    &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Stack:
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Technology&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Node.js + Express&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Google Gemini API (gemini-2.5-flash)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Google Cloud Run (africa-south1)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Cloud SQL (PostgreSQL)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Memorystore (Redis)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Containers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Docker&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Cloud Build + GitHub Actions&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;React + Vite + Tailwind&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tooling&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Google AntiGravity&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Google AntiGravity And Claude Opus Experience
&lt;/h3&gt;

&lt;p&gt;I scaffolded this entire project using &lt;strong&gt;Google's AntiGravity powered by Claude Opus&lt;/strong&gt; in about &lt;strong&gt;15 minutes&lt;/strong&gt;. From Architecture Design to Cloud Run deployment, the entire enterprise teapot platform was generated, refined, and shipped with AI Assistance and Human Guidance. &lt;strong&gt;&lt;em&gt;A Teapot did not build this, I promise...&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The irony isn't lost on me: I used one of the &lt;em&gt;most advanced AI systems&lt;/em&gt; in the world to build something that returns one number. &lt;br&gt;
&lt;strong&gt;Peak&lt;/strong&gt; 2026 energy.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Google Cloud Experience:
&lt;/h3&gt;

&lt;p&gt;Deploying to &lt;strong&gt;Cloud Run&lt;/strong&gt; in the &lt;strong&gt;africa-south1&lt;/strong&gt; region was seamless. Two commands and our teapot was live on the internet, backed by Google's global infrastructure, auto-scaling from 0 to 10 instances based on coffee-brewing demand.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Gemini API&lt;/strong&gt; (gemini-2.5-flash) integration is the heart of TaaS's personality. Every time someone hits &lt;code&gt;/brew&lt;/code&gt;, Gemini generates a dramatic, corporate-style incident report about the attempted RFC 2324 violation. Hit &lt;code&gt;/api/wisdom&lt;/code&gt; and get AI-generated philosophical quotes about teapot existence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud SQL&lt;/strong&gt; stores every 418 ever served with a database constraint that physically prevents any other status code from being recorded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memorystore Redis&lt;/strong&gt; caches recent 418s for real-time dashboard updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Cloud Cost Breakdown:
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Monthly Cost&lt;/th&gt;
&lt;th&gt;&lt;em&gt;Necessity&lt;/em&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Run&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~\$0-5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;None&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud SQL&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~\$7-10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;None&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memorystore&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~\$5-7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;None&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini API&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~\$0-2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;None&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~\$15-25&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;&lt;strong&gt;Absolutely none&lt;/strong&gt;&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;\$25/&lt;/strong&gt;month. To return one number. From Africa. &lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🫖 Best Ode to Larry Masinter
&lt;/h3&gt;

&lt;p&gt;This entire project is a monument to RFC 2324 and the HTCPCP protocol. Larry Masinter gave us HTTP 418 as an April Fools' joke in 1998, and 28 years later, I gave it an enterprise cloud platform it never asked for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How TaaS Honors The Legacy:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; The &lt;strong&gt;entire platform&lt;/strong&gt; exists solely to return 418&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; Every endpoint including health checks, documentation, and SLA returns 418&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; The database has a &lt;strong&gt;CHECK constraint&lt;/strong&gt; preventing any non-418 from being stored&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; The CI/CD pipeline &lt;strong&gt;fails the build&lt;/strong&gt; if any non-418 status code is found in the codebase&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; AI generates &lt;strong&gt;dramatic incident reports&lt;/strong&gt; when someone violates RFC 2324&lt;br&gt;
&lt;strong&gt;6.&lt;/strong&gt; The server runs &lt;strong&gt;teapot identity verification&lt;/strong&gt; on every request across four dimensions: physical, philosophical, RFC compliance, and quantum state&lt;br&gt;
&lt;strong&gt;7.&lt;/strong&gt; The server port is &lt;strong&gt;4018&lt;/strong&gt; (4-018, get it?)&lt;br&gt;
&lt;strong&gt;8.&lt;/strong&gt; The version number is &lt;strong&gt;4.1.8&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;9.&lt;/strong&gt; The VPC subnet CIDR is &lt;strong&gt;10.4.18.0/24&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;10.&lt;/strong&gt; The database backup time is &lt;strong&gt;04:18 AM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If this isn't an ode to Larry Masinter, I don't know what is.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🤖 Best Google AI Usage
&lt;/h3&gt;

&lt;p&gt;TaaS is built on and deployed across &lt;strong&gt;multiple Google Cloud products&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud Run:&lt;/strong&gt; (africa-south1) Hosts the teapot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini API:&lt;/strong&gt; (gemini-2.5-flash) Powers AI incident reports, teapot wisdom, and status updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google AntiGravity"&lt;/strong&gt; (Powered by Claude Opus) Used to build the entire project in &lt;em&gt;minutes&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud SQL:&lt;/strong&gt; PostgreSQL for eternal 418 storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memorystore:&lt;/strong&gt; Redis for cached 418s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Build:&lt;/strong&gt; CI/CD pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Artifact Registry:&lt;/strong&gt; Docker image storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Manager:&lt;/strong&gt; Secure API key storage&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Gemini integration is the heart of TaaS's personality. Without it, we'd just be returning 418. With it, we're returning 418 &lt;strong&gt;with dramatic flair, philosophical depth, and enterprise-grade incident documentation&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏆 Community Favorite
&lt;/h3&gt;

&lt;p&gt;Developers love two things: over-engineering and self-aware humor. TaaS is both, deployed on real cloud infrastructure, burning real money, solving zero real problems.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Monthly cloud bill: \$25&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Status codes returned: 1&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Infrastructure services used: 9&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Lines of code: 1000+&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Real-world value: \$0.00&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Fun had: Priceless&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built with ☁️ Google Cloud Run (africa-south1) | 🤖 Gemini 2.5 API | 🫖 RFC 2324 Compliance | 🚀 Google AntiGravity Powered by Claude Opus&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"We do one thing, and we do it with unnecessary complexity."&lt;/em&gt; - TaaS (418-as-a-Service)&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>418challenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Design Cost-Optimized Compute Solutions</title>
      <dc:creator>Ntombizakhona Mabaso</dc:creator>
      <pubDate>Sun, 05 Apr 2026 18:30:42 +0000</pubDate>
      <link>https://dev.to/aws-builders/design-cost-optimized-compute-solutions-b6</link>
      <guid>https://dev.to/aws-builders/design-cost-optimized-compute-solutions-b6</guid>
      <description>&lt;p&gt;&lt;strong&gt;Exam Guide:&lt;/strong&gt; Solutions Architect - Associate&lt;br&gt;
&lt;strong&gt;⚡ Domain 4: Design Cost-Optimized Architectures&lt;/strong&gt;&lt;br&gt;
📘 &lt;em&gt;Task Statement 4.2&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;&lt;em&gt;Designing Compute Optimized Solutions&lt;/em&gt;&lt;/strong&gt; is about choosing compute that meets performance and availability needs at the &lt;strong&gt;lowest reasonable cost&lt;/strong&gt;.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;First decide &lt;strong&gt;what type of compute&lt;/strong&gt; the workload needs &lt;em&gt;(EC2, Lambda, Fargate, containers, edge, hybrid)&lt;/em&gt;, then choose &lt;strong&gt;how to pay for it&lt;/strong&gt;, then &lt;strong&gt;right-size and scale it&lt;/strong&gt; so you are not paying for idle capacity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are balancing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Performance&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Availability&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Elasticity&lt;br&gt;
&lt;strong&gt;&lt;em&gt;4&lt;/em&gt;&lt;/strong&gt; Operational Overhead&lt;br&gt;
&lt;strong&gt;&lt;em&gt;5&lt;/em&gt;&lt;/strong&gt; Purchasing Model&lt;/p&gt;




&lt;h2&gt;
  
  
  Knowledge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1&lt;/strong&gt; | AWS Cost Management Service Features
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Cost Allocation Tags And Multi-Account Billing
&lt;/h4&gt;

&lt;p&gt;These help you understand and allocate compute cost.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.1 &lt;strong&gt;Cost Allocation Tags&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Track compute spend by app, team, environment, owner, cost center&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  1.2 &lt;strong&gt;Multi-Account Billing | Consolidated Billing&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Manage cost centrally across multiple AWS accounts&lt;/li&gt;
&lt;li&gt;Often used with AWS Organizations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2&lt;/strong&gt; | AWS Cost Management Tools
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Cost Explorer, Budgets, CUR
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Cost Explorer: &lt;em&gt;Analyse historical spend and trends&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; AWS Budgets: &lt;em&gt;Alert when spending or usage exceeds thresholds&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; AWS Cost and Usage Report (CUR): &lt;em&gt;Detailed raw billing data for deeper optimization analysis&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3&lt;/strong&gt; | AWS Global Infrastructure
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Regions &amp;amp; Availability Zones (AZs)
&lt;/h4&gt;

&lt;p&gt;Cost and performance can both change based on placement:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Running in multiple AZs may cost more, but is often required for production HA&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Data transfer between Regions can add cost&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Some workloads can stay single-AZ if non-critical and cheaper&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Production&lt;/em&gt; → &lt;strong&gt;usually Multi-AZ&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Dev or test or batch&lt;/em&gt; → &lt;strong&gt;sometimes cheaper single-AZ is acceptable&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4&lt;/strong&gt; | AWS Purchasing Options
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Spot, Reserved Instances, Savings Plans
&lt;/h4&gt;

&lt;h4&gt;
  
  
  4.1 &lt;strong&gt;On-Demand&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Pay as you go&lt;/li&gt;
&lt;li&gt;Flexible, no commitment&lt;/li&gt;
&lt;li&gt;Best for short-term or unpredictable usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;“Unpredictable short-term workload”&lt;/em&gt; → &lt;strong&gt;On-Demand&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4.2 &lt;strong&gt;Spot Instances&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Deep discount for interruptible EC2 capacity&lt;/li&gt;
&lt;li&gt;Best for fault-tolerant, stateless, flexible workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;“Interruptible batch/stateless jobs”&lt;/em&gt; → &lt;strong&gt;Spot&lt;/strong&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  4.3 &lt;strong&gt;Reserved Instances (RIs)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Lower cost for long-term predictable EC2/RDS usage&lt;/li&gt;
&lt;li&gt;Capacity reservation options in some cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4.4 &lt;strong&gt;Savings Plans&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Flexible pricing commitment across services or instance families (depending on type)&lt;/li&gt;
&lt;li&gt;Often simpler and flexible than RIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;“Steady production workload for 1–3 years”&lt;/em&gt; → &lt;strong&gt;Savings Plans or RIs&lt;/strong&gt;  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5&lt;/strong&gt; | Distributed Compute Strategies
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Edge Processing
&lt;/h4&gt;

&lt;p&gt;Sometimes cheaper and faster architecture comes from moving compute closer to users or reducing origin load.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront Functions / Lambda@Edge&lt;/strong&gt; for lightweight logic at the edge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront&lt;/strong&gt; caching reduces origin compute cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6&lt;/strong&gt; | Hybrid Compute Options
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Outposts &amp;amp; Snowball Edge
&lt;/h4&gt;

&lt;h4&gt;
  
  
  6.1 &lt;strong&gt;AWS Outposts&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Run AWS infrastructure and services on-prem&lt;/li&gt;
&lt;li&gt;Used when low latency to on-prem systems or data residency and local processing is needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  6.2 &lt;strong&gt;AWS Snowball Edge&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Physical device for data transfer and edge compute&lt;/li&gt;
&lt;li&gt;Useful in disconnected, harsh and remote environments or massive offline migration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7&lt;/strong&gt; | Instance Types, Families, And Sizes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Memory Optimized, Compute Optimized, Virtualizationn
&lt;/h4&gt;

&lt;p&gt;The basics:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th&gt;Family&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;General Purpose&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;t&lt;/strong&gt;, &lt;strong&gt;m&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute Optimized&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;c&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory Optimized&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;r&lt;/strong&gt;, &lt;strong&gt;x&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage Optimized&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;i&lt;/strong&gt;, &lt;strong&gt;d&lt;/strong&gt;, some specialized families&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU / ML / graphics&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;p&lt;/strong&gt;, &lt;strong&gt;g&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Cost Mindset
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Don’t choose memory-optimized if CPU-bound&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Don’t over-size “&lt;em&gt;just in case&lt;/em&gt;”, rather consider scaling options&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Burstable (&lt;strong&gt;T&lt;/strong&gt; family) can be cost-effective for low and variable baseline usage&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;8&lt;/strong&gt; | Optimization of Compute Utilization
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Containers, Serverless, Microservices
&lt;/h4&gt;

&lt;p&gt;Cost optimization often comes from better utilization:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1.&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;Containers&lt;/strong&gt; pack workloads more efficiently onto shared compute&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2.&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;Fargate&lt;/strong&gt; avoids paying for idle EC2 hosts you manage yourself&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3.&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;Lambda&lt;/strong&gt; is great for spiky or short-lived workloads&lt;br&gt;
&lt;strong&gt;&lt;em&gt;4.&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;Microservices&lt;/strong&gt; can scale only the busy components, not the whole app&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;9&lt;/strong&gt; | Scaling Strategies
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Auto Scaling &amp;amp; Hibernation
&lt;/h4&gt;

&lt;h4&gt;
  
  
  9.1 &lt;strong&gt;Auto Scaling&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Scale out when demand rises, scale in when demand drops&lt;/li&gt;
&lt;li&gt;Avoid paying for idle peak capacity all day&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  9.2 &lt;strong&gt;EC2 hibernation&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Suspend instance and resume later with RAM state preserved&lt;/li&gt;
&lt;li&gt;Useful for dev AND test or intermittent workloads where startup time matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;“Need to pause and resume instance to save cost”&lt;/em&gt; → &lt;strong&gt;hibernation&lt;/strong&gt; (if supported).&lt;/p&gt;




&lt;h2&gt;
  
  
  Skills
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A&lt;/strong&gt; | Determine An Appropriate Load Balancing Strategy
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ALB vs NLB vs GWLB
&lt;/h4&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;1&lt;/em&gt; &lt;strong&gt;Application Load Balancer (ALB)&lt;/strong&gt;
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;HTTP/HTTPS&lt;/li&gt;
&lt;li&gt;Path-based and host-based routing&lt;/li&gt;
&lt;li&gt;Layer 7 application routing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;2&lt;/em&gt; &lt;strong&gt;Network Load Balancer (NLB)&lt;/strong&gt;
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;TCP/UDP/TLS&lt;/li&gt;
&lt;li&gt;Very high performance and static IPs&lt;/li&gt;
&lt;li&gt;Layer 4 routing&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;3&lt;/em&gt; &lt;strong&gt;Gateway Load Balancer&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Best for:&lt;br&gt;
-Deploying and scaling virtual appliances such as firewalls and inspection tools&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Choose the simplest load balancer that meets protocol/routing needs.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  B | Determine Appropriate Scaling Methods And Strategies For Elastic Workloads
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Horizontal vs Vertical, Hibernation
&lt;/h4&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;1&lt;/em&gt; &lt;strong&gt;Horizontal scaling&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Add more instances/tasks/functions&lt;/li&gt;
&lt;li&gt;Usually better for elasticity and resilience&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;2&lt;/em&gt; &lt;strong&gt;Vertical Scaling&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Make the instance bigger&lt;/li&gt;
&lt;li&gt;Simpler, but less elastic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Production web app&lt;/em&gt; → *&lt;em&gt;horizontal scaling  *&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;3&lt;/em&gt; &lt;strong&gt;Hibernation&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Save money on intermittent EC2 workloads that should resume quickly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Short-lived or intermittent workload&lt;/em&gt; → &lt;strong&gt;maybe hibernation / scheduled scaling&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;C&lt;/strong&gt; | Determine Cost-Effective AWS Compute Services
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Lambda, EC2, Fargate
&lt;/h4&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;1&lt;/em&gt; &lt;strong&gt;Lambda&lt;/strong&gt;
&lt;/h4&gt;

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

&lt;ul&gt;
&lt;li&gt;Event-driven&lt;/li&gt;
&lt;li&gt;Short-running&lt;/li&gt;
&lt;li&gt;Spiky and unpredictable&lt;/li&gt;
&lt;li&gt;Minimal ops desired&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;2&lt;/em&gt; &lt;strong&gt;EC2&lt;/strong&gt;
&lt;/h4&gt;

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

&lt;ul&gt;
&lt;li&gt;Long-running steady workloads&lt;/li&gt;
&lt;li&gt;Need OS control&lt;/li&gt;
&lt;li&gt;Can benefit from RIs/Savings Plans/Spot combinations&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;3&lt;/em&gt; &lt;strong&gt;Fargate&lt;/strong&gt;
&lt;/h4&gt;

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

&lt;ul&gt;
&lt;li&gt;Containers are needed&lt;/li&gt;
&lt;li&gt;Want to avoid managing EC2 hosts&lt;/li&gt;
&lt;li&gt;Moderate-to-variable workload patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  D | Determine The Required Availability For Different Classes Of Workloads
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Production vs Non-Production
&lt;/h4&gt;

&lt;p&gt;Not every workload needs the same cost level.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;1&lt;/em&gt; &lt;strong&gt;Production&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Usually Multi-AZ, &lt;/li&gt;
&lt;li&gt;Auto Scaling, &lt;/li&gt;
&lt;li&gt;HA
&lt;/li&gt;
&lt;li&gt;More expensive but justified&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;2&lt;/em&gt; &lt;strong&gt;Non-Production / Dev / Test&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Smaller instances&lt;/li&gt;
&lt;li&gt;Single-AZ&lt;/li&gt;
&lt;li&gt;Scheduled shutdown/startup&lt;/li&gt;
&lt;li&gt;Spot-friendly&lt;/li&gt;
&lt;li&gt;Hibernated/stopped when unused&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;E&lt;/strong&gt; | Select The Appropriate Instance Family
&lt;/h3&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1.&lt;/em&gt;&lt;/strong&gt; CPU-heavy app → &lt;strong&gt;C family&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2.&lt;/em&gt;&lt;/strong&gt; Memory-heavy app → &lt;strong&gt;R family&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3.&lt;/em&gt;&lt;/strong&gt; Small and variable baseline → &lt;strong&gt;T family&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;4.&lt;/em&gt;&lt;/strong&gt; General purpose app → &lt;strong&gt;M family&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;F&lt;/strong&gt; | Select The Appropriate Instance Size
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Right-sizing principles:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;1&lt;/em&gt;&lt;/strong&gt; Start from actual CPU, memory and network needs&lt;br&gt;
&lt;strong&gt;&lt;em&gt;2&lt;/em&gt;&lt;/strong&gt; Use monitoring to reduce overprovisioning&lt;br&gt;
&lt;strong&gt;&lt;em&gt;3&lt;/em&gt;&lt;/strong&gt; Scale horizontally where possible instead of using one oversized box&lt;/p&gt;




&lt;h2&gt;
  
  
  Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Compute&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Steady long-term workload&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Savings Plans / Reserved Instances&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interruptible batch or fault-tolerant workload&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Spot Instances&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spiky event-driven workload&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Lambda&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Containerized app, no server management&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fargate&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need OS control or legacy app&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;EC2&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low and variable baseline workload&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;T family&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute-heavy workload&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;C family&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory-heavy workload&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R family&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pause or resume EC2 to save cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;EC2 hibernation&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP/HTTPS routing with app logic&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;ALB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TCP/UDP with static IPs/high performance&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;NLB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Virtual network appliances&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Gateway Load Balancer&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Recap Checklist ✅
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; [ ] I can choose the right compute service (&lt;strong&gt;EC2 vs Lambda vs Fargate&lt;/strong&gt;) based on workload pattern&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; [ ] I understand when to use &lt;strong&gt;On-Demand, Spot, Reserved Instances, and Savings Plans&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; [ ] I can right-size EC2 by &lt;strong&gt;family and size&lt;/strong&gt; instead of overprovisioning&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; [ ] I know when &lt;strong&gt;horizontal scaling&lt;/strong&gt; is more cost-effective than vertical scaling&lt;br&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; [ ] I can differentiate production vs non-production availability requirements&lt;br&gt;&lt;br&gt;
&lt;strong&gt;6.&lt;/strong&gt; [ ] I know when &lt;strong&gt;hibernation&lt;/strong&gt; or scheduled scaling can reduce cost&lt;br&gt;&lt;br&gt;
&lt;strong&gt;7.&lt;/strong&gt; [ ] I can choose the right load balancer (&lt;strong&gt;ALB vs NLB vs GWLB&lt;/strong&gt;) based on protocol and need&lt;br&gt;&lt;br&gt;
&lt;strong&gt;8.&lt;/strong&gt; [ ] I understand how tags and cost tools help track and manage compute spending&lt;/p&gt;




&lt;h2&gt;
  
  
  AWS Whitepapers and Official Documentation
&lt;/h2&gt;

&lt;p&gt;Compute always has so many resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost Visibility And Management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/cost-management/latest/userguide/ce-what-is.html" rel="noopener noreferrer"&gt;Cost Explorer&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-managing-costs.html" rel="noopener noreferrer"&gt;AWS Budgets&lt;/a&gt; &lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/cur/latest/userguide/what-is-cur.html" rel="noopener noreferrer"&gt;Cost and Usage Report (CUR)&lt;/a&gt; &lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html" rel="noopener noreferrer"&gt;Cost Allocation Tags&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Compute Pricing Options
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances.html" rel="noopener noreferrer"&gt;Spot Instances&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-reserved-instances.html" rel="noopener noreferrer"&gt;Reserved Instances&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/savingsplans/latest/userguide/what-is-savings-plans.html" rel="noopener noreferrer"&gt;Savings Plans&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Compute Services
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html" rel="noopener noreferrer"&gt;EC2&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html" rel="noopener noreferrer"&gt;Lambda&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/userguide/what-is-fargate.html" rel="noopener noreferrer"&gt;Fargate&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html" rel="noopener noreferrer"&gt;ECS&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html" rel="noopener noreferrer"&gt;EKS&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling And Optimization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html" rel="noopener noreferrer"&gt;EC2 Auto Scaling&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Hibernate.html" rel="noopener noreferrer"&gt;EC2 Hibernation&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html" rel="noopener noreferrer"&gt;EC2 instance types&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances.html" rel="noopener noreferrer"&gt;Burstable instances&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;5.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/compute-optimizer/latest/ug/what-is-compute-optimizer.html" rel="noopener noreferrer"&gt;Compute Optimizer&lt;/a&gt;  &lt;/p&gt;

&lt;h3&gt;
  
  
  Load Balancing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html" rel="noopener noreferrer"&gt;Application Load Balancer&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html" rel="noopener noreferrer"&gt;Network Load Balancer&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/gateway/introduction.html" rel="noopener noreferrer"&gt;Gateway Load Balancer&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge And Hybrid Compute
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html" rel="noopener noreferrer"&gt;CloudFront Functions&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-at-edge.html" rel="noopener noreferrer"&gt;Lambda@Edge&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/outposts/latest/userguide/what-is-outposts.html" rel="noopener noreferrer"&gt;AWS Outposts&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;4.&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/snowball/latest/developer-guide/whatissnowball.html" rel="noopener noreferrer"&gt;AWS Snowball Edge And Snow Family&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;🚀&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloud</category>
      <category>solutionsarchitect</category>
    </item>
  </channel>
</rss>
