<?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: Siddharth Mishra</title>
    <description>The latest articles on DEV Community by Siddharth Mishra (@siddharth912).</description>
    <link>https://dev.to/siddharth912</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4123081%2Ffc4094ca-9935-4410-9f82-8bbb8828a3a5.jpg</url>
      <title>DEV Community: Siddharth Mishra</title>
      <link>https://dev.to/siddharth912</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siddharth912"/>
    <language>en</language>
    <item>
      <title>Catching a Silent AWS Failure: A Serverless Daily Report for Suspended Auto Scaling Groups</title>
      <dc:creator>Siddharth Mishra</dc:creator>
      <pubDate>Sun, 13 Sep 2026 11:23:30 +0000</pubDate>
      <link>https://dev.to/siddharth912/catching-a-silent-aws-failure-a-serverless-daily-report-for-suspended-auto-scaling-groups-28ng</link>
      <guid>https://dev.to/siddharth912/catching-a-silent-aws-failure-a-serverless-daily-report-for-suspended-auto-scaling-groups-28ng</guid>
      <description>&lt;h1&gt;
  
  
  Catching a Silent AWS Failure: A Serverless Daily Report for Suspended Auto Scaling Groups
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;How I built a zero-cost, zero-server monitoring alert with Lambda, EventBridge, and SES, and the two production bugs I hit along the way.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The silent failure nobody watches
&lt;/h2&gt;

&lt;p&gt;Amazon EC2 Auto Scaling Groups (ASGs) have a feature that's incredibly useful during incidents and quietly dangerous afterward: you can &lt;strong&gt;suspend&lt;/strong&gt; individual scaling processes like &lt;code&gt;Launch&lt;/code&gt;, &lt;code&gt;Terminate&lt;/code&gt;, &lt;code&gt;HealthCheck&lt;/code&gt;, or &lt;code&gt;AZRebalance&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Engineers suspend these all the time, to freeze capacity during a deployment, to stop instance churn while debugging, to hold a group steady during a migration. The problem is what happens next: &lt;strong&gt;someone forgets to resume them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A group with &lt;code&gt;Launch&lt;/code&gt; suspended won't add capacity when traffic spikes. A group with &lt;code&gt;HealthCheck&lt;/code&gt; suspended won't replace unhealthy instances. Nothing alarms on this by default. You often discover it during the exact incident where you needed scaling to work.&lt;/p&gt;

&lt;p&gt;I wanted a simple, reliable way to surface this every single day. Here's what I built.&lt;/p&gt;




&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;The whole thing is serverless and costs effectively nothing to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Amazon EventBridge (daily cron)
        |
        v
   AWS Lambda (Python + boto3)  --- scans all ASGs for suspended processes
        |
        v
   Amazon SES  --- emails a branded HTML report
        |
        v
     Your inbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge&lt;/strong&gt; triggers the function on a daily schedule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda&lt;/strong&gt; does the work: list every ASG across the configured regions, filter to those with suspended processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SES&lt;/strong&gt; delivers a formatted HTML table so the report is readable at a glance, not a wall of JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No servers, no agents, no cron box to maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  The core logic
&lt;/h2&gt;

&lt;p&gt;The heart of the function is a paginated scan of Auto Scaling Groups, keeping only the ones with suspended processes:&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;boto3&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_suspended_asgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;client&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;autoscaling&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;paginator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_paginator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;describe_auto_scaling_groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;suspended&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;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paginator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paginate&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;asg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&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;AutoScalingGroups&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;processes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asg&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;SuspendedProcesses&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;processes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;suspended&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;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;region&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;asg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AutoScalingGroupName&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_names&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;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ProcessName&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;processes&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;desired&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asg&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;DesiredCapacity&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;min&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asg&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;MinSize&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;max&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asg&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;MaxSize&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="n"&gt;suspended&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the &lt;strong&gt;paginator&lt;/strong&gt; matters, accounts with many ASGs return paged results, and a naive single call would silently miss groups.&lt;/p&gt;

&lt;p&gt;The results are rendered into an HTML table and sent through SES. The email shows each affected ASG, which processes are suspended, and the min/desired/max capacity so you can judge the blast radius immediately. There's also a &lt;code&gt;NOTIFY_WHEN_EMPTY&lt;/code&gt; toggle so you can choose between "only email me when something's wrong" and "email me a daily all-clear."&lt;/p&gt;




