<?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: Jehiel Martinez</title>
    <description>The latest articles on DEV Community by Jehiel Martinez (@jehielmartinez).</description>
    <link>https://dev.to/jehielmartinez</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%2F138475%2F4fdf7b3c-114e-49f1-b937-0d635f5b3d30.jpeg</url>
      <title>DEV Community: Jehiel Martinez</title>
      <link>https://dev.to/jehielmartinez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jehielmartinez"/>
    <language>en</language>
    <item>
      <title>Building a Scalable Serverless Image Processing Pipeline with AWS SQS and Lambda</title>
      <dc:creator>Jehiel Martinez</dc:creator>
      <pubDate>Fri, 13 Dec 2024 20:22:00 +0000</pubDate>
      <link>https://dev.to/jehielmartinez/building-a-scalable-serverless-image-processing-pipeline-with-aws-sqs-and-lambda-2f2k</link>
      <guid>https://dev.to/jehielmartinez/building-a-scalable-serverless-image-processing-pipeline-with-aws-sqs-and-lambda-2f2k</guid>
      <description>&lt;p&gt;Image-intensive applications need efficient ways to process images as soon as they are uploaded. Direct processing can overload servers and create bottlenecks. A distributed, scalable approach is necessary to handle varying workloads without sacrificing performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/jehielmartinez/construyendo-un-procesador-de-imagenes-escalable-con-sqs-y-lambda-3khl"&gt;Click aquí para la version en español&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;The solution uses a serverless, event-driven architecture that ensures scalability and resilience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Images are uploaded to an S3 input bucket.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upload events trigger a Lambda function.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lambda pushes metadata to an SQS queue.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processing Lambda consumes messages from the SQS queue.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thumbnails are generated and stored in the output bucket.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach decouples the image upload and processing stages, allowing the system to handle spikes in uploads efficiently.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  AWS Services Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon S3&lt;/strong&gt;: Acts as both the source for original images and the destination for processed thumbnails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon SQS&lt;/strong&gt;: Serves as a message broker to decouple upload and processing stages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda&lt;/strong&gt;: Provides serverless compute for event handling and image processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS IAM&lt;/strong&gt;: Manages permissions and ensures secure access to AWS resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technical Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Image Upload Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;A user uploads an image to the input S3 bucket.&lt;/li&gt;
&lt;li&gt;An S3 event notification triggers the first Lambda function.&lt;/li&gt;
&lt;li&gt;This Lambda function constructs a message containing the image's metadata (e.g., bucket name, object key).&lt;/li&gt;
&lt;li&gt;The metadata is published to an SQS queue.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Processing Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;A second Lambda function continuously polls the SQS queue for new messages.&lt;/li&gt;
&lt;li&gt;Upon receiving a message, the Lambda function:

&lt;ul&gt;
&lt;li&gt;Downloads the image from the input bucket.&lt;/li&gt;
&lt;li&gt;Processes the image using the &lt;strong&gt;Sharp&lt;/strong&gt; library to generate a thumbnail.&lt;/li&gt;
&lt;li&gt;Uploads the thumbnail to the output bucket.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Once the process is successful, the corresponding SQS message is deleted.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dead Letter Queue (DLQ)&lt;/strong&gt;: Messages that fail processing after retries are moved to a DLQ for further analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudWatch Logs&lt;/strong&gt;: Logs capture detailed processing steps and error information for debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Retries&lt;/strong&gt;: Transient errors trigger automatic retries based on SQS policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Infrastructure as Code with AWS CDK
&lt;/h3&gt;

&lt;p&gt;Let's break down the core infrastructure implementation in our AWS CDK stack:&lt;/p&gt;

&lt;h4&gt;
  
  
  S3 Bucket Setup
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorBucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqs-thumbnail-generator-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;removalPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DESTROY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;autoDeleteObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;versioned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create an S3 bucket with versioning enabled to store original images and generated thumbnails. The bucket is configured for automatic object deletion to simplify cleanup.&lt;/p&gt;

&lt;h4&gt;
  
  
  Queue Configuration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dlq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorDeadLetterQueue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thumbnail-generator-dlq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;retentionPeriod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&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;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorQueue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thumbnail-generator-queue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;visibilityTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;deadLetterQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dlq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxReceiveCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set up two queues:&lt;/p&gt;

