<?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: Rey Abolofia</title>
    <description>The latest articles on DEV Community by Rey Abolofia (@purple4reina).</description>
    <link>https://dev.to/purple4reina</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%2F1157940%2F01a21ca7-0d67-4104-995b-39983cdd95c6.png</url>
      <title>DEV Community: Rey Abolofia</title>
      <link>https://dev.to/purple4reina</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/purple4reina"/>
    <language>en</language>
    <item>
      <title>Reducing AWS Lambda Cold Starts</title>
      <dc:creator>Rey Abolofia</dc:creator>
      <pubDate>Fri, 24 May 2024 20:01:47 +0000</pubDate>
      <link>https://dev.to/aws-builders/reducing-aws-lambda-cold-starts-3eea</link>
      <guid>https://dev.to/aws-builders/reducing-aws-lambda-cold-starts-3eea</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;AWS Lambda functions with large dependencies can suffer from significant cold start times due to the time it takes to import these dependencies. In this post, we'll explore a simple yet effective way to reduce Python cold start times without changing a line of code by precompiling dependencies into bytecode. We'll cover the following topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding Python bytecode and &lt;code&gt;*.pyc&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Precompiling dependencies to reduce init duration&lt;/li&gt;
&lt;li&gt;Using Python optimization levels for further improvements&lt;/li&gt;
&lt;li&gt;Reducing memory overhead with &lt;code&gt;PYTHONNODEBUGRANGES=1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding Python Bytecode and &lt;code&gt;*.pyc&lt;/code&gt; Files
&lt;/h2&gt;

&lt;p&gt;When Python loads source code for the first time, it &lt;a href="https://peps.python.org/pep-3147/#background"&gt;compiles it to bytecode&lt;/a&gt; and saves it to &lt;code&gt;*.pyc&lt;/code&gt; files in &lt;code&gt;__pycache__&lt;/code&gt; directories. On subsequent loads, Python will use these precompiled &lt;code&gt;*.pyc&lt;/code&gt; files instead of recompiling the source code, saving time.&lt;/p&gt;

&lt;p&gt;By precompiling dependencies and removing the original &lt;code&gt;*.py&lt;/code&gt; files, we can bypass the bytecode compilation step during function initialization. This can significantly reduce init duration. For example, a simple handler with &lt;code&gt;import numpy as np&lt;/code&gt; can see an init duration reduction of approximately 20%.&lt;/p&gt;

&lt;p&gt;Removing &lt;code&gt;*.py&lt;/code&gt; files affects the detail in tracebacks when exceptions occur. With &lt;code&gt;*.py&lt;/code&gt; files, tracebacks include the relevant source code lines. Without &lt;code&gt;*.py&lt;/code&gt; files, tracebacks only display line numbers, requiring you to refer to your version-controlled source code for debugging. For custom code not in version control, consider keeping the relevant &lt;code&gt;*.py&lt;/code&gt; files to aid in debugging. For third-party packages, removing &lt;code&gt;*.py&lt;/code&gt; files can improve cold start times at the cost of slightly less detailed tracebacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Faster imports during runtime&lt;/li&gt;
&lt;li&gt;Reduced package size by removing &lt;code&gt;*.py&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Same &lt;code&gt;*.pyc&lt;/code&gt; files work on any OS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to
&lt;/h3&gt;

&lt;p&gt;precompile dependencies and remove &lt;code&gt;*.py&lt;/code&gt; files:&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="nv"&gt;$ &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; compileall &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.py"&lt;/span&gt; &lt;span class="nt"&gt;-delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Caution
&lt;/h3&gt;

&lt;p&gt;Always test your code after precompilation, as some packages do rely on the presence of &lt;code&gt;*.py&lt;/code&gt; files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Python Optimization Levels
&lt;/h2&gt;

&lt;p&gt;Python offers &lt;a href="https://docs.python.org/3/using/cmdline.html#cmdoption-O"&gt;optimization levels&lt;/a&gt; that can further improve init and runtime duration by removing debug statements and docstrings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Optimization Level&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-O&lt;/td&gt;
&lt;td&gt;Removes assert statements and code blocks that rely on &lt;code&gt;__debug__&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-OO&lt;/td&gt;
&lt;td&gt;Removes assert statements, &lt;code&gt;__debug__&lt;/code&gt; code blocks, and docstrings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  How to
&lt;/h3&gt;