&lt;h2&gt;
  
  
  Deploying with just the AWS CLI
&lt;/h2&gt;

&lt;p&gt;I kept the deployment dependency-free, no framework, just a bash script wrapping the AWS CLI. The essentials:&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;# Package the function&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;src &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; zip &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ../function.zip handler.py

&lt;span class="c"&gt;# Create the Lambda (first deploy)&lt;/span&gt;
aws lambda create-function &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; asg-suspend-report &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--runtime&lt;/span&gt; python3.12 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROLE_ARN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--handler&lt;/span&gt; handler.handler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt; 120 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--zip-file&lt;/span&gt; fileb://function.zip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; ap-south-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EventBridge and the IAM role can be created the same way, or once manually. That's the whole footprint.&lt;/p&gt;




&lt;h2&gt;
  
  
  The two bugs (the fun part)
&lt;/h2&gt;

&lt;p&gt;A tutorial where everything works first try teaches you nothing. Here's what actually happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 1: &lt;code&gt;Runtime.ImportModuleError: No module named 'lambda_function'&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The first invocation failed immediately:&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;[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function':
No module named 'lambda_function'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cause: Lambda's &lt;strong&gt;handler&lt;/strong&gt; setting still pointed at the default &lt;code&gt;lambda_function.lambda_handler&lt;/code&gt;, but my code lived in &lt;code&gt;handler.py&lt;/code&gt; with a function named &lt;code&gt;handler&lt;/code&gt;. The handler string must be &lt;code&gt;&amp;lt;file&amp;gt;.&amp;lt;function&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws lambda update-function-configuration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; asg-suspend-report &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--handler&lt;/span&gt; handler.handler &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; ap-south-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lesson: the handler string is a &lt;strong&gt;file-and-function path&lt;/strong&gt;, and it's easy for it to drift from your actual code, especially if the function was created with console defaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 2: &lt;code&gt;AccessDenied&lt;/code&gt; on &lt;code&gt;autoscaling:DescribeAutoScalingGroups&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Next invocation got further, then failed on permissions:&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;[ERROR] ClientError: An error occurred (AccessDenied) when calling the
DescribeAutoScalingGroups operation: ... is not authorized to perform:
autoscaling:DescribeAutoScalingGroups
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution role had a basic trust policy but was missing the actual permissions the code needs. The fix, a minimal inline policy:&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;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"autoscaling:DescribeAutoScalingGroups"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ses:SendEmail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ses:SendRawEmail"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;DescribeAutoScalingGroups&lt;/code&gt; doesn't support resource-level restrictions, so it requires &lt;code&gt;Resource: "*"&lt;/code&gt;. SES can be scoped tighter to a verified identity ARN for stricter least privilege.&lt;/p&gt;

&lt;p&gt;Lesson: &lt;strong&gt;least privilege means you'll hit AccessDenied&lt;/strong&gt;, and that's a good thing. The errors tell you exactly which action to grant, one at a time, instead of over-provisioning with a wildcard.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this small project demonstrates
&lt;/h2&gt;

&lt;p&gt;It's not a huge system, but it exercises a surprising amount of real cloud engineering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serverless event-driven design&lt;/strong&gt; (EventBridge → Lambda → SES)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The AWS SDK&lt;/strong&gt; with correct pagination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM least-privilege&lt;/strong&gt; debugging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda packaging and configuration&lt;/strong&gt; gotchas&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure delivered as a repeatable script&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are exactly the day-to-day skills that keep production healthy.&lt;/p&gt;




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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Suspended ASG processes are a silent risk.&lt;/strong&gt; If your team uses them during incidents, monitor for ones left behind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless is perfect for periodic checks&lt;/strong&gt;, no infrastructure to babysit, effectively free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read your error types.&lt;/strong&gt; &lt;code&gt;Runtime.ImportModuleError&lt;/code&gt; is a config problem; &lt;code&gt;AccessDenied&lt;/code&gt; is an IAM problem. Each points straight at the fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small automations have outsized value.&lt;/strong&gt; This one can prevent a genuinely bad day for a few lines of Python.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading. I write about AWS, serverless, and cloud operations. Connect with me if you're building similar things.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