&lt;p&gt;A main queue for processing images&lt;br&gt;
A Dead Letter Queue (DLQ) for handling failed processing attempts&lt;br&gt;
Messages are moved to DLQ after 3 failed attempts&lt;/p&gt;

&lt;h4&gt;
  
  
  S3 to SQS Integration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT_CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uploads/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration automatically sends a message to our SQS queue whenever a new file is uploaded to the 'uploads/' directory in our S3 bucket.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sharp Layer
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sharpLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LayerVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SharpLayer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./layers/sharp.zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="na"&gt;compatibleRuntimes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_LATEST&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;compatibleArchitectures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARM_64&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;We need the &lt;strong&gt;Sharp&lt;/strong&gt; library to process images. We create a Lambda Layer with the library and attach it to our processing Lambda function. This ensures that the library is available to the function at runtime.&lt;/p&gt;

&lt;p&gt;This specific layer is built for ARM64 architecture, which is the architecture used by AWS Graviton2 processors. It's optimized for performance and cost savings. &lt;a href="https://github.com/pH200/sharp-layer" rel="noopener noreferrer"&gt;Sharp Layer Source&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Thumbnail Generator Lambda
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodejsFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorProcessor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thumbnail-generator-processor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_LATEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./functions/thumbnail-generator.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sharpLayer&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;architecture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARM_64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;QUEUE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsEventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define a Lambda function that processes messages from the SQS queue. The function is triggered by new messages in the queue and generates thumbnails using the &lt;strong&gt;Sharp&lt;/strong&gt; library.&lt;/p&gt;

&lt;p&gt;The function code is defined in the &lt;code&gt;thumbnail-generator.ts&lt;/code&gt; file, which is responsible for downloading, processing, and uploading images.&lt;/p&gt;

&lt;h4&gt;
  
  
  IAM Policies
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToResourcePolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;principals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
      &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqs:SendMessage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queueArn&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ArnLike&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws:SourceArn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantReadWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantConsumeMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define IAM policies to allow the S3 bucket to send messages to the SQS queue and grant the processing Lambda function read/write access to the bucket and permission to consume messages from the queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it
&lt;/h2&gt;

&lt;p&gt;If you’d like to try this project, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clone the Repository&lt;/strong&gt;: &lt;a href="https://github.com/jehielmartinez/aws-sqs-thumbnail-generator" rel="noopener noreferrer"&gt;AWS SQS Thumbnail Generator&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update Configuration&lt;/strong&gt;: Modify the account and region details in the &lt;code&gt;/bin/aws-sqs-thumbnail-generator.ts&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure the Thumbnail Sizes&lt;/strong&gt;: Adjust the thumbnail sizes in the &lt;code&gt;/functions/thumbnail-generator.ts&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy the Infrastructure&lt;/strong&gt;: Use AWS CDK to deploy the necessary resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test the Workflow&lt;/strong&gt;: Upload an image to the input S3 bucket and watch as thumbnails are automatically generated and stored in the output bucket.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;The AWS SQS Thumbnail Generator is a powerful example of leveraging serverless architecture to build scalable, efficient, and resilient workflows. By decoupling processes and utilizing services like SQS, Lambda, and S3, this project showcases how to handle resource-intensive tasks with ease.&lt;/p&gt;

&lt;p&gt;This project can be extended further by adding features like image recognition, metadata extraction, or integrating with other AWS services. The possibilities are endless, and the scalability and flexibility of serverless architecture make it an ideal choice for such applications.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jehielmartinez/aws-sqs-thumbnail-generator" rel="noopener noreferrer"&gt;Project Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/sqs/" rel="noopener noreferrer"&gt;Amazon SQS Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS Cloud Development Kit (CDK)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>lambda</category>
      <category>devops</category>
      <category>sqs</category>
      <category>aws</category>
    </item>
    <item>
      <title>Construyendo un Procesador de Imágenes Escalable con SQS y Lambda</title>
      <dc:creator>Jehiel Martinez</dc:creator>
      <pubDate>Fri, 13 Dec 2024 18:20:00 +0000</pubDate>
      <link>https://dev.to/jehielmartinez/construyendo-un-procesador-de-imagenes-escalable-con-sqs-y-lambda-3khl</link>
      <guid>https://dev.to/jehielmartinez/construyendo-un-procesador-de-imagenes-escalable-con-sqs-y-lambda-3khl</guid>
      <description>&lt;p&gt;Las aplicaciones que manejan un alto volumen de imágenes necesitan formas eficientes de procesarlas tan pronto como se suben al sistema. El procesamiento directo puede sobrecargar los servidores y crear cuellos de botella. Por eso, es necesario un enfoque distribuido y escalable para manejar cargas de trabajo variables sin sacrificar el rendimiento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/jehielmartinez/building-a-scalable-serverless-image-processing-pipeline-with-aws-sqs-and-lambda-2f2k"&gt;Click here for the english version&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Arquitectura