&lt;p&gt;precompile with optimization level 2:&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="nv"&gt;$ &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; compileall &lt;span class="nt"&gt;-o&lt;/span&gt; 2 &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.py"&lt;/span&gt; &lt;span class="nt"&gt;-delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Caution
&lt;/h3&gt;

&lt;p&gt;Test your code thoroughly, as optimization levels may introduce subtle bugs if your business logic relies on assert statements or docstrings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reducing Memory Overhead with &lt;code&gt;PYTHONNODEBUGRANGES=1&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In Python 3.11+, you can use the &lt;a href="https://docs.python.org/3/using/cmdline.html#envvar-PYTHONNODEBUGRANGES"&gt;&lt;code&gt;PYTHONNODEBUGRANGES=1&lt;/code&gt;&lt;/a&gt; environment variable to disable the inclusion of column numbers in tracebacks. This reduces memory overhead but sacrifices the ability to pinpoint the exact location of exceptions on a given line of code.&lt;/p&gt;

&lt;p&gt;Example traceback with debug ranges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "hello.py", line 1, in &amp;lt;module&amp;gt;
    print(f"Hello world! {1/0}")
                          ~^~
ZeroDivisionError: division by zero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example traceback without debug ranges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
  File "hello.py", line 1, in &amp;lt;module&amp;gt;
    print(f"Hello world! {1/0}")
ZeroDivisionError: division by zero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reduced memory overhead&lt;/li&gt;
&lt;li&gt;Reduced package sizes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to
&lt;/h3&gt;

&lt;p&gt;precompile with optimization level 2 and no debug ranges:&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="nv"&gt;$ PYTHONNODEBUGRANGES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 python &lt;span class="nt"&gt;-m&lt;/span&gt; compileall &lt;span class="nt"&gt;-o&lt;/span&gt; 2 &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.py"&lt;/span&gt; &lt;span class="nt"&gt;-delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;By precompiling dependencies, using optimization levels, and disabling debug ranges, you can significantly reduce cold start times in your AWS Lambda Python functions. These techniques can lead to over 20% faster startup times, allowing your functions to respond more quickly to events. Try these optimizations in your own functions and see the performance improvements for yourself!&lt;/p&gt;

</description>
      <category>coldstart</category>
      <category>python</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Serverless wsgi zipped packages</title>
      <dc:creator>Rey Abolofia</dc:creator>
      <pubDate>Sun, 10 Sep 2023 22:14:14 +0000</pubDate>
      <link>https://dev.to/aws-builders/serverless-wsgi-zipped-packages-3hm0</link>
      <guid>https://dev.to/aws-builders/serverless-wsgi-zipped-packages-3hm0</guid>
      <description>&lt;p&gt;I just spent the longest time trying to debug why my Flask app run on AWS Lambda wasn't working correctly. Consistently, I was seeing the error,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No module named 'wsgi_handler'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was able to track this down to how I am packaging my function. I create a zip file containing my function code and its requirements. Using Serverless Framework, this looks like,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package:
  artifact: .package/package.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was then using the plugin &lt;code&gt;serverless-wsgi&lt;/code&gt; to serve my Flask app.&lt;/p&gt;

&lt;p&gt;The problem was that the &lt;code&gt;serverless-wsgi&lt;/code&gt; plugin was unable to include its required &lt;code&gt;wsgi_handler&lt;/code&gt; code file. This is because my code was already zipped before running &lt;code&gt;serverless deploy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The solution was to remove the &lt;code&gt;serverless-wsgi&lt;/code&gt; plugin and wrap the handler manually.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;serverless-wsgi&lt;/code&gt; as a python dependency
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  $ pip install serverless-wsgi
  $ pip freeze &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the lambda handler
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="c1"&gt;# file handlers/ui_handler/__init__.py
&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;serverless_wsgi&lt;/span&gt;

  &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;handlers.ui_handler.app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&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="n"&gt;serverless_wsgi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Using Serverless Framework, set the handler to this function
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  functions:
    ui:
      handler: handlers/ui_handler.handle
      url: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