&lt;/h2&gt;

&lt;p&gt;La solución utiliza una arquitectura serverless y event-driven que garantiza escalabilidad y resistencia:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Las imágenes se suben a un bucket de entrada en S3.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Los eventos de subida ejecutan una función Lambda.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lambda envía los metadatos a una cola SQS.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Una Lambda de procesamiento consume los mensajes de la cola SQS.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Las miniaturas se generan y se almacenan en el bucket de salida.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este enfoque desacopla las etapas de subida y procesamiento de imágenes, permitiendo que el sistema maneje picos de carga de manera eficiente.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Servicios AWS Utilizados
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon S3&lt;/strong&gt;: Funciona como origen para las imágenes originales y destino para las miniaturas procesadas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon SQS&lt;/strong&gt;: Actúa como message broker para desacoplar las etapas de subida y procesamiento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda&lt;/strong&gt;: Proporciona capacidad de cómputo serverless para el manejo de eventos y procesamiento de imágenes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS IAM&lt;/strong&gt;: Gestiona los permisos y asegura el acceso seguro a los recursos de AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementación Técnica
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Subida de Imágenes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Un usuario sube una imagen al bucket de entrada en S3.&lt;/li&gt;
&lt;li&gt;Una notificación de evento de S3 activa la primera función Lambda.&lt;/li&gt;
&lt;li&gt;Esta función Lambda construye un mensaje que contiene los metadatos de la imagen (ej: bucketName, key).&lt;/li&gt;
&lt;li&gt;Los metadatos se publican en una cola SQS.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Procesamiento
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Una segunda función Lambda monitorea constantemente la cola SQS en busca de nuevos mensajes.&lt;/li&gt;
&lt;li&gt;Al recibir un mensaje, la función Lambda:

&lt;ul&gt;
&lt;li&gt;Descarga la imagen del bucket de entrada.&lt;/li&gt;
&lt;li&gt;Procesa la imagen usando la librería &lt;strong&gt;Sharp&lt;/strong&gt; para generar las miniaturas.&lt;/li&gt;
&lt;li&gt;Sube las miniaturas de regreso al bucket .&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Una vez que el proceso termina exitosamente, el mensaje correspondiente se elimina de la cola SQS.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Manejo de Errores
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dead Letter Queue (DLQ)&lt;/strong&gt;: Los mensajes que fallan en el procesamiento después de varios intentos se mueven a una DLQ para análisis posterior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudWatch Logs&lt;/strong&gt;: Los logs capturan los pasos detallados del procesamiento e información de errores para debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reintentos Automáticos&lt;/strong&gt;: Los errores transitorios activan reintentos automáticos basados en las políticas de SQS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Infraestructura como Código con AWS CDK
&lt;/h3&gt;

&lt;p&gt;Veamos en detalle la implementación de la infraestructura principal en nuestro stack de AWS CDK:&lt;/p&gt;

&lt;h4&gt;
  
  
  S3 Bucket
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorBucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqs-thumbnail-generator-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;removalPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DESTROY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;autoDeleteObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;versioned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creamos un bucket de S3 con versionamiento habilitado para almacenar imágenes originales y miniaturas generadas. El bucket está configurado para la eliminación automática de objetos para simplificar la eliminación del stack, esto no se recomienda en producción.&lt;/p&gt;

&lt;h4&gt;
  
  
  Queues
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dlq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorDeadLetterQueue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thumbnail-generator-dlq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;retentionPeriod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&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;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorQueue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;queueName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thumbnail-generator-queue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;visibilityTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;deadLetterQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dlq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxReceiveCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuramos dos queues (colas):&lt;/p&gt;

&lt;p&gt;Un queue principal para procesar imágenes&lt;br&gt;
Una Dead Letter Queue (DLQ) para manejar intentos fallidos de procesamiento&lt;br&gt;
Los mensajes se mueven a la DLQ después de 3 intentos fallidos&lt;/p&gt;

&lt;h4&gt;
  
  
  S3 to SQS Integration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OBJECT_CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uploads/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta configuración envía automáticamente un mensaje a SQS cada vez que se sube un nuevo archivo al directorio &lt;code&gt;uploads/&lt;/code&gt; en nuestro bucket de S3.&lt;/p&gt;

&lt;h4&gt;
  
  
  Libreria Sharp
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sharpLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LayerVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SharpLayer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./layers/sharp.zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="na"&gt;compatibleRuntimes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_LATEST&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;compatibleArchitectures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARM_64&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;Necesitamos la librería &lt;strong&gt;Sharp&lt;/strong&gt; para procesar imágenes. Creamos una Lambda Layer con la librería y la adjuntamos a nuestra función de procesamiento. Esto asegura que la librería esté disponible para la función en tiempo de ejecución.&lt;/p&gt;

&lt;p&gt;Esta capa específica está construida para la arquitectura ARM64, que es la arquitectura utilizada por los procesadores AWS Graviton2. Está optimizada para rendimiento y ahorro de costos. &lt;a href="https://github.com/pH200/sharp-layer" rel="noopener noreferrer"&gt;Sharp Layer&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Thumbnail Generator Lambda
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodejsFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AwsSqsThumbnailGeneratorProcessor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;thumbnail-generator-processor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_LATEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./functions/thumbnail-generator.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sharpLayer&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;architecture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARM_64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;QUEUE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsEventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Definimos una función Lambda que procesa mensajes del SQS. La función se activa con nuevos mensajes en la cola y genera miniaturas usando la librería &lt;strong&gt;Sharp&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El código de la función está definido en el archivo &lt;code&gt;thumbnail-generator.ts&lt;/code&gt;, que es responsable de descargar, procesar y subir imágenes.&lt;/p&gt;

&lt;h4&gt;
  
  
  IAM Policies
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToResourcePolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;principals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ServicePrincipal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
      &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqs:SendMessage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queueArn&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ArnLike&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws:SourceArn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantReadWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantConsumeMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Definimos políticas IAM para permitir que el bucket de S3 envíe mensajes al queue y otorgamos a la función Lambda de procesamiento acceso de lectura/escritura al bucket y permiso para consumir mensajes del queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cómo Utilizarlo
&lt;/h2&gt;

&lt;p&gt;Si quieres probar este proyecto, sigue estos pasos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clona el Repositorio&lt;/strong&gt;: &lt;a href="https://github.com/jehielmartinez/aws-sqs-thumbnail-generator" rel="noopener noreferrer"&gt;AWS SQS Thumbnail Generator&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actualiza la Configuración&lt;/strong&gt;: Modifica los detalles de cuenta y región en el archivo &lt;code&gt;/bin/aws-sqs-thumbnail-generator.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configura los Tamaños de Miniatura&lt;/strong&gt;: Ajusta los tamaños en el archivo &lt;code&gt;/functions/thumbnail-generator.ts&lt;/code&gt; a tus necesidades.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Despliega la Infraestructura&lt;/strong&gt;: Utiliza AWS CDK para desplegar los recursos necesarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prueba el Flujo&lt;/strong&gt;: Sube una imagen al bucket de entrada en S3 y observa cómo se generan y almacenan automáticamente las miniaturas en el bucket de salida.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;El AWS SQS Thumbnail Generator es un excelente ejemplo de cómo aprovechar la arquitectura serverless para construir flujos de trabajo escalables, eficientes y resilientes. Al desacoplar procesos y utilizar servicios como SQS, Lambda y S3, este proyecto demuestra cómo manejar tareas intensivas en recursos de manera sencilla.&lt;/p&gt;

&lt;p&gt;Este proyecto puede expandirse añadiendo funcionalidades como reconocimiento de imágenes, extracción de metadatos o integración con otros servicios de AWS. Las posibilidades son infinitas, y la escalabilidad y flexibilidad de la arquitectura serverless la convierten en la opción ideal para este tipo de aplicaciones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos Adicionales
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jehielmartinez/aws-sqs-thumbnail-generator" rel="noopener noreferrer"&gt;Repositorio del Proyecto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;Documentación de AWS Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/sqs/" rel="noopener noreferrer"&gt;Documentación de Amazon SQS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS Cloud Development Kit (CDK)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>lambda</category>
      <category>devops</category>
      <category>sqs</category>
      <category>aws</category>
    </item>
    <item>
      <title>Cómo crear un portafolio de tus proyectos en Github Pages</title>
      <dc:creator>Jehiel Martinez</dc:creator>
      <pubDate>Mon, 27 Jan 2020 04:42:50 +0000</pubDate>
      <link>https://dev.to/jehielmartinez/como-crear-un-portafolio-de-tus-proyectos-en-github-pages-3jm</link>
      <guid>https://dev.to/jehielmartinez/como-crear-un-portafolio-de-tus-proyectos-en-github-pages-3jm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;En el arte de la programación todos necesitamos una galería.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imaginemos esto, estas aprendiendo a programar, contruyes tus propios proyectos, algunos los terminas, la mayoría no. En el proceso terminas con mas de veinte repositorios entre locales y remotos nadando por alli. &lt;/p&gt;

&lt;p&gt;De repente, recibes una llamada para una entrevista en un empleo como desarrollador web. La adrenalina sube, te pones ansioso, quieres demostrar a estas personas tus habilidades y lo increíbles que son tus proyectos. &lt;/p&gt;

&lt;p&gt;¿El problema? no tienes idea de como mostrar tu trabajo. &lt;/p&gt;

&lt;p&gt;Debiste planear esto antes. ¿Ya lo habías pensado verdad? Necesitas un portafolio web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Github Pages
&lt;/h2&gt;

&lt;p&gt;Segun la documentación &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;Github Pages&lt;/a&gt; es un servicio que te permite publicar contenido web de una manera fácil y sencilla. Básicamente, solo debes de subir tus archivos estáticos a un repositorio especial de &lt;em&gt;github.io&lt;/em&gt; y listo. Todo funciona.&lt;/p&gt;

&lt;p&gt;Hoy vas a aprender como publicar un portafolio web de tres simples archivos: portfolio.html, portfolio.css y portfolio.js. &lt;/p&gt;

&lt;p&gt;Si, no te compliques la vida, todavía.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Creando el repositorio
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Ingresa a tu cuenta de Github, luego puedes crear un nuevo repositorio desde &lt;a href="https://github.com/new" rel="noopener noreferrer"&gt;github.com/new&lt;/a&gt; o presionando el botón &lt;em&gt;New&lt;/em&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2944wndz4rmn5963zaw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2944wndz4rmn5963zaw6.png" alt="Alt Text" width="673" height="356"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;En el nombre del repositorio debes ingresar &lt;code&gt;user.github.io&lt;/code&gt; reemplaza &lt;code&gt;user&lt;/code&gt; por tu nombre de usuario. Configúralo como público.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00xv2048b1pwf6tcgbti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00xv2048b1pwf6tcgbti.png" alt="Alt Text" width="800" height="747"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Subiendo archivos
&lt;/h2&gt;

&lt;p&gt;Navega hasta la carpeta donde guardas los archivos estáticos de tu proyecto.&lt;/p&gt;

&lt;h4&gt;
  
  
  Opción 1 ("low code")
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;En &lt;em&gt;github.com&lt;/em&gt; dentro de tu repositorio nuevo, presiona el botón &lt;code&gt;Upload Files&lt;/code&gt; y arrastra el contenido de tu carpeta local hasta el area indicada.&lt;/li&gt;
&lt;li&gt;Deja un mensaje para tu commit y haz click en &lt;code&gt;Commit Changes&lt;/code&gt;.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwgwj487pjymz5qrzw47.png" alt="Alt Text" width="800" height="298"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Opción 2 ("the dev way")
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;En la carpeta de tu proyecto abre una terminal. &lt;br&gt;
&lt;em&gt;Si nunca has utilizado git en tu máquina o no sabes que es una llave SSH. Puedes hacer esto con la Opción 1.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;En la terminal ingresa el comando &lt;code&gt;git init&lt;/code&gt;. Esto iniciará un git dentro de la carpeta de tu proyecto. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;En github.com dentro de tu repositorio, presiona el botón &lt;code&gt;Clone or Download&lt;/code&gt;. Luego, copia la URL.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5pgckoxwnwzvlrlr12j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5pgckoxwnwzvlrlr12j.png" alt="Alt Text" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;En la terminal de tu proyecto ingresa &lt;code&gt;git remote add origin url&lt;/code&gt;. Reemplaza la url con la que copiaste de tu repositorio. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;En la terminal verifica que el &lt;em&gt;origin&lt;/em&gt; este listado con el comando: &lt;code&gt;git remote -v&lt;/code&gt;. Deberias ver listada la url que copiaste.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Haz un &lt;em&gt;commit&lt;/em&gt; de los archivos de tu proyecto agregándolos todos con &lt;code&gt;git add .&lt;/code&gt; Luego ingresa el comando &lt;code&gt;git commit  -m "mi primer commit"&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Haz un &lt;em&gt;push&lt;/em&gt; al repositorio remoto: &lt;code&gt;git push -u origin master&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Listo! Espera unos cinco minutos y deberías poder navegar a la url &lt;code&gt;user.github.io&lt;/code&gt; reemplazando &lt;em&gt;user&lt;/em&gt; por tu nombre de usuario y ver tu proyecto publicado.&lt;/p&gt;

&lt;p&gt;Puedes tratar este repositorio como el &lt;em&gt;homepage&lt;/em&gt; de tu portafolio y poner enlaces a otros proyectos. &lt;/p&gt;

&lt;p&gt;Pero, ¿Cómo agregas más proyectos a tu portafolio?&lt;/p&gt;

&lt;h2&gt;
  
  
  Agregando Proyectos
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Archivos Estáticos
&lt;/h4&gt;

&lt;p&gt;Si tienes proyectos frontend básicos hechos con un conjunto de archivos html, css y js enlazados entre si. Puedes crear un repositorio nuevo siguiendo los pasos de la opción 2 de la sección anterior, luego:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Una vez tus archivos esten en github, ve a la pestaña de &lt;code&gt;Settings&lt;/code&gt; dentro de tu repositorio.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Baja hasta la sección &lt;em&gt;GitHub Pages&lt;/em&gt; y activa la opción &lt;em&gt;Source&lt;/em&gt; y selecciona &lt;code&gt;master branch&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr07ce3ixj8ga62lcyys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr07ce3ixj8ga62lcyys.png" alt="Alt Text" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automáticamente se creara un nuevo proyecto en la dirección &lt;code&gt;user.github.io/nombre-del-repositorio&lt;/code&gt;. Puedes utilizar estos enlaces en tu portafolio para mostrar tus mejores proyectos.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Websites con React
&lt;/h4&gt;

&lt;p&gt;Supongamos que tienes un proyecto hecho con React en el cual has estado trabajando largo tiempo, incluso con un repositorio remoto en GitHub y varias ramas (todo un pro).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Agrega el paquete de node &lt;em&gt;gh-pages&lt;/em&gt; con &lt;code&gt;npm i -D gh-pages&lt;/code&gt;. Este comando instalara el paquete en las dependencias de desarrollo. &lt;/li&gt;
&lt;li&gt;Edita el archivo &lt;em&gt;package.json&lt;/em&gt; agregando dos scripts &lt;code&gt;"deploy": "gh-pages -d build"&lt;/code&gt; y &lt;code&gt;"predeploy": "npm run build"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Agrega la propiedad &lt;code&gt;"homepage":"http://user.github.io/nombre-del-repositorio&lt;/code&gt;. Reemplazando user por tu usuario de GitHub y el nombre del repositorio remoto del proyecto.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "homepage": "http://user.github.io/nombre-del-repositorio",
    ...
    "scripts": {
        "deploy": "gh-pages -d build",
        "predeploy": "npm run build"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Agrega los ultimos cambios haciendo &lt;em&gt;commit&lt;/em&gt; y &lt;em&gt;push&lt;/em&gt; del proyecto.&lt;/li&gt;
&lt;li&gt;Corre el comando &lt;code&gt;npm run deploy&lt;/code&gt; para hacer el despliegue del proyecto y publicarlo en la &lt;em&gt;hompage&lt;/em&gt; especificada.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Listo! En cinco minutos deberías de poder navegar a la url de &lt;em&gt;homepage&lt;/em&gt; y ver tu proyecto de React desplegado!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;A partir de aquí puedes agregar mas proyectos de frontend a tu portafolio desplegándolos en &lt;em&gt;Github Pages&lt;/em&gt; y agregando los enlaces donde sea que los quieras mostrar. &lt;/p&gt;

&lt;p&gt;De esta manera siempre estarás preparado para demostrar a los reclutadores no solamente el código sino también el resultado final de tus magníficas creaciones.&lt;/p&gt;

</description>
      <category>github</category>
      <category>portfolio</category>
      <category>beginners</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
