<?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: Hazel Saenz</title>
    <description>The latest articles on DEV Community by Hazel Saenz (@hsaenzg).</description>
    <link>https://dev.to/hsaenzg</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%2F852908%2Fa3a10986-307b-4a35-8adf-eeb9a583e6a9.jpg</url>
      <title>DEV Community: Hazel Saenz</title>
      <link>https://dev.to/hsaenzg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hsaenzg"/>
    <language>en</language>
    <item>
      <title>Escala Inteligente con Microservicios Serverless</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Tue, 24 Mar 2026 17:57:16 +0000</pubDate>
      <link>https://dev.to/aws/escala-inteligente-con-microservicios-serverless-3lbe</link>
      <guid>https://dev.to/aws/escala-inteligente-con-microservicios-serverless-3lbe</guid>
      <description>&lt;p&gt;&lt;em&gt;Cuándo dividir, cómo conectar y qué patrones usar para no crear un monolito distribuido.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Hace un tiempo me tocó trabajar en un proyecto donde todo funcionaba. Un monolito. Un deploy, un repo, un equipo. Respondía rápido, los usuarios estaban contentos, el jefe estaba contento.&lt;/p&gt;

&lt;p&gt;Hasta que alguien en una conferencia dijo: &lt;em&gt;"los microservicios son el futuro"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Y miramos nuestro monolito y pensamos: &lt;em&gt;"esto no escala, necesitamos microservicios"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Tres meses después teníamos 15 servicios. Un request del usuario pasaba por 7 de ellos antes de responder. Si inventario iba lento, el checkout se caía. Si notificaciones fallaba, nadie sabía por qué el pedido se quedó a medias.&lt;/p&gt;

&lt;p&gt;Teníamos un &lt;strong&gt;monolito distribuido&lt;/strong&gt;. Los mismos problemas de antes, pero ahora con latencia de red y 12 dashboards que nadie entendía.&lt;/p&gt;

&lt;p&gt;La complejidad no desapareció. Solo cambió de forma.&lt;/p&gt;

&lt;p&gt;Si alguna vez sentiste que migrar a microservicios iba a resolver todos tus problemas y terminó creando nuevos... este artículo es para ti.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Realmente necesitas microservicios?
&lt;/h2&gt;

&lt;p&gt;Antes de hablar de &lt;em&gt;cómo&lt;/em&gt;, hablemos de &lt;em&gt;cuándo&lt;/em&gt;. Porque la decisión más inteligente a veces es &lt;strong&gt;no dividir&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Cuando empecé a investigar más sobre el tema, me di cuenta de que muchas migraciones a microservicios no nacen de un problema real. Nacen del hype. De escuchar que "Netflix usa microservicios" y asumir que nosotros también deberíamos.&lt;/p&gt;

&lt;p&gt;Pero Netflix llegó a microservicios después de años de crecimiento y con miles de ingenieros dedicados a esa transición. El contexto importa: lo que funciona para una empresa con esa escala no necesariamente aplica para todos los equipos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Señales reales vs. falsas alarmas
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;✅ Señales reales para dividir&lt;/th&gt;
&lt;th&gt;❌ Falsas alarmas&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Equipos se bloquean entre sí para hacer deploy&lt;/td&gt;
&lt;td&gt;"Netflix usa microservicios"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Un componente necesita escalar 100x más que el resto&lt;/td&gt;
&lt;td&gt;"Mi monolito es legacy"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dominios de negocio claramente independientes&lt;/td&gt;
&lt;td&gt;"Quiero usar tecnologías diferentes por servicio"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ciclos de release muy diferentes entre componentes&lt;/td&gt;
&lt;td&gt;"Los microservicios son más modernos"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Un fallo en un módulo tumba todo el sistema&lt;/td&gt;
&lt;td&gt;"Mi equipo de 3 personas necesita agilidad"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Si tu equipo es pequeño y todo cabe en un deploy, no necesitas microservicios. Necesitas un &lt;strong&gt;monolito bien estructurado&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Divide cuando el dolor es real: equipos que se bloquean, componentes que necesitan escalar de forma radicalmente diferente, dominios de negocio que evolucionan a ritmos distintos.&lt;/p&gt;

&lt;p&gt;No dividas porque suena moderno.&lt;/p&gt;

&lt;h3&gt;
  
  
  No es binario — hay un espectro
&lt;/h3&gt;

&lt;p&gt;Algo que me costó entender al principio es que no es "monolito o microservicios". Hay un espectro completo entre ambos:&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%2F386umm3b5i9tzs304n95.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%2F386umm3b5i9tzs304n95.png" alt="monolito O Microservicios" width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La mayoría de los sistemas no necesitan ir directo a microservicios.&lt;/p&gt;

&lt;p&gt;Empieza con un &lt;strong&gt;monolito modular&lt;/strong&gt;: un solo deploy, pero con límites claros entre dominios. Cuando un módulo necesite escalar o evolucionar independientemente, lo extraes.&lt;/p&gt;

&lt;p&gt;Eso es escalar inteligente: dividir cuando hay evidencia, no cuando hay hype.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless cambia las reglas
&lt;/h2&gt;

&lt;p&gt;Cuando trabajas con microservicios tradicionales, cada servicio necesita su servidor, su scaling, su service discovery. Es mucha carga operativa.&lt;/p&gt;

&lt;p&gt;Serverless cambia eso por completo:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Microservicios Tradicionales&lt;/th&gt;
&lt;th&gt;Microservicios Serverless&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tú manejas servidores por servicio&lt;/td&gt;
&lt;td&gt;Sin servidores que gestionar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tú configuras auto-scaling&lt;/td&gt;
&lt;td&gt;Escala automática por función&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pagas por servidor encendido&lt;/td&gt;
&lt;td&gt;Pagas por ejecución&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tú manejas service discovery&lt;/td&gt;
&lt;td&gt;Eventos y colas conectan servicios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes, Docker, load balancers&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://docs.aws.amazon.com/lambda?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Lambda&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/apigateway?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;API Gateway&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/eventbridge?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;EventBridge&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pero hay algo que quiero dejar claro porque es una confusión muy común:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Un microservicio serverless no es UNA Lambda.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Es la colección de Lambdas detrás de un API Gateway que resuelven un dominio de negocio. Pedidos, inventario, pagos, cada uno es un microservicio compuesto por varias funciones pequeñas y enfocadas.&lt;/p&gt;

&lt;p&gt;Si metes toda la lógica en una sola Lambda gigante, estás creando un monolito dentro de una función.&lt;/p&gt;

&lt;p&gt;La pregunta ya no es &lt;em&gt;"cómo escalo este servicio"&lt;/em&gt; sino &lt;em&gt;"cómo conecto estos servicios de forma inteligente"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Y ahí es donde entran los patrones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Los 3 patrones clave
&lt;/h2&gt;

&lt;p&gt;Después de haber pasado por varias migraciones (algunas exitosas, otras no tanto), identifiqué tres patrones que marcan la diferencia entre una arquitectura de microservicios que funciona y un monolito distribuido disfrazado.&lt;/p&gt;

&lt;p&gt;Los presento aquí a nivel conceptual. Cada uno tendrá su artículo dedicado con implementación práctica y código real.&lt;/p&gt;

&lt;h3&gt;
  
  
  Patrón 1: Comunicación desacoplada — eventos, no llamadas directas
&lt;/h3&gt;

&lt;p&gt;Este fue el error que más me costó entender.&lt;/p&gt;

&lt;p&gt;Cuando empezamos a dividir servicios, lo primero que hicimos fue conectar Lambdas en cadena. Lambda A llama a B, B llama a C. Parecía lógico.&lt;/p&gt;

&lt;p&gt;El problema:&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%2F0odggawr4p8vjbw8w454.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%2F0odggawr4p8vjbw8w454.png" alt="anti patron 1" width="691" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si C falla, todo falla. Las latencias se suman. Estás recreando el monolito pero con más latencia.&lt;/p&gt;

&lt;p&gt;El patrón correcto es usar &lt;strong&gt;eventos asíncronos&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklwvjn8qh8wj6cgkcvao.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%2Fklwvjn8qh8wj6cgkcvao.png" alt="eventos asincronos" width="691" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tu microservicio responde al usuario y emite un evento. Los demás microservicios reaccionan al evento a su propio ritmo.&lt;/p&gt;

&lt;p&gt;Desacoplados. Independientes. Resilientes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Amazon EventBridge&lt;/a&gt; actúa como un bus de eventos serverless que desacopla la lógica de enrutamiento de tus microservicios. &lt;a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Amazon SQS&lt;/a&gt; te da colas de mensajes para procesamiento asíncrono con garantías de entrega. Ambos son piezas fundamentales para este patrón.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En el próximo artículo de la serie vamos a implementar este patrón paso a paso con EventBridge y SQS, incluyendo las trampas que te puedes encontrar.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Patrón 2: Cada servicio, su data
&lt;/h3&gt;

&lt;p&gt;Este es directo y no tiene vuelta:&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%2Fcz1vocgio9mtgvlhbnjw.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%2Fcz1vocgio9mtgvlhbnjw.png" alt="Antipatron 2 Cada servicio, su data" width="270" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si todos tus servicios leen y escriben en la misma tabla de DynamoDB, no tienes microservicios. Tienes un &lt;strong&gt;monolito disfrazado&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;El patrón correcto:&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%2Fgw99ayqyvm6v9ocwk8vi.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%2Fgw99ayqyvm6v9ocwk8vi.png" alt="Patron 2 Cada servicio, su datas" width="254" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cada servicio es dueño de su data. Si otro servicio necesita esa información, la pide por evento o por API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nunca por query directo a la base de datos ajena.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;¿Por qué? Porque si compartes la base de datos, cualquier cambio de schema puede romper múltiples servicios al mismo tiempo. Y ahí se fue tu independencia.&lt;/p&gt;

&lt;p&gt;Esto se conoce como &lt;em&gt;database per service&lt;/em&gt; y suena simple, pero tiene implicaciones importantes, como qué pasa cuando una transacción involucra múltiples servicios (spoiler: necesitas el patrón Saga).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En el tercer artículo de la serie vamos a profundizar en este patrón y en cómo manejar transacciones distribuidas con Sagas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Patrón 3: Observabilidad desde el día 1
&lt;/h3&gt;

&lt;p&gt;En un monolito, un error aparece en un log. En microservicios, un error puede estar en cualquiera de 10 servicios.&lt;/p&gt;

&lt;p&gt;Sin observabilidad, estás debuggeando a ciegas. Y te lo digo por experiencia: no hay nada más frustrante que saber que algo falló y no poder encontrar dónde.&lt;/p&gt;

&lt;p&gt;Los tres pilares que necesitas desde el día 1:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Logs estructurados con correlation ID&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota importante:&lt;/strong&gt; Cada request que entra a tu sistema debe llevar un ID único que viaje por todos los servicios. Cuando algo falla, buscas ese ID y ves el camino completo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.powertools.aws.dev/lambda/python/latest/" rel="noopener noreferrer"&gt;Lambda Powertools&lt;/a&gt; te lo da casi gratis, inyecta correlation IDs, estructura tus logs en JSON y agrega contexto automáticamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Traces distribuidos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/xray/latest/devguide?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;AWS X-Ray&lt;/a&gt; y &lt;a href="https://aws.amazon.com/otel?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;AWS Distro for OpenTelemetry (ADOT)&lt;/a&gt; te permiten ver el viaje completo de cada request a través de todos los servicios. Puedes identificar exactamente dónde está el bottleneck.&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%2F8fw5jubypqpbslevq282.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%2F8fw5jubypqpbslevq282.png" alt="Observabilidad" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota importante:&lt;/strong&gt; AWS está convergiendo hacia OpenTelemetry como estándar de instrumentación. ADOT te da una distribución optimizada para AWS que envía traces y métricas a X-Ray, CloudWatch y otros destinos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Métricas de negocio&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No solo "cuántos errores 500" sino "cuántos pedidos se perdieron por minuto". Las métricas técnicas te dicen que algo falló. Las métricas de negocio te dicen cuánto te costó.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si no puedes ver qué pasa, no puedes arreglar lo que falla. En el cuarto artículo de la serie vamos a implementar observabilidad completa con Lambda Powertools, X-Ray y métricas custom.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  El framework de decisión
&lt;/h2&gt;

&lt;p&gt;Después de todo lo que vimos, quiero dejarte algo práctico. Un framework que puedes usar la próxima vez que alguien diga "necesitamos microservicios":&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%2Fgxm3uk3xsnjsmd80gh7z.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%2Fgxm3uk3xsnjsmd80gh7z.png" alt="framework de decision" width="800" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No empieces por la tecnología. Empieza por las preguntas.&lt;/p&gt;

&lt;p&gt;Si la respuesta a todo es no, quédate con tu monolito. Si es sí, extrae con estrategia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que quiero que te lleves
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;🧠 &lt;strong&gt;Decide con evidencia, no con hype&lt;/strong&gt;: Microservicios no son el default. Son una herramienta para problemas específicos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;📐 &lt;strong&gt;Empieza modular, extrae después&lt;/strong&gt;: Monolito modular → macro-servicios → microservicios. En ese orden.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🔌 &lt;strong&gt;Eventos sobre llamadas directas&lt;/strong&gt;: Desacopla con EventBridge/SQS. Nunca encadenes Lambdas síncronamente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🗄️ &lt;strong&gt;Cada servicio, su data&lt;/strong&gt;: Base de datos compartida = monolito disfrazado.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;👀 &lt;strong&gt;Observabilidad no es opcional&lt;/strong&gt;: Correlation IDs, X-Ray/OpenTelemetry, métricas de negocio. Desde el día 1.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Qué sigue
&lt;/h2&gt;

&lt;p&gt;Este artículo es el mapa conceptual. Los siguientes artículos de la serie van a profundizar en cada patrón con implementación práctica y código real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Comunicación desacoplada con EventBridge y SQS&lt;/strong&gt;: Implementación paso a paso, trampas comunes y demo funcional&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database per service y el patrón Saga&lt;/strong&gt;: Cómo manejar transacciones distribuidas con acciones compensatorias&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observabilidad en microservicios serverless&lt;/strong&gt;: Lambda Powertools, X-Ray/OpenTelemetry y métricas de negocio en acción&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Escalar inteligente no es tener más servicios. Es tomar mejores decisiones."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Si quieres profundizar más, estos son los recursos oficiales de AWS que recomiendo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/whitepapers/latest/microservices-on-aws/microservices-on-aws.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Implementing Microservices on AWS&lt;/a&gt; — Whitepaper completo sobre patrones API-driven, event-driven y data streaming&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/whitepapers/latest/microservices-on-aws/microservices-on-serverless-technologies.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Microservices on Serverless Technologies&lt;/a&gt; — Arquitecturas serverless con Lambda, API Gateway y Fargate&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-integrating-microservices/introduction.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Integrating Microservices by Using AWS Serverless Services&lt;/a&gt; — Guía prescriptiva sobre comunicación síncrona y asíncrona entre microservicios&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/introduction.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Cloud Design Patterns, Architectures, and Implementations&lt;/a&gt; — Patrones como Saga, circuit breaker, event sourcing y strangler fig aplicados con servicios AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;¿Te resultó útil este artículo?&lt;/strong&gt; Compártelo con tu equipo. Y si ya pasaste por una migración a microservicios exitosa o no me encantaría escuchar tu experiencia.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>microservices</category>
      <category>architecture</category>
      <category>aws</category>
    </item>
    <item>
      <title>AWS Lambda Durable Functions + IA: el combo que no sabías que necesitabas</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Wed, 18 Mar 2026 16:56:38 +0000</pubDate>
      <link>https://dev.to/aws/aws-lambda-durable-functions-ia-el-combo-que-no-sabias-que-necesitabas-3eoc</link>
      <guid>https://dev.to/aws/aws-lambda-durable-functions-ia-el-combo-que-no-sabias-que-necesitabas-3eoc</guid>
      <description>&lt;p&gt;&lt;em&gt;Cómo instalar y usar el nuevo Kiro Power para Lambda Durable Functions paso a paso.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;En el &lt;a href="https://dev.to/aws/lambda-durable-functions-mata-a-step-functions-o-no-2p6c"&gt;artículo anterior&lt;/a&gt; vimos que Lambda Durable Functions y Step Functions no compiten. Son dos filosofías diferentes para resolver el mismo problema: orquestación de workflows.&lt;/p&gt;

&lt;p&gt;Step Functions orquesta visualmente. Durable Functions orquesta en código.&lt;/p&gt;

&lt;p&gt;Y prometí que en este artículo íbamos a pasar de la teoría a la práctica.&lt;/p&gt;

&lt;p&gt;Pero hay un detalle que no mencioné:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Construir tu primera Durable Function no tiene que ser complicado.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Porque desde marzo de 2026, existe un &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/03/lambda-durable-kiro-power/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Kiro Power&lt;/a&gt; que te guía paso a paso. Con IA. Dentro de tu IDE.&lt;/p&gt;

&lt;p&gt;Y eso cambia todo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Espera... ¿qué es Kiro?
&lt;/h2&gt;

&lt;p&gt;Si es la primera vez que escuchas el nombre, no te preocupes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kiro.dev?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Kiro&lt;/a&gt; es un IDE creado por AWS, potenciado con IA. Piensa en él como tu editor de código, pero con un agente de IA integrado que entiende lo que estás construyendo y te ayuda a hacerlo mejor.&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%2Ffakj0k6wmsgk5s4271u3.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%2Ffakj0k6wmsgk5s4271u3.png" alt="Kiro IDE mostrando el agente de IA en acción" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No es un chatbot que pega código de internet. No es un autocompletado glorificado.&lt;/p&gt;

&lt;p&gt;Es un agente que &lt;strong&gt;entiende el contexto&lt;/strong&gt; de tu proyecto, sigue buenas prácticas, y te guía mientras escribes código.&lt;/p&gt;

&lt;p&gt;Puedes usarlo para escribir código, debuggear, hacer deploy, y mucho más. Si quieres conocerlo a fondo, te recomiendo esta &lt;a href="https://builder.aws.com/content/34X2JujaGkTJed5N2KeMYt1Mz9m/como-comenzar-con-kiro-tu-guia-de-primeros-pasos?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;guía de primeros pasos con Kiro&lt;/a&gt;. Pero lo que lo hace especial para este artículo es algo llamado &lt;strong&gt;&lt;a href="https://kiro.dev/powers?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Powers&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un Kiro Power?
&lt;/h2&gt;

&lt;p&gt;Un Power es como darle superpoderes especializados al agente de IA de Kiro.&lt;/p&gt;

&lt;p&gt;Sin un Power, el agente sabe de todo un poco. Con un Power instalado, el agente se convierte en &lt;strong&gt;experto&lt;/strong&gt; en un tema específico.&lt;/p&gt;

&lt;p&gt;Piensa en esto: si le pides a un asistente genérico que te ayude a construir una Durable Function, probablemente te dé una respuesta genérica. Puede que funcione. Puede que no.&lt;/p&gt;

&lt;p&gt;Pero si ese asistente tiene cargado un Power de Lambda Durable Functions, se convierte en un experto que &lt;strong&gt;sabe&lt;/strong&gt; las reglas, los patrones, y las trampas comunes. Y carga esa información dinámicamente según lo que estés haciendo.&lt;/p&gt;

&lt;h2&gt;
  
  
  El Lambda Durable Functions Power
&lt;/h2&gt;

&lt;p&gt;El 5 de marzo de 2026, AWS lanzó el &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/03/lambda-durable-kiro-power/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Kiro Power para Lambda Durable Functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Incluye guía especializada para todo el ciclo de desarrollo: desde el setup del proyecto y las reglas del replay model, pasando por steps, waits, callbacks, ejecución en paralelo, manejo de errores, testing local, hasta deploy con CDK, SAM, o CloudFormation.&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%2F6g0u7skigd98cii83jhf.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%2F6g0u7skigd98cii83jhf.png" alt="Diagrama de lo que incluye el Power — replay model, steps, waits, error handling, testing, deployment" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No tienes que leer toda la documentación antes de empezar. El Power te da lo que necesitas, cuando lo necesitas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalando el Power
&lt;/h2&gt;

&lt;p&gt;Esto es la parte más fácil. Literalmente un clic.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abre Kiro&lt;/li&gt;
&lt;li&gt;Ve al panel de Powers (en la barra lateral)&lt;/li&gt;
&lt;li&gt;En la sección &lt;strong&gt;Available&lt;/strong&gt;, busca "Lambda Durable Functions"&lt;/li&gt;
&lt;li&gt;Haz clic en &lt;strong&gt;Install&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Eso es todo.&lt;/p&gt;

&lt;p&gt;No hay configuración adicional. No hay dependencias que instalar manualmente para el Power. Una vez instalado, el agente de Kiro ya tiene acceso a toda la guía especializada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; No todos los servicios de AWS tienen un Power dedicado. Los Powers son módulos especializados que se van agregando con el tiempo. Puedes explorar los disponibles en el panel de Powers de Kiro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahora sí, vamos a construir algo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisitos
&lt;/h2&gt;

&lt;p&gt;Antes de escribir código, necesitas tener algunas herramientas instaladas. Los siguientes comandos te ayudan a verificar si ya las tienes. Si alguno falla, sigue el link de documentación correspondiente para instalarlo.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS CLI&lt;/strong&gt; instalado (versión 2.33.22 o superior) y &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;configurado con tus credenciales&lt;/a&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--version&lt;/span&gt;
aws sts get-caller-identity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js 22+&lt;/a&gt;&lt;/strong&gt; instalado (para este tutorial usaremos TypeScript):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS CDK&lt;/strong&gt; instalado globalmente (versión 2.237.1 o superior). Este se instala a nivel global en tu máquina, no dentro del proyecto:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; aws-cdk
cdk &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si prefieres Python, &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Lambda Durable Functions&lt;/a&gt; también soporta Python 3.11+. Pero para este tutorial vamos con TypeScript porque es el lenguaje que más uso y el que me resulta más natural para explicar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creando tu primer proyecto
&lt;/h2&gt;

&lt;p&gt;Abre Kiro y crea una carpeta nueva para tu proyecto. Luego, en el chat del agente, puedes pedirle directamente:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Crea un proyecto de Lambda Durable Function con TypeScript y CDK"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El agente, con el Power instalado, va a:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inicializar el proyecto con la estructura correcta&lt;/li&gt;
&lt;li&gt;Instalar las dependencias necesarias&lt;/li&gt;
&lt;li&gt;Configurar TypeScript&lt;/li&gt;
&lt;li&gt;Crear los archivos base&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pero para que entiendas qué está pasando, vamos a hacerlo paso a paso.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inicializar el proyecto
&lt;/h3&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;image-processor
&lt;span class="nb"&gt;cd &lt;/span&gt;image-processor
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Instalar dependencias
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws/durable-execution-sdk-js
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @aws/durable-execution-sdk-js-testing typescript @types/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ese primer paquete es el &lt;a href="https://github.com/aws/aws-durable-execution-sdk-js?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;SDK de Durable Execution&lt;/a&gt;. Es el core de las Durable Functions: lo que hace posible que tu función guarde checkpoints y sobreviva a fallos.&lt;/p&gt;

&lt;p&gt;El segundo paquete (&lt;code&gt;-testing&lt;/code&gt;) es para testear localmente sin necesidad de deployar a AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estructura del proyecto
&lt;/h3&gt;

&lt;p&gt;Kiro va a generar esta estructura por ti cuando le pidas crear el proyecto. Pero si prefieres hacerlo manual, así es como debería verse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image-processor/
├── src/
│   └── handler.ts          # Tu función durable
├── tests/
│   └── handler.test.ts     # Tests locales
├── infrastructure/
│   └── stack.ts             # CDK stack para deploy
├── tsconfig.json
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple. Sin carpetas innecesarias. Sin archivos que no vas a usar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tu primera Durable Function (generada por el Power)
&lt;/h2&gt;

&lt;p&gt;Ahora viene la parte divertida.&lt;/p&gt;

&lt;p&gt;¿Recuerdas el ejemplo del &lt;a href="https://dev.to/aws/lambda-durable-functions-mata-a-step-functions-o-no-2p6c"&gt;artículo anterior&lt;/a&gt;? Un usuario sube una foto y necesitas: validar que sea una imagen válida, redimensionar a diferentes tamaños, aplicar marca de agua, generar thumbnails, y guardar en S3.&lt;/p&gt;

&lt;p&gt;Abre el chat de Kiro y escríbele algo como:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Crea una Durable Function que procese imágenes: validar el archivo, redimensionar, aplicar marca de agua, generar thumbnails y guardar en S3"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El agente, con el Power instalado, &lt;strong&gt;genera el código por ti&lt;/strong&gt;. No copia y pega de internet. Entiende las reglas del replay model, sabe qué va dentro de un step y qué no, y estructura el workflow siguiendo las buenas prácticas del SDK.&lt;/p&gt;

&lt;p&gt;Esto es lo que el Power generó para mí cuando le pedí exactamente eso:&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%2Floq30by0lgdpwou1b7nv.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%2Floq30by0lgdpwou1b7nv.png" alt="Screenshot del agente de Kiro generando el código de la Durable Function en el chat" width="800" height="463"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;outputBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputBucket&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;event&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputPrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputPrefix&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processed&lt;/span&gt;&lt;span class="dl"&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;baseName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.[^&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&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;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.[^&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&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="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 1: Validate the file&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;GetObjectCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&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="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&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="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`File not found: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&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;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transformToByteArray&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;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&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;jpeg&lt;/span&gt;&lt;span class="dl"&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;png&lt;/span&gt;&lt;span class="dl"&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;webp&lt;/span&gt;&lt;span class="dl"&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;tiff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`Unsupported image format: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Supported: jpeg, png, webp, tiff`&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File exceeds 50MB limit&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="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File validated&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;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&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="c1"&gt;// Step 2: Resize the image&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resizedBase64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&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;maxWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxWidth&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1920&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;maxHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxHeight&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1080&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;resized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inside&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;withoutEnlargement&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBuffer&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;resizedKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;outputPrefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;baseName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-resized&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;PutObjectCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;outputBucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resizedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`image/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image resized&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;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resizedKey&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resized&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;retryStrategy&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;p&gt;Ver codigo completo: &lt;a href="https://github.com/hsaenzG/durable-funtions-demo/blob/main/src/handler.ts" rel="noopener noreferrer"&gt;https://github.com/hsaenzG/durable-funtions-demo/blob/main/src/handler.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Parece código normal, ¿verdad? Y lo es. Pero con superpoderes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qué está pasando aquí
&lt;/h3&gt;

&lt;p&gt;Cada &lt;code&gt;context.step()&lt;/code&gt; es un &lt;strong&gt;checkpoint&lt;/strong&gt;. Si tu función falla aplicando la marca de agua (paso 3), cuando se reintente, &lt;strong&gt;no va a volver a validar ni redimensionar&lt;/strong&gt;. Salta directamente al paso 3 con los resultados que ya tenía guardados.&lt;/p&gt;

&lt;p&gt;Eso es el replay model en acción. Y para un workflow de procesamiento de imágenes, donde cada paso puede tardar segundos o minutos, no repetir trabajo es la diferencia entre una buena experiencia y una pesadilla.&lt;/p&gt;

&lt;p&gt;Fíjate también en &lt;code&gt;context.logger&lt;/code&gt; en lugar de &lt;code&gt;console.log&lt;/code&gt;: es &lt;strong&gt;replay-aware&lt;/strong&gt;. No duplica logs cuando la función se reintenta.&lt;/p&gt;

&lt;h2&gt;
  
  
  El Kiro Power y la regla de oro del Replay Model
&lt;/h2&gt;

&lt;p&gt;Aquí es donde el Kiro Power realmente brilla. Porque hay una regla que la mayoría no conocemos hasta que algo se rompe:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Todo código no determinístico DEBE ir dentro de un step.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Y el Power te avisa cuando estás a punto de violar esa regla. No tienes que memorizar todos los casos. El agente los detecta y te sugiere la corrección antes de que sea un problema.&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%2F1tzve877ywwkjmlhxyya.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%2F1tzve877ywwkjmlhxyya.png" alt="creenshot del agente de Kiro detectando una violación del replay model y sugiriendo la corrección" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pero, ¿por qué importa tanto esta regla?&lt;/p&gt;

&lt;p&gt;Cuando una Durable Function se reintenta (replay), ejecuta todo el código desde el principio. Los steps que ya completaron se saltan (usa el resultado guardado). Pero el código que está &lt;strong&gt;fuera&lt;/strong&gt; de los steps se ejecuta de nuevo.&lt;/p&gt;

&lt;p&gt;Si ese código da un resultado diferente en el replay... las cosas se rompen.&lt;/p&gt;

&lt;p&gt;¿Qué es código no determinístico? Cualquier cosa que puede dar un resultado diferente cada vez:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Date.now()&lt;/code&gt; → diferente cada vez&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Math.random()&lt;/code&gt; → diferente cada vez&lt;/li&gt;
&lt;li&gt;Llamadas a APIs externas → pueden devolver datos diferentes&lt;/li&gt;
&lt;li&gt;Consultas a bases de datos → los datos pueden haber cambiado&lt;/li&gt;
&lt;li&gt;Generación de UUIDs → diferente cada vez&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Veamos un ejemplo concreto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ MAL: Date.now() fuera de un step&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Diferente en cada replay&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ BIEN: Date.now() dentro del step&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save-with-timestamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Se guarda con el checkpoint&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&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;Sin el Power, descubrir este tipo de errores es prueba y error. Con el Power, el agente te lo señala mientras escribes.&lt;/p&gt;

&lt;p&gt;Además, puedes instalar el plugin de ESLint para Durable Functions que atrapa estos errores en tiempo de desarrollo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @aws/durable-execution-sdk-js-eslint-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testeando localmente
&lt;/h2&gt;

&lt;p&gt;No necesitas hacer deploy para probar tu función. El SDK incluye un test runner local.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LocalDurableTestRunner&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws/durable-execution-sdk-js-testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image Processing Workflow&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should process an image successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;runner&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;LocalDurableTestRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;skipTime&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-images-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;key&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/photo.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-123&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="c1"&gt;// Verificar que el procesamiento se completó&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalKey&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&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/photo.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Verificar que los steps se ejecutaron&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOperations&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;validateStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate-image&lt;/span&gt;&lt;span class="dl"&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;resizeStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize-image&lt;/span&gt;&lt;span class="dl"&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;watermarkStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apply-watermark&lt;/span&gt;&lt;span class="dl"&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;thumbnailStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;generate-thumbnails&lt;/span&gt;&lt;span class="dl"&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;saveStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save-to-s3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validateStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resizeStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;watermarkStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thumbnailStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saveStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&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;p&gt;El &lt;code&gt;skipTime: true&lt;/code&gt; es clave: hace que los &lt;code&gt;wait&lt;/code&gt; se salten instantáneamente en los tests.&lt;/p&gt;

&lt;p&gt;Y fíjate que buscamos los steps &lt;strong&gt;por nombre&lt;/strong&gt;, no por índice. Eso es una buena práctica que el Power te recuerda constantemente: siempre nombra tus steps de forma descriptiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Haciendo deploy con CDK
&lt;/h2&gt;

&lt;p&gt;Ya tienes tu función funcionando localmente. Ahora toca subirla a AWS.&lt;/p&gt;

&lt;p&gt;Para esto usamos &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/home.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;, que te permite definir tu infraestructura en código (TypeScript, en nuestro caso).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-logs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-iam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DurableFunctionStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&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;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&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;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Log group explícito para mejor control&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LogGroup&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;ImageProcessingLogs&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;logGroupName&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/lambda/imageProcessing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;retention&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RetentionDays&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ONE_WEEK&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="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// La función durable&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Function&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;ImageProcessing&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;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&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_24_X&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.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;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;logGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;durableConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;executionTimeout&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;hours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="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;7&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;// Política de permisos para durable execution&lt;/span&gt;
    &lt;span class="nx"&gt;imageFunction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;addManagedPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ManagedPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAwsManagedPolicyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;service-role/AWSLambdaBasicDurableExecutionRolePolicy&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="c1"&gt;// Crear alias para invocación&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageFunction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentVersion&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;alias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Alias&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;ProdAlias&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;aliasName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnOutput&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;FunctionAliasArn&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;functionArn&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lo que importa aquí
&lt;/h3&gt;

&lt;p&gt;Hay tres cosas que no puedes olvidar al hacer deploy de una Durable Function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;durableConfig&lt;/code&gt;&lt;/strong&gt;: Sin esto, tu función es una Lambda normal. El &lt;code&gt;executionTimeout&lt;/code&gt; define cuánto tiempo máximo puede correr tu workflow (hasta 1 año). El &lt;code&gt;retentionPeriod&lt;/code&gt; define cuánto tiempo se guardan los datos de ejecución.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;AWSLambdaBasicDurableExecutionRolePolicy&lt;/code&gt;&lt;/strong&gt;: Esta política le da a tu función permisos para hacer checkpoints (&lt;code&gt;lambda:CheckpointDurableExecution&lt;/code&gt;) y leer el estado de ejecución (&lt;code&gt;lambda:GetDurableExecutionState&lt;/code&gt;). Sin ella, los steps no pueden guardar su progreso.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ARN calificado&lt;/strong&gt;: Las Durable Functions &lt;strong&gt;requieren&lt;/strong&gt; un &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;ARN&lt;/a&gt; calificado para ser invocadas. Un ARN (Amazon Resource Name) es el identificador único de un recurso en AWS. "Calificado" significa que incluye la versión o alias de la función. No puedes invocar una Durable Function con el ARN sin calificar.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ✅ Correcto: con alias&lt;/span&gt;
aws lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; &lt;span class="s1"&gt;'MiStack-MiFuncion-abc123:prod'&lt;/span&gt; response.json

&lt;span class="c"&gt;# ✅ Correcto: con versión&lt;/span&gt;
aws lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; &lt;span class="s1"&gt;'MiStack-MiFuncion-abc123:1'&lt;/span&gt; response.json

&lt;span class="c"&gt;# ❌ Incorrecto: sin calificar — va a fallar&lt;/span&gt;
aws lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; MiStack-MiFuncion-abc123 response.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; CDK genera nombres de recursos con un sufijo aleatorio (ej: &lt;code&gt;ImageProcessorStack-ImageProcessor5D0B0257-lBARjqDaXdWK&lt;/code&gt;). Puedes encontrar el nombre exacto de tu función en el output del &lt;code&gt;cdk deploy&lt;/code&gt; o en la consola de AWS Lambda.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Compilar TypeScript&lt;/span&gt;
npx tsc

&lt;span class="c"&gt;# Deploy con CDK&lt;/span&gt;
cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CDK se encarga de crear todo: la función, el rol de IAM, los permisos, el log group, la versión y el alias.&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%2Fnds21mbsr10rh5lkkvow.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%2Fnds21mbsr10rh5lkkvow.png" alt="IScreenshot del deploy con CDK ejecutándose en la terminal" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Invocando tu función
&lt;/h2&gt;

&lt;p&gt;Ya está en la nube. Ahora vamos a probarla.&lt;/p&gt;

&lt;p&gt;Primero, sube una imagen de prueba al bucket de S3 que CDK creó:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;tu-imagen.jpg &lt;span class="se"&gt;\&lt;/span&gt;
  s3://TU-BUCKET-S3/photos/test.jpg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; TU-PERFIL &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; El nombre del bucket lo genera CDK automáticamente (ej: &lt;code&gt;imageprocessorstack-imagebucket97210811-x5j3e61lysxh&lt;/code&gt;). Puedes encontrarlo en el output del &lt;code&gt;cdk deploy&lt;/code&gt; o en la consola de S3.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahora sí, invoca la función:&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 invoke &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; &lt;span class="s1"&gt;'TU-NOMBRE-DE-FUNCION:prod'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--invocation-type&lt;/span&gt; Event &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--durable-execution-name&lt;/span&gt; &lt;span class="s2"&gt;"test-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--payload&lt;/span&gt; &lt;span class="s1"&gt;'{"bucket":"TU-BUCKET-S3","key":"photos/test.jpg"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cli-binary-format&lt;/span&gt; raw-in-base64-out &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; TU-PERFIL &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  response.json

&lt;span class="nb"&gt;cat &lt;/span&gt;response.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Reemplaza &lt;code&gt;TU-NOMBRE-DE-FUNCION&lt;/code&gt;, &lt;code&gt;TU-BUCKET-S3&lt;/code&gt; y &lt;code&gt;TU-PERFIL&lt;/code&gt; con los valores reales de tu entorno. Revisa los outputs del &lt;code&gt;cdk deploy&lt;/code&gt; para encontrarlos.&lt;/p&gt;
&lt;/blockquote&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%2F0nkoicfiymikbsnby8we.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%2F0nkoicfiymikbsnby8we.png" alt="Screenshot de la respuesta JSON en la terminal después de invocar la función" width="800" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Algunos detalles sobre estos parámetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--invocation-type Event&lt;/code&gt;&lt;/strong&gt;: Invoca la función de forma asíncrona. Para workflows largos como procesamiento de imágenes, esto es lo recomendado. Si quieres esperar la respuesta, usa &lt;code&gt;RequestResponse&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--durable-execution-name "test-$(date +%s)"&lt;/code&gt;&lt;/strong&gt;: Genera un nombre único por ejecución usando un timestamp. Esto garantiza &lt;strong&gt;idempotencia&lt;/strong&gt;: si invocas con el mismo nombre dos veces, la segunda no crea una ejecución nueva.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--profile&lt;/code&gt; y &lt;code&gt;--region&lt;/code&gt;&lt;/strong&gt;: Si tienes múltiples perfiles de AWS configurados, no olvides especificarlos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monitoreando tus ejecuciones
&lt;/h2&gt;

&lt;p&gt;Ya invocaste tu función. ¿Y ahora? ¿Cómo sabes si funcionó?&lt;/p&gt;

&lt;p&gt;No estás a ciegas. La consola de AWS Lambda tiene una interfaz dedicada para Durable Functions donde puedes ver todo lo que está pasando.&lt;/p&gt;

&lt;p&gt;Ve a tu función en la consola y busca la pestaña &lt;strong&gt;Durable executions&lt;/strong&gt;. Ahí vas a encontrar la lista de todas las ejecuciones con su estado: running, completed, failed.&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%2Fo1w5zhcbyzwd0l8gko8n.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%2Fo1w5zhcbyzwd0l8gko8n.png" alt="Screenshot de la consola de AWS Lambda mostrando la lista de ejecuciones durables con sus estados" width="800" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Haz clic en cualquier ejecución y vas a ver el detalle completo: qué steps se completaron, cuáles fallaron, cuánto tardó cada uno, y los datos que se guardaron en cada checkpoint.&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%2F9c9g5im3wvekd34m1ol2.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%2F9c9g5im3wvekd34m1ol2.png" alt="Screenshot del detalle de una ejecución durable mostrando los steps completados y sus resultados" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto es oro para debuggear. Si algo falló en el paso 3, puedes ver exactamente qué datos tenía en ese momento y qué error se produjo. Sin adivinar. Sin buscar en CloudWatch a ciegas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué esto importa si estás empezando
&lt;/h2&gt;

&lt;p&gt;Sin el Power, el camino típico es: leer toda la documentación, tropezar con el replay model, configurar el proyecto a mano, y descubrir errores de deploy por prueba y error.&lt;/p&gt;

&lt;p&gt;Con el Power, el agente te guía en cada paso. No elimina la necesidad de entender los conceptos (eso sigue siendo importante). Pero reduce drásticamente el tiempo entre "quiero aprender Durable Functions" y "tengo una funcionando en producción".&lt;/p&gt;

&lt;h2&gt;
  
  
  Limpieza de recursos
&lt;/h2&gt;

&lt;p&gt;Si solo estás probando, recuerda eliminar los recursos para evitar cargos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cdk destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto elimina la función Lambda, el rol de IAM, el log group, y todos los recursos asociados. CDK se encarga de todo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que aprendiste
&lt;/h2&gt;

&lt;p&gt;Instalaste un Kiro Power con un clic, creaste un proyecto desde cero, dejaste que el agente generara tu primera Durable Function con el mismo ejemplo de procesamiento de imágenes del artículo anterior, entendiste la regla de oro del replay model, testeaste localmente sin deploy, y subiste todo a AWS con CDK.&lt;/p&gt;

&lt;p&gt;De cero a producción. Con IA guiándote en cada paso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué sigue
&lt;/h2&gt;

&lt;p&gt;Ya tienes el workflow de procesamiento de imágenes funcionando. Pero lo construimos en el camino feliz: todo sale bien, nada falla.&lt;/p&gt;

&lt;p&gt;En el próximo artículo vamos a &lt;strong&gt;romper cosas a propósito&lt;/strong&gt;. Vamos a ver cómo los checkpoints automáticos mantienen tu progreso incluso cuando algo truena, y cómo el replay model recupera la ejecución exactamente donde quedó.&lt;/p&gt;

&lt;p&gt;Código real. Fallos reales. Recuperación real.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Te resultó útil este artículo?&lt;/strong&gt; Compártelo con tu equipo o déjame saber en los comentarios qué otros temas de serverless te gustaría que cubriera. Y si ya instalaste el Kiro Power y estás construyendo tu primera Durable Function, me encantaría escuchar tu experiencia.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>AWS Lambda Durable Functions + IA: el combo que no sabías que necesitabas</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Wed, 18 Mar 2026 16:56:38 +0000</pubDate>
      <link>https://dev.to/aws/aws-lambda-durable-functions-ia-el-combo-que-no-sabias-que-necesitabas-3lh2</link>
      <guid>https://dev.to/aws/aws-lambda-durable-functions-ia-el-combo-que-no-sabias-que-necesitabas-3lh2</guid>
      <description>&lt;p&gt;&lt;em&gt;Cómo instalar y usar el nuevo Kiro Power para Lambda Durable Functions paso a paso.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;En el &lt;a href="https://dev.to/aws/lambda-durable-functions-mata-a-step-functions-o-no-2p6c"&gt;artículo anterior&lt;/a&gt; vimos que Lambda Durable Functions y Step Functions no compiten. Son dos filosofías diferentes para resolver el mismo problema: orquestación de workflows.&lt;/p&gt;

&lt;p&gt;Step Functions orquesta visualmente. Durable Functions orquesta en código.&lt;/p&gt;

&lt;p&gt;Y prometí que en este artículo íbamos a pasar de la teoría a la práctica.&lt;/p&gt;

&lt;p&gt;Pero hay un detalle que no mencioné:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Construir tu primera Durable Function no tiene que ser complicado.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Porque desde marzo de 2026, existe un &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/03/lambda-durable-kiro-power/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Kiro Power&lt;/a&gt; que te guía paso a paso. Con IA. Dentro de tu IDE.&lt;/p&gt;

&lt;p&gt;Y eso cambia todo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Espera... ¿qué es Kiro?
&lt;/h2&gt;

&lt;p&gt;Si es la primera vez que escuchas el nombre, no te preocupes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kiro.dev?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Kiro&lt;/a&gt; es un IDE creado por AWS, potenciado con IA. Piensa en él como tu editor de código, pero con un agente de IA integrado que entiende lo que estás construyendo y te ayuda a hacerlo mejor.&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%2Ffakj0k6wmsgk5s4271u3.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%2Ffakj0k6wmsgk5s4271u3.png" alt="Kiro IDE mostrando el agente de IA en acción" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No es un chatbot que pega código de internet. No es un autocompletado glorificado.&lt;/p&gt;

&lt;p&gt;Es un agente que &lt;strong&gt;entiende el contexto&lt;/strong&gt; de tu proyecto, sigue buenas prácticas, y te guía mientras escribes código.&lt;/p&gt;

&lt;p&gt;Puedes usarlo para escribir código, debuggear, hacer deploy, y mucho más. Si quieres conocerlo a fondo, te recomiendo esta &lt;a href="https://builder.aws.com/content/34X2JujaGkTJed5N2KeMYt1Mz9m/como-comenzar-con-kiro-tu-guia-de-primeros-pasos?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;guía de primeros pasos con Kiro&lt;/a&gt;. Pero lo que lo hace especial para este artículo es algo llamado &lt;strong&gt;&lt;a href="https://kiro.dev/powers?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Powers&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un Kiro Power?
&lt;/h2&gt;

&lt;p&gt;Un Power es como darle superpoderes especializados al agente de IA de Kiro.&lt;/p&gt;

&lt;p&gt;Sin un Power, el agente sabe de todo un poco. Con un Power instalado, el agente se convierte en &lt;strong&gt;experto&lt;/strong&gt; en un tema específico.&lt;/p&gt;

&lt;p&gt;Piensa en esto: si le pides a un asistente genérico que te ayude a construir una Durable Function, probablemente te dé una respuesta genérica. Puede que funcione. Puede que no.&lt;/p&gt;

&lt;p&gt;Pero si ese asistente tiene cargado un Power de Lambda Durable Functions, se convierte en un experto que &lt;strong&gt;sabe&lt;/strong&gt; las reglas, los patrones, y las trampas comunes. Y carga esa información dinámicamente según lo que estés haciendo.&lt;/p&gt;

&lt;h2&gt;
  
  
  El Lambda Durable Functions Power
&lt;/h2&gt;

&lt;p&gt;El 5 de marzo de 2026, AWS lanzó el &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/03/lambda-durable-kiro-power/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Kiro Power para Lambda Durable Functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Incluye guía especializada para todo el ciclo de desarrollo: desde el setup del proyecto y las reglas del replay model, pasando por steps, waits, callbacks, ejecución en paralelo, manejo de errores, testing local, hasta deploy con CDK, SAM, o CloudFormation.&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%2F6g0u7skigd98cii83jhf.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%2F6g0u7skigd98cii83jhf.png" alt="Diagrama de lo que incluye el Power — replay model, steps, waits, error handling, testing, deployment" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No tienes que leer toda la documentación antes de empezar. El Power te da lo que necesitas, cuando lo necesitas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalando el Power
&lt;/h2&gt;

&lt;p&gt;Esto es la parte más fácil. Literalmente un clic.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abre Kiro&lt;/li&gt;
&lt;li&gt;Ve al panel de Powers (en la barra lateral)&lt;/li&gt;
&lt;li&gt;En la sección &lt;strong&gt;Available&lt;/strong&gt;, busca "Lambda Durable Functions"&lt;/li&gt;
&lt;li&gt;Haz clic en &lt;strong&gt;Install&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Eso es todo.&lt;/p&gt;

&lt;p&gt;No hay configuración adicional. No hay dependencias que instalar manualmente para el Power. Una vez instalado, el agente de Kiro ya tiene acceso a toda la guía especializada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; No todos los servicios de AWS tienen un Power dedicado. Los Powers son módulos especializados que se van agregando con el tiempo. Puedes explorar los disponibles en el panel de Powers de Kiro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahora sí, vamos a construir algo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisitos
&lt;/h2&gt;

&lt;p&gt;Antes de escribir código, necesitas tener algunas herramientas instaladas. Los siguientes comandos te ayudan a verificar si ya las tienes. Si alguno falla, sigue el link de documentación correspondiente para instalarlo.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS CLI&lt;/strong&gt; instalado (versión 2.33.22 o superior) y &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;configurado con tus credenciales&lt;/a&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--version&lt;/span&gt;
aws sts get-caller-identity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js 22+&lt;/a&gt;&lt;/strong&gt; instalado (para este tutorial usaremos TypeScript):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS CDK&lt;/strong&gt; instalado globalmente (versión 2.237.1 o superior). Este se instala a nivel global en tu máquina, no dentro del proyecto:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; aws-cdk
cdk &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si prefieres Python, &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Lambda Durable Functions&lt;/a&gt; también soporta Python 3.11+. Pero para este tutorial vamos con TypeScript porque es el lenguaje que más uso y el que me resulta más natural para explicar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creando tu primer proyecto
&lt;/h2&gt;

&lt;p&gt;Abre Kiro y crea una carpeta nueva para tu proyecto. Luego, en el chat del agente, puedes pedirle directamente:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Crea un proyecto de Lambda Durable Function con TypeScript y CDK"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El agente, con el Power instalado, va a:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inicializar el proyecto con la estructura correcta&lt;/li&gt;
&lt;li&gt;Instalar las dependencias necesarias&lt;/li&gt;
&lt;li&gt;Configurar TypeScript&lt;/li&gt;
&lt;li&gt;Crear los archivos base&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pero para que entiendas qué está pasando, vamos a hacerlo paso a paso.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inicializar el proyecto
&lt;/h3&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;image-processor
&lt;span class="nb"&gt;cd &lt;/span&gt;image-processor
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Instalar dependencias
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws/durable-execution-sdk-js
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @aws/durable-execution-sdk-js-testing typescript @types/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ese primer paquete es el &lt;a href="https://github.com/aws/aws-durable-execution-sdk-js?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;SDK de Durable Execution&lt;/a&gt;. Es el core de las Durable Functions: lo que hace posible que tu función guarde checkpoints y sobreviva a fallos.&lt;/p&gt;

&lt;p&gt;El segundo paquete (&lt;code&gt;-testing&lt;/code&gt;) es para testear localmente sin necesidad de deployar a AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estructura del proyecto
&lt;/h3&gt;

&lt;p&gt;Kiro va a generar esta estructura por ti cuando le pidas crear el proyecto. Pero si prefieres hacerlo manual, así es como debería verse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image-processor/
├── src/
│   └── handler.ts          # Tu función durable
├── tests/
│   └── handler.test.ts     # Tests locales
├── infrastructure/
│   └── stack.ts             # CDK stack para deploy
├── tsconfig.json
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple. Sin carpetas innecesarias. Sin archivos que no vas a usar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tu primera Durable Function (generada por el Power)
&lt;/h2&gt;

&lt;p&gt;Ahora viene la parte divertida.&lt;/p&gt;

&lt;p&gt;¿Recuerdas el ejemplo del &lt;a href="https://dev.to/aws/lambda-durable-functions-mata-a-step-functions-o-no-2p6c"&gt;artículo anterior&lt;/a&gt;? Un usuario sube una foto y necesitas: validar que sea una imagen válida, redimensionar a diferentes tamaños, aplicar marca de agua, generar thumbnails, y guardar en S3.&lt;/p&gt;

&lt;p&gt;Abre el chat de Kiro y escríbele algo como:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Crea una Durable Function que procese imágenes: validar el archivo, redimensionar, aplicar marca de agua, generar thumbnails y guardar en S3"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El agente, con el Power instalado, &lt;strong&gt;genera el código por ti&lt;/strong&gt;. No copia y pega de internet. Entiende las reglas del replay model, sabe qué va dentro de un step y qué no, y estructura el workflow siguiendo las buenas prácticas del SDK.&lt;/p&gt;

&lt;p&gt;Esto es lo que el Power generó para mí cuando le pedí exactamente eso:&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%2Floq30by0lgdpwou1b7nv.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%2Floq30by0lgdpwou1b7nv.png" alt="Screenshot del agente de Kiro generando el código de la Durable Function en el chat" width="800" height="463"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;outputBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputBucket&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;event&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputPrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputPrefix&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processed&lt;/span&gt;&lt;span class="dl"&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;baseName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.[^&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&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;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.[^&lt;/span&gt;&lt;span class="sr"&gt;.&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&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="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 1: Validate the file&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate-file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;GetObjectCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&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="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&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="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`File not found: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&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;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transformToByteArray&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;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&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;jpeg&lt;/span&gt;&lt;span class="dl"&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;png&lt;/span&gt;&lt;span class="dl"&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;webp&lt;/span&gt;&lt;span class="dl"&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;tiff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`Unsupported image format: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Supported: jpeg, png, webp, tiff`&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File exceeds 50MB limit&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="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File validated&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;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&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="c1"&gt;// Step 2: Resize the image&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resizedBase64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&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;maxWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxWidth&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1920&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;maxHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxHeight&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1080&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;resized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sharp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inside&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;withoutEnlargement&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBuffer&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;resizedKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;outputPrefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;baseName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-resized&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;PutObjectCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;outputBucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resizedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`image/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image resized&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;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resizedKey&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;resized&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;retryStrategy&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;p&gt;Ver codigo completo: &lt;a href="https://github.com/hsaenzG/durable-funtions-demo/blob/main/src/handler.ts" rel="noopener noreferrer"&gt;https://github.com/hsaenzG/durable-funtions-demo/blob/main/src/handler.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Parece código normal, ¿verdad? Y lo es. Pero con superpoderes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Qué está pasando aquí
&lt;/h3&gt;

&lt;p&gt;Cada &lt;code&gt;context.step()&lt;/code&gt; es un &lt;strong&gt;checkpoint&lt;/strong&gt;. Si tu función falla aplicando la marca de agua (paso 3), cuando se reintente, &lt;strong&gt;no va a volver a validar ni redimensionar&lt;/strong&gt;. Salta directamente al paso 3 con los resultados que ya tenía guardados.&lt;/p&gt;

&lt;p&gt;Eso es el replay model en acción. Y para un workflow de procesamiento de imágenes, donde cada paso puede tardar segundos o minutos, no repetir trabajo es la diferencia entre una buena experiencia y una pesadilla.&lt;/p&gt;

&lt;p&gt;Fíjate también en &lt;code&gt;context.logger&lt;/code&gt; en lugar de &lt;code&gt;console.log&lt;/code&gt;: es &lt;strong&gt;replay-aware&lt;/strong&gt;. No duplica logs cuando la función se reintenta.&lt;/p&gt;

&lt;h2&gt;
  
  
  El Kiro Power y la regla de oro del Replay Model
&lt;/h2&gt;

&lt;p&gt;Aquí es donde el Kiro Power realmente brilla. Porque hay una regla que la mayoría no conocemos hasta que algo se rompe:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Todo código no determinístico DEBE ir dentro de un step.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Y el Power te avisa cuando estás a punto de violar esa regla. No tienes que memorizar todos los casos. El agente los detecta y te sugiere la corrección antes de que sea un problema.&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%2F1tzve877ywwkjmlhxyya.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%2F1tzve877ywwkjmlhxyya.png" alt="creenshot del agente de Kiro detectando una violación del replay model y sugiriendo la corrección" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pero, ¿por qué importa tanto esta regla?&lt;/p&gt;

&lt;p&gt;Cuando una Durable Function se reintenta (replay), ejecuta todo el código desde el principio. Los steps que ya completaron se saltan (usa el resultado guardado). Pero el código que está &lt;strong&gt;fuera&lt;/strong&gt; de los steps se ejecuta de nuevo.&lt;/p&gt;

&lt;p&gt;Si ese código da un resultado diferente en el replay... las cosas se rompen.&lt;/p&gt;

&lt;p&gt;¿Qué es código no determinístico? Cualquier cosa que puede dar un resultado diferente cada vez:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Date.now()&lt;/code&gt; → diferente cada vez&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Math.random()&lt;/code&gt; → diferente cada vez&lt;/li&gt;
&lt;li&gt;Llamadas a APIs externas → pueden devolver datos diferentes&lt;/li&gt;
&lt;li&gt;Consultas a bases de datos → los datos pueden haber cambiado&lt;/li&gt;
&lt;li&gt;Generación de UUIDs → diferente cada vez&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Veamos un ejemplo concreto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ MAL: Date.now() fuera de un step&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Diferente en cada replay&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ BIEN: Date.now() dentro del step&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save-with-timestamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Se guarda con el checkpoint&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timestamp&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;Sin el Power, descubrir este tipo de errores es prueba y error. Con el Power, el agente te lo señala mientras escribes.&lt;/p&gt;

&lt;p&gt;Además, puedes instalar el plugin de ESLint para Durable Functions que atrapa estos errores en tiempo de desarrollo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @aws/durable-execution-sdk-js-eslint-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testeando localmente
&lt;/h2&gt;

&lt;p&gt;No necesitas hacer deploy para probar tu función. El SDK incluye un test runner local.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LocalDurableTestRunner&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws/durable-execution-sdk-js-testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image Processing Workflow&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should process an image successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;runner&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;LocalDurableTestRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;skipTime&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-images-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;key&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/photo.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-123&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="c1"&gt;// Verificar que el procesamiento se completó&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalKey&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&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/photo.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Verificar que los steps se ejecutaron&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOperations&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;validateStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate-image&lt;/span&gt;&lt;span class="dl"&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;resizeStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize-image&lt;/span&gt;&lt;span class="dl"&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;watermarkStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apply-watermark&lt;/span&gt;&lt;span class="dl"&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;thumbnailStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;generate-thumbnails&lt;/span&gt;&lt;span class="dl"&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;saveStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;op&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;op&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save-to-s3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validateStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resizeStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;watermarkStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thumbnailStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saveStep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&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;p&gt;El &lt;code&gt;skipTime: true&lt;/code&gt; es clave: hace que los &lt;code&gt;wait&lt;/code&gt; se salten instantáneamente en los tests.&lt;/p&gt;

&lt;p&gt;Y fíjate que buscamos los steps &lt;strong&gt;por nombre&lt;/strong&gt;, no por índice. Eso es una buena práctica que el Power te recuerda constantemente: siempre nombra tus steps de forma descriptiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Haciendo deploy con CDK
&lt;/h2&gt;

&lt;p&gt;Ya tienes tu función funcionando localmente. Ahora toca subirla a AWS.&lt;/p&gt;

&lt;p&gt;Para esto usamos &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/home.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;, que te permite definir tu infraestructura en código (TypeScript, en nuestro caso).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-logs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-iam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DurableFunctionStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&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;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&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;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Log group explícito para mejor control&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LogGroup&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;ImageProcessingLogs&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;logGroupName&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/lambda/imageProcessing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;retention&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RetentionDays&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ONE_WEEK&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="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// La función durable&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Function&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;ImageProcessing&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;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&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_24_X&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.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;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;logGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;durableConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;executionTimeout&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;hours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="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;7&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;// Política de permisos para durable execution&lt;/span&gt;
    &lt;span class="nx"&gt;imageFunction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;addManagedPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ManagedPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAwsManagedPolicyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;service-role/AWSLambdaBasicDurableExecutionRolePolicy&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="c1"&gt;// Crear alias para invocación&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageFunction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentVersion&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;alias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Alias&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;ProdAlias&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;aliasName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CfnOutput&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;FunctionAliasArn&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;functionArn&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lo que importa aquí
&lt;/h3&gt;

&lt;p&gt;Hay tres cosas que no puedes olvidar al hacer deploy de una Durable Function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;durableConfig&lt;/code&gt;&lt;/strong&gt;: Sin esto, tu función es una Lambda normal. El &lt;code&gt;executionTimeout&lt;/code&gt; define cuánto tiempo máximo puede correr tu workflow (hasta 1 año). El &lt;code&gt;retentionPeriod&lt;/code&gt; define cuánto tiempo se guardan los datos de ejecución.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;AWSLambdaBasicDurableExecutionRolePolicy&lt;/code&gt;&lt;/strong&gt;: Esta política le da a tu función permisos para hacer checkpoints (&lt;code&gt;lambda:CheckpointDurableExecution&lt;/code&gt;) y leer el estado de ejecución (&lt;code&gt;lambda:GetDurableExecutionState&lt;/code&gt;). Sin ella, los steps no pueden guardar su progreso.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ARN calificado&lt;/strong&gt;: Las Durable Functions &lt;strong&gt;requieren&lt;/strong&gt; un &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;ARN&lt;/a&gt; calificado para ser invocadas. Un ARN (Amazon Resource Name) es el identificador único de un recurso en AWS. "Calificado" significa que incluye la versión o alias de la función. No puedes invocar una Durable Function con el ARN sin calificar.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ✅ Correcto: con alias&lt;/span&gt;
aws lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; &lt;span class="s1"&gt;'MiStack-MiFuncion-abc123:prod'&lt;/span&gt; response.json

&lt;span class="c"&gt;# ✅ Correcto: con versión&lt;/span&gt;
aws lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; &lt;span class="s1"&gt;'MiStack-MiFuncion-abc123:1'&lt;/span&gt; response.json

&lt;span class="c"&gt;# ❌ Incorrecto: sin calificar — va a fallar&lt;/span&gt;
aws lambda invoke &lt;span class="nt"&gt;--function-name&lt;/span&gt; MiStack-MiFuncion-abc123 response.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; CDK genera nombres de recursos con un sufijo aleatorio (ej: &lt;code&gt;ImageProcessorStack-ImageProcessor5D0B0257-lBARjqDaXdWK&lt;/code&gt;). Puedes encontrar el nombre exacto de tu función en el output del &lt;code&gt;cdk deploy&lt;/code&gt; o en la consola de AWS Lambda.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Compilar TypeScript&lt;/span&gt;
npx tsc

&lt;span class="c"&gt;# Deploy con CDK&lt;/span&gt;
cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CDK se encarga de crear todo: la función, el rol de IAM, los permisos, el log group, la versión y el alias.&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%2Fnds21mbsr10rh5lkkvow.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%2Fnds21mbsr10rh5lkkvow.png" alt="IScreenshot del deploy con CDK ejecutándose en la terminal" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Invocando tu función
&lt;/h2&gt;

&lt;p&gt;Ya está en la nube. Ahora vamos a probarla.&lt;/p&gt;

&lt;p&gt;Primero, sube una imagen de prueba al bucket de S3 que CDK creó:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;tu-imagen.jpg &lt;span class="se"&gt;\&lt;/span&gt;
  s3://TU-BUCKET-S3/photos/test.jpg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; TU-PERFIL &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; El nombre del bucket lo genera CDK automáticamente (ej: &lt;code&gt;imageprocessorstack-imagebucket97210811-x5j3e61lysxh&lt;/code&gt;). Puedes encontrarlo en el output del &lt;code&gt;cdk deploy&lt;/code&gt; o en la consola de S3.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahora sí, invoca la función:&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 invoke &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; &lt;span class="s1"&gt;'TU-NOMBRE-DE-FUNCION:prod'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--invocation-type&lt;/span&gt; Event &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--durable-execution-name&lt;/span&gt; &lt;span class="s2"&gt;"test-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--payload&lt;/span&gt; &lt;span class="s1"&gt;'{"bucket":"TU-BUCKET-S3","key":"photos/test.jpg"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cli-binary-format&lt;/span&gt; raw-in-base64-out &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; TU-PERFIL &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  response.json

&lt;span class="nb"&gt;cat &lt;/span&gt;response.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Reemplaza &lt;code&gt;TU-NOMBRE-DE-FUNCION&lt;/code&gt;, &lt;code&gt;TU-BUCKET-S3&lt;/code&gt; y &lt;code&gt;TU-PERFIL&lt;/code&gt; con los valores reales de tu entorno. Revisa los outputs del &lt;code&gt;cdk deploy&lt;/code&gt; para encontrarlos.&lt;/p&gt;
&lt;/blockquote&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%2F0nkoicfiymikbsnby8we.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%2F0nkoicfiymikbsnby8we.png" alt="Screenshot de la respuesta JSON en la terminal después de invocar la función" width="800" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Algunos detalles sobre estos parámetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--invocation-type Event&lt;/code&gt;&lt;/strong&gt;: Invoca la función de forma asíncrona. Para workflows largos como procesamiento de imágenes, esto es lo recomendado. Si quieres esperar la respuesta, usa &lt;code&gt;RequestResponse&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--durable-execution-name "test-$(date +%s)"&lt;/code&gt;&lt;/strong&gt;: Genera un nombre único por ejecución usando un timestamp. Esto garantiza &lt;strong&gt;idempotencia&lt;/strong&gt;: si invocas con el mismo nombre dos veces, la segunda no crea una ejecución nueva.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--profile&lt;/code&gt; y &lt;code&gt;--region&lt;/code&gt;&lt;/strong&gt;: Si tienes múltiples perfiles de AWS configurados, no olvides especificarlos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monitoreando tus ejecuciones
&lt;/h2&gt;

&lt;p&gt;Ya invocaste tu función. ¿Y ahora? ¿Cómo sabes si funcionó?&lt;/p&gt;

&lt;p&gt;No estás a ciegas. La consola de AWS Lambda tiene una interfaz dedicada para Durable Functions donde puedes ver todo lo que está pasando.&lt;/p&gt;

&lt;p&gt;Ve a tu función en la consola y busca la pestaña &lt;strong&gt;Durable executions&lt;/strong&gt;. Ahí vas a encontrar la lista de todas las ejecuciones con su estado: running, completed, failed.&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%2Fo1w5zhcbyzwd0l8gko8n.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%2Fo1w5zhcbyzwd0l8gko8n.png" alt="Screenshot de la consola de AWS Lambda mostrando la lista de ejecuciones durables con sus estados" width="800" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Haz clic en cualquier ejecución y vas a ver el detalle completo: qué steps se completaron, cuáles fallaron, cuánto tardó cada uno, y los datos que se guardaron en cada checkpoint.&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%2F9c9g5im3wvekd34m1ol2.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%2F9c9g5im3wvekd34m1ol2.png" alt="Screenshot del detalle de una ejecución durable mostrando los steps completados y sus resultados" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto es oro para debuggear. Si algo falló en el paso 3, puedes ver exactamente qué datos tenía en ese momento y qué error se produjo. Sin adivinar. Sin buscar en CloudWatch a ciegas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué esto importa si estás empezando
&lt;/h2&gt;

&lt;p&gt;Sin el Power, el camino típico es: leer toda la documentación, tropezar con el replay model, configurar el proyecto a mano, y descubrir errores de deploy por prueba y error.&lt;/p&gt;

&lt;p&gt;Con el Power, el agente te guía en cada paso. No elimina la necesidad de entender los conceptos (eso sigue siendo importante). Pero reduce drásticamente el tiempo entre "quiero aprender Durable Functions" y "tengo una funcionando en producción".&lt;/p&gt;

&lt;h2&gt;
  
  
  Limpieza de recursos
&lt;/h2&gt;

&lt;p&gt;Si solo estás probando, recuerda eliminar los recursos para evitar cargos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cdk destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto elimina la función Lambda, el rol de IAM, el log group, y todos los recursos asociados. CDK se encarga de todo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que aprendiste
&lt;/h2&gt;

&lt;p&gt;Instalaste un Kiro Power con un clic, creaste un proyecto desde cero, dejaste que el agente generara tu primera Durable Function con el mismo ejemplo de procesamiento de imágenes del artículo anterior, entendiste la regla de oro del replay model, testeaste localmente sin deploy, y subiste todo a AWS con CDK.&lt;/p&gt;

&lt;p&gt;De cero a producción. Con IA guiándote en cada paso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué sigue
&lt;/h2&gt;

&lt;p&gt;Ya tienes el workflow de procesamiento de imágenes funcionando. Pero lo construimos en el camino feliz: todo sale bien, nada falla.&lt;/p&gt;

&lt;p&gt;En el próximo artículo vamos a &lt;strong&gt;romper cosas a propósito&lt;/strong&gt;. Vamos a ver cómo los checkpoints automáticos mantienen tu progreso incluso cuando algo truena, y cómo el replay model recupera la ejecución exactamente donde quedó.&lt;/p&gt;

&lt;p&gt;Código real. Fallos reales. Recuperación real.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Te resultó útil este artículo?&lt;/strong&gt; Compártelo con tu equipo o déjame saber en los comentarios qué otros temas de serverless te gustaría que cubriera. Y si ya instalaste el Kiro Power y estás construyendo tu primera Durable Function, me encantaría escuchar tu experiencia.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cold Starts en AWS Lambda: Qué son, por qué ocurren y cómo solucionarlos</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Mon, 16 Mar 2026 17:08:25 +0000</pubDate>
      <link>https://dev.to/aws/cold-starts-en-aws-lambda-que-son-por-que-ocurren-y-como-solucionarlos-13no</link>
      <guid>https://dev.to/aws/cold-starts-en-aws-lambda-que-son-por-que-ocurren-y-como-solucionarlos-13no</guid>
      <description>&lt;p&gt;&lt;em&gt;Todo lo que necesitas saber sobre cold starts en Lambda y las estrategias para reducir su impacto.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;La primera vez que me topé con un cold start, no tenía idea de qué estaba pasando.&lt;/p&gt;

&lt;p&gt;Había terminado de deployar una API con Lambda para un proyecto en el que estaba trabajando. Todo funcionaba. Los tests pasaban. El endpoint respondía rápido. Estaba feliz.&lt;/p&gt;

&lt;p&gt;Hasta que un compañero me escribió: "Oye, a veces la API tarda como 3 segundos en responder. ¿Es normal?"&lt;/p&gt;

&lt;p&gt;Mi primera reacción fue: "No puede ser, a mí me responde en 200ms". Así que abrí CloudWatch, empecé a revisar los logs... y ahí lo vi. Un &lt;code&gt;INIT&lt;/code&gt; duration de 2.8 segundos que aparecía de vez en cuando, sin patrón aparente. No había error. No había timeout. Solo... lentitud.&lt;/p&gt;

&lt;p&gt;Pasé un buen rato buscando qué significaba ese &lt;code&gt;INIT&lt;/code&gt;. ¿Era un bug? ¿Algo que configuré mal? ¿Un problema de red?&lt;/p&gt;

&lt;p&gt;No. Era un cold start.&lt;/p&gt;

&lt;p&gt;Y cuando entendí qué era y por qué pasaba, todo empezó a tener sentido. Esas peticiones lentas no eran aleatorias. Eran el precio de no tener servidores corriendo 24/7.&lt;/p&gt;

&lt;p&gt;Si alguna vez sentiste que tu función Lambda "se dormía" y tardaba en despertar, este artículo es para ti. Te voy a contar todo lo que aprendí sobre cold starts: qué son, por qué ocurren, y las estrategias que uso para reducir su impacto.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un cold start?
&lt;/h2&gt;

&lt;p&gt;Cuando invocas una función Lambda, AWS necesita un lugar donde ejecutar tu código. Ese lugar se llama &lt;strong&gt;execution environment&lt;/strong&gt;: un contenedor aislado con su runtime, tu código, y las dependencias que necesita.&lt;/p&gt;

&lt;p&gt;Si ya existe un environment disponible (porque tu función se ejecutó hace poco), Lambda lo reutiliza. Eso es un &lt;strong&gt;warm start&lt;/strong&gt;. Rápido. Sin sorpresas.&lt;/p&gt;

&lt;p&gt;Pero si no hay ninguno disponible — porque es la primera invocación, porque pasó mucho tiempo sin actividad, o porque hay un pico de tráfico y Lambda necesita crear más environments — entonces tiene que crear uno nuevo desde cero.&lt;/p&gt;

&lt;p&gt;Eso es un &lt;strong&gt;cold start&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyofixknlxsvwhity8ieq.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%2Fyofixknlxsvwhity8ieq.png" alt="Diagrama comparando warm start vs cold start — mostrando las fases adicionales del cold start" width="800" height="142"&gt;&lt;/a&gt;&lt;br&gt;
Y crear un environment desde cero no es instantáneo. Lambda tiene que hacer varias cosas antes de que tu código empiece a ejecutarse:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Container Provisioning&lt;/strong&gt;: asignar los recursos de cómputo según la memoria configurada&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime Initialization&lt;/strong&gt;: cargar el runtime del lenguaje (Python, Node.js, Java, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function Code Loading&lt;/strong&gt;: descargar y desempaquetar tu código&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Resolution&lt;/strong&gt;: cargar las librerías y paquetes que tu función necesita&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Todo eso es la &lt;strong&gt;fase de inicialización&lt;/strong&gt; (Init phase). Y esa latencia adicional es lo que llamamos cold start.&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%2Fkvsz28wfsv0kansff8sp.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%2Fkvsz28wfsv0kansff8sp.png" alt="Diagrama de las fases del cold start — Container Provisioning → Runtime Init → Code Loading → Dependency Resolution → Function Execution" width="800" height="105"&gt;&lt;/a&gt;&lt;br&gt;
La buena noticia: el cold start solo ocurre &lt;strong&gt;una vez&lt;/strong&gt; por ciclo de vida del environment. Una vez que el environment está listo, las siguientes invocaciones son warm starts.&lt;/p&gt;

&lt;p&gt;La otra buena noticia: según AWS, los cold starts típicamente afectan &lt;strong&gt;menos del 1% de las invocaciones&lt;/strong&gt;. Pero ese 1% puede ser un problema si tu aplicación es sensible a la latencia.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Por qué ocurren?
&lt;/h2&gt;

&lt;p&gt;Los cold starts no son un bug. Son una consecuencia natural de cómo funciona el modelo serverless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eficiencia de recursos&lt;/strong&gt;: no pagas cuando tu código no se ejecuta. Eso es genial para tu billetera, pero significa que Lambda apaga los environments que llevan tiempo sin usarse. Cuando llega una nueva invocación, tiene que crear uno nuevo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aislamiento de seguridad&lt;/strong&gt;: cada execution environment es independiente. No comparte memoria ni estado con otros. Esa seguridad requiere crear un environment fresco cada vez.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-scaling&lt;/strong&gt;: cuando llega un pico de tráfico, Lambda crea nuevos environments para manejar la carga. Cada environment nuevo pasa por la fase de inicialización.&lt;/p&gt;

&lt;p&gt;En resumen: los cold starts son el precio que pagas por no tener que administrar servidores. Y en la mayoría de los casos, es un precio muy bajo.&lt;/p&gt;

&lt;p&gt;Pero cuando sí importa — APIs de usuario, microservicios interactivos, flujos donde cada segundo cuenta — necesitas saber cómo reducirlos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Factores que influyen en la duración
&lt;/h2&gt;

&lt;p&gt;No todos los cold starts son iguales. Algunos duran 100 milisegundos. Otros duran 5 segundos. La diferencia depende de varios factores.&lt;/p&gt;
&lt;h3&gt;
  
  
  Runtime
&lt;/h3&gt;

&lt;p&gt;Los lenguajes interpretados como Python y Node.js inicializan más rápido que los compilados como Java o .NET.&lt;/p&gt;

&lt;p&gt;¿Por qué? Java necesita cargar la JVM y hacer JIT compilation. .NET tiene un proceso similar. Python y Node.js simplemente cargan el intérprete y empiezan a ejecutar.&lt;/p&gt;

&lt;p&gt;Eso no significa que debas elegir tu lenguaje solo por el cold start. Pero es un factor a considerar si la latencia es crítica.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tamaño del paquete
&lt;/h3&gt;

&lt;p&gt;Más grande el paquete = más tiempo para descargarlo, descomprimirlo e inicializarlo.&lt;/p&gt;

&lt;p&gt;Si tu función incluye dependencias que no usa, estás pagando cold start por código que nunca se ejecuta. Un paquete de 5 MB inicializa mucho más rápido que uno de 250 MB.&lt;/p&gt;
&lt;h3&gt;
  
  
  Memoria asignada
&lt;/h3&gt;

&lt;p&gt;Esto es contraintuitivo: &lt;strong&gt;más memoria = cold starts más rápidos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;¿Por qué? Porque Lambda asigna CPU proporcionalmente a la memoria. Más memoria significa más CPU, y más CPU significa que la inicialización se completa más rápido.&lt;/p&gt;

&lt;p&gt;A veces, subir la memoria de 128 MB a 512 MB reduce el cold start significativamente, y el costo adicional es mínimo porque la función termina más rápido.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuración de red (VPC)
&lt;/h3&gt;

&lt;p&gt;Si tu función está dentro de una &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;VPC&lt;/a&gt;, Lambda necesita crear una Elastic Network Interface (ENI) para conectarla a la red. Eso agrega latencia al cold start.&lt;/p&gt;

&lt;p&gt;AWS mejoró esto significativamente con &lt;a href="https://aws.amazon.com/blogs/compute/announcing-improved-vpc-networking-for-aws-lambda-functions/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Hyperplane&lt;/a&gt;, que redujo la latencia de VPC de segundos a milisegundos. Pero sigue siendo un factor si tu función necesita acceso a recursos dentro de una VPC.&lt;/p&gt;
&lt;h3&gt;
  
  
  Inicialización estática
&lt;/h3&gt;

&lt;p&gt;Todo el código que se ejecuta &lt;strong&gt;fuera del handler&lt;/strong&gt; se ejecuta durante la fase Init. Si estás importando 15 librerías, creando conexiones a bases de datos, y cargando archivos de configuración... todo eso suma al cold start.&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;# Todo esto se ejecuta durante el Init (cold start)
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&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;langchain&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LLMChain&lt;/span&gt;

&lt;span class="n"&gt;s3_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;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&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;my-table&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="c1"&gt;# Esto se ejecuta en cada invocación (warm o cold)
&lt;/span&gt;    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La inicialización estática es un arma de doble filo: quieres inicializar cosas fuera del handler para reutilizarlas en warm starts, pero todo lo que pongas ahí aumenta el cold start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estrategias de optimización (sin costo adicional)
&lt;/h2&gt;

&lt;p&gt;Antes de llegar a las soluciones de AWS que cuestan dinero, hay varias cosas que puedes hacer gratis.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Importa solo lo necesario
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ❌ Importa todo el SDK
&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;# ✅ Importa solo lo que necesitas
&lt;/span&gt;&lt;span class="kn"&gt;from&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;client&lt;/span&gt;
&lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&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;s3&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;h3&gt;
  
  
  2. Mantén tus paquetes pequeños
&lt;/h3&gt;

&lt;p&gt;Elimina dependencias que no uses. Usa &lt;a href="https://aws.amazon.com/blogs/compute/optimizing-node-js-dependencies-in-aws-lambda/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;tree shaking&lt;/a&gt; en Node.js. Excluye archivos de tests, documentación, y ejemplos de tus paquetes de deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Inicializa clientes fuera del handler
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ✅ Se inicializa una vez y se reutiliza en warm starts
&lt;/span&gt;&lt;span class="n"&gt;s3_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;s3&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="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&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-bucket&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Asigna memoria adecuada
&lt;/h3&gt;

&lt;p&gt;No te quedes con los 128 MB por defecto si tu función carga dependencias pesadas. Experimenta con 256 MB, 512 MB, o más. Usa &lt;a href="https://docs.aws.amazon.com/lambda/latest/operatorguide/profile-functions.html/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;AWS Lambda Power Tuning&lt;/a&gt; para encontrar el balance óptimo entre costo y rendimiento.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Usa layers para dependencias compartidas
&lt;/h3&gt;

&lt;p&gt;Si varias funciones usan las mismas dependencias, empaquétalas en un &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Lambda Layer&lt;/a&gt;. Esto no reduce el cold start directamente, pero te ayuda a mantener paquetes organizados y más fáciles de optimizar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provisioned Concurrency: environments siempre calientes
&lt;/h2&gt;

&lt;p&gt;Si las optimizaciones de código no son suficientes, AWS tiene dos soluciones dedicadas. La primera es &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Provisioned Concurrency&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La idea es simple: le dices a Lambda "mantén X environments siempre listos". Lambda los pre-inicializa y los mantiene calientes, esperando invocaciones.&lt;/p&gt;

&lt;p&gt;Resultado: &lt;strong&gt;cero cold starts&lt;/strong&gt; para esas invocaciones. Respuestas en milisegundos de doble dígito.&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;# Configurar 10 environments siempre listos&lt;/span&gt;
aws lambda put-provisioned-concurrency-config &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--function-name&lt;/span&gt; my-function &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--qualifier&lt;/span&gt; prod &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provisioned-concurrent-executions&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cuándo usarlo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tu aplicación tiene requisitos estrictos de latencia (APIs de usuario, microservicios interactivos)&lt;/li&gt;
&lt;li&gt;El tráfico es predecible o puedes configurar auto-scaling&lt;/li&gt;
&lt;li&gt;Estás dispuesto a pagar por environments que están listos aunque no se usen&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cuándo NO usarlo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tráfico esporádico o impredecible (vas a pagar por environments idle)&lt;/li&gt;
&lt;li&gt;Workloads asíncronos donde la latencia no es crítica (procesamiento de datos, colas)&lt;/li&gt;
&lt;li&gt;Tu presupuesto es ajustado&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Nota importante:&lt;/strong&gt; Provisioned Concurrency tiene un costo adicional. Pagas por cada environment provisionado, esté o no procesando invocaciones. Pero si la latencia es crítica para tu negocio, el costo vale la pena.&lt;/p&gt;

&lt;p&gt;También puedes combinar Provisioned Concurrency con &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html#managing-provisioned-concurency/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Application Auto Scaling&lt;/a&gt; para ajustar automáticamente la cantidad de environments según el tráfico. Puedes usar scheduled scaling (para patrones predecibles) o target tracking (para ajuste dinámico).&lt;/p&gt;

&lt;h2&gt;
  
  
  SnapStart: snapshots del environment inicializado
&lt;/h2&gt;

&lt;p&gt;La segunda solución es &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Lambda SnapStart&lt;/a&gt;. Y funciona de una manera completamente diferente.&lt;/p&gt;

&lt;p&gt;En lugar de mantener environments calientes, SnapStart toma una &lt;strong&gt;foto&lt;/strong&gt; (snapshot) del environment después de que se inicializa. Cuando llega una invocación, en lugar de inicializar desde cero, Lambda &lt;strong&gt;restaura&lt;/strong&gt; el environment desde esa foto.&lt;/p&gt;

&lt;p&gt;El resultado: cold starts que bajan de varios segundos a &lt;strong&gt;sub-segundo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1jn48dxx7m1l6z8b3xy.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%2Fj1jn48dxx7m1l6z8b3xy.png" alt="Diagrama comparando el flujo normal (Init completo) vs el flujo con SnapStart" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Runtimes soportados
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Java 11+&lt;/li&gt;
&lt;li&gt;Python 3.12+&lt;/li&gt;
&lt;li&gt;.NET 8+&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cuándo usarlo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Funciones con inicialización pesada (dependencias grandes, frameworks, modelos ML)&lt;/li&gt;
&lt;li&gt;Invocaciones frecuentes a escala&lt;/li&gt;
&lt;li&gt;Quieres reducir cold starts sin el costo de Provisioned Concurrency&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cuándo NO usarlo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Funciones que ya inicializan en milisegundos (no vas a notar la diferencia)&lt;/li&gt;
&lt;li&gt;Necesitas latencia garantizada de doble dígito de milisegundos (usa Provisioned Concurrency)&lt;/li&gt;
&lt;li&gt;Tu función usa EFS, Provisioned Concurrency, o almacenamiento efímero mayor a 512 MB (no es compatible)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SnapStart es especialmente interesante para &lt;strong&gt;Python&lt;/strong&gt;, donde cargar dependencias como Pandas, NumPy, LangChain, o frameworks como Flask y Django puede tomar varios segundos.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;En el próximo artículo de esta serie, vamos a profundizar en SnapStart para Python&lt;/strong&gt;: cómo funciona internamente, cómo activarlo paso a paso, cómo usar runtime hooks, y las mejores prácticas para sacarle el máximo provecho.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cuál estrategia elegir?
&lt;/h2&gt;

&lt;p&gt;No es "una u otra". Puedes (y deberías) combinarlas.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Estrategia&lt;/th&gt;
&lt;th&gt;Latencia&lt;/th&gt;
&lt;th&gt;Costo adicional&lt;/th&gt;
&lt;th&gt;Ideal para&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Optimización de código&lt;/td&gt;
&lt;td&gt;Reduce el Init&lt;/td&gt;
&lt;td&gt;Ninguno&lt;/td&gt;
&lt;td&gt;Siempre. Es el primer paso&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SnapStart&lt;/td&gt;
&lt;td&gt;Sub-segundo&lt;/td&gt;
&lt;td&gt;Costo de cache + restauración&lt;/td&gt;
&lt;td&gt;Funciones con init pesado a escala&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provisioned Concurrency&lt;/td&gt;
&lt;td&gt;Milisegundos&lt;/td&gt;
&lt;td&gt;Pago por environment provisionado&lt;/td&gt;
&lt;td&gt;Latencia ultra-baja garantizada&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;La recomendación:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Siempre&lt;/strong&gt; optimiza tu código primero. Es gratis y ayuda en todos los escenarios.&lt;/li&gt;
&lt;li&gt;Si después de optimizar sigues teniendo cold starts largos y tu función se invoca frecuentemente, &lt;strong&gt;prueba SnapStart&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Si necesitas latencia garantizada de milisegundos sin excepciones, &lt;strong&gt;usa Provisioned Concurrency&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;📊 Árbol de decisión (haz clic para expandir)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fguj5dptyxiu7epcx2xds.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%2Fguj5dptyxiu7epcx2xds.png" alt="Diagrama comparando el flujo normal (Init completo) vs el flujo con SnapStart (restaurar desde snapshot)" width="800" height="1779"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoreo: cómo saber si tienes un problema
&lt;/h2&gt;

&lt;p&gt;Antes de optimizar, necesitas medir. No asumas que tienes un problema de cold starts solo porque "a veces se siente lento".&lt;/p&gt;

&lt;p&gt;Si quieres ir más a fondo en el tema de diagnóstico y optimización de rendimiento en Lambda, te recomiendo este artículo donde comparto mi experiencia: &lt;a href="https://dev.to/aws-espanol/eleva-el-rendimiento-de-aws-lambda-7il"&gt;Eleva el rendimiento de AWS Lambda&lt;/a&gt;. Ahí cubro métricas de invocación, benchmarks, y estrategias prácticas para llevar tus funciones al siguiente nivel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que aprendiste
&lt;/h2&gt;

&lt;p&gt;Los cold starts son parte natural del modelo serverless. No son un bug, son un trade-off por no administrar servidores. Afectan menos del 1% de las invocaciones, pero cuando importan, importan mucho.&lt;/p&gt;

&lt;p&gt;La duración depende del runtime, el tamaño del paquete, la memoria asignada, y la configuración de red. Optimizar el código es siempre el primer paso y no cuesta nada. Provisioned Concurrency y SnapStart son las dos soluciones de AWS cuando necesitas ir más allá.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué sigue
&lt;/h2&gt;

&lt;p&gt;Ya entiendes qué son los cold starts y las estrategias para combatirlos. En el próximo artículo vamos a profundizar en &lt;strong&gt;Lambda SnapStart para Python&lt;/strong&gt;: cómo funciona por debajo (Firecracker snapshots, cache en dos niveles), cómo activarlo paso a paso, cómo usar runtime hooks, y las mejores prácticas para sacarle el máximo provecho a tus funciones Python.&lt;/p&gt;

&lt;p&gt;Código real. Configuración real. Resultados reales.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Te resultó útil este artículo?&lt;/strong&gt; Compártelo con tu equipo o déjame saber en los comentarios qué otros temas de serverless te gustaría que cubriera. Y si ya estás lidiando con cold starts en producción, me encantaría escuchar cómo los resolviste.&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>performance</category>
      <category>español</category>
      <category>aws</category>
    </item>
    <item>
      <title>Lambda Durable Functions mata a Step Functions... ¿o no?</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Thu, 12 Mar 2026 00:26:59 +0000</pubDate>
      <link>https://dev.to/aws/lambda-durable-functions-mata-a-step-functions-o-no-2p6c</link>
      <guid>https://dev.to/aws/lambda-durable-functions-mata-a-step-functions-o-no-2p6c</guid>
      <description>&lt;p&gt;La verdad sobre cuándo usar cada una (y por qué necesitas entender ambas).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Al final de este artículo, sabrás exactamente cuándo elegir cada una.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Cuando AWS anunció &lt;a href="https://aws.amazon.com/blogs/aws/build-multi-step-applications-and-ai-workflows-with-aws-lambda-durable-functions/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Lambda Durable Functions&lt;/a&gt; en re:Invent 2025, mi primera reacción fue:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Espera... ¿no es eso lo que hace Step Functions?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Y no fui la única. En conversaciones con otros devs, la pregunta era siempre la misma:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Por qué dos herramientas para lo mismo?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Si ya tengo &lt;a href="https://docs.aws.amazon.com/step-functions/?trk=b4df06f7-1a05-4faf-a488-43ff27da389d&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Step Functions&lt;/a&gt; orquestando workflows, ¿para qué necesito Durable Functions? ¿Es un reemplazo? ¿Debería migrar todo? Pasé días leyendo la documentación, probando ejemplos, y tratando de entender la diferencia real. Y descubrí algo que casi nadie estaba diciendo:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No son lo mismo. Ni siquiera intentan serlo.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  La respuesta corta: No
&lt;/h2&gt;

&lt;p&gt;Lambda Durable Functions no mata a Step Functions. Son dos filosofías diferentes para resolver el mismo problema. Step Functions orquesta visualmente, Durable Functions orquesta en código. Y aquí está lo interesante: ambas tienen su lugar. No es "una u otra". Es "cuál para qué".&lt;/p&gt;

&lt;h2&gt;
  
  
  El problema que ambas resuelven
&lt;/h2&gt;

&lt;p&gt;Antes de hablar de diferencias, hay que entender qué problema están resolviendo.&lt;/p&gt;

&lt;p&gt;Imagina que estás construyendo un sistema de procesamiento de imágenes. Un usuario sube una foto y necesitas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validar que el archivo es una imagen válida&lt;/li&gt;
&lt;li&gt;Redimensionar a diferentes tamaños&lt;/li&gt;
&lt;li&gt;Aplicar marca de agua&lt;/li&gt;
&lt;li&gt;Generar thumbnails&lt;/li&gt;
&lt;li&gt;Optimizar y guardar en S3&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Suena simple, ¿no?&lt;/p&gt;

&lt;p&gt;Pero cada paso puede fallar.&lt;br&gt;&lt;br&gt;
Cada paso puede tardar segundos... o minutos.&lt;br&gt;&lt;br&gt;
Y necesitas mantener el estado del procesamiento a través de todo el flujo.&lt;/p&gt;

&lt;p&gt;Si la validación falla, no puedes continuar.&lt;br&gt;&lt;br&gt;
Si el redimensionamiento truena, necesitas reintentarlo sin volver a validar.&lt;br&gt;&lt;br&gt;
Si algo falla a la mitad, necesitas saber exactamente dónde quedó todo.&lt;/p&gt;

&lt;p&gt;Esto es &lt;strong&gt;orquestación de workflows&lt;/strong&gt;: coordinar múltiples pasos sin perder el estado, manejando errores y reintentos de forma elegante.&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%2Fnfzbyb1binxdui7s5bk4.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%2Fnfzbyb1binxdui7s5bk4.png" alt="workflow" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tanto Step Functions como Durable Functions resuelven esto. Pero lo hacen de maneras completamente diferentes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step Functions: El enfoque visual
&lt;/h2&gt;

&lt;p&gt;Step Functions es &lt;strong&gt;declarativo&lt;/strong&gt;. Eso significa que defines &lt;em&gt;qué&lt;/em&gt; debe pasar, no &lt;em&gt;cómo&lt;/em&gt; hacerlo. Piensa en pedir un Uber: dices "llévame al aeropuerto" y alguien más decide la ruta, los giros, las autopistas. Tú solo declaras el destino.&lt;/p&gt;

&lt;p&gt;Así se ve un workflow en Step Functions:&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%2Fjsc39ypuhxs2zw0a6gu7.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%2Fjsc39ypuhxs2zw0a6gu7.png" alt="Step Functions" width="692" height="1148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En el código del workflow en Step Functions no estás escribiendo código que ejecuta cada paso. Estás describiendo el flujo. Y AWS se encarga del resto: mantener el estado, manejar errores, reintentar cuando falla algo.&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;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ValidateImage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ValidateImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:...:function:ValidateImage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ResizeImage"&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;"ResizeImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:...:function:ResizeImage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ApplyWatermark"&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;"ApplyWatermark"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:...:function:ApplyWatermark"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GenerateThumbnails"&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;"GenerateThumbnails"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:...:function:GenerateThumbnails"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SaveToS3"&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;"SaveToS3"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:...:function:SaveToS3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cuándo brilla Step Functions
&lt;/h3&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%2Fyv7h8zr9yyrmn67l9lh1.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%2Fyv7h8zr9yyrmn67l9lh1.png" alt="Step Functions" width="800" height="336"&gt;&lt;/a&gt;&lt;br&gt;
Hay escenarios donde este enfoque visual es perfecto:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflows con múltiples ramas y condiciones complejas&lt;/strong&gt;&lt;br&gt;
Si tu flujo tiene muchos "si esto, entonces aquello", Step Functions te deja verlo todo de un vistazo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Equipos no técnicos necesitan entender la lógica&lt;/strong&gt;&lt;br&gt;
Product managers, QA, stakeholders... todos pueden abrir la consola de AWS y ver exactamente qué está pasando.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;El workflow cambia frecuentemente&lt;/strong&gt;&lt;br&gt;
Ajustar un JSON es más rápido que reescribir código, hacer tests y deployar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integraciones directas con servicios AWS&lt;/strong&gt;&lt;br&gt;
DynamoDB, SNS, SQS... Step Functions los conecta sin escribir código.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Lambda Durable Functions: El enfoque code-first
&lt;/h2&gt;

&lt;p&gt;Durable Functions es completamente diferente. Aquí no describes el flujo. Lo escribes.&lt;/p&gt;

&lt;p&gt;Es &lt;strong&gt;code-first&lt;/strong&gt;: código que ejecuta paso a paso, con checkpoints automáticos que mantienen el estado. Siguiendo la analogía del Uber: aquí tú manejas. Gira a la izquierda, sigue derecho tres cuadras, toma la autopista, sal en la salida 12. Tú controlas cada paso del camino.&lt;/p&gt;

&lt;p&gt;Así se ve el mismo workflow en Durable Functions:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws/durable-execution-sdk-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Cada step es un checkpoint automático&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="nf"&gt;validateImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;resized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize-image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="nf"&gt;resizeImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validated&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;watermarked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apply-watermark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="nf"&gt;applyWatermark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resized&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;watermarked&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;Parece código normal, ¿verdad? Y lo es. Pero con un superpoder: cada &lt;code&gt;step&lt;/code&gt; es un checkpoint. Si algo falla, el workflow se reanuda exactamente donde quedó. No pierdes estado. No repites trabajo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cuándo brilla Durable Functions
&lt;/h3&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%2Fkucx9omblni06iyt9r9w.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%2Fkucx9omblni06iyt9r9w.png" alt="Durable Functions" width="800" height="336"&gt;&lt;/a&gt;&lt;br&gt;
Este enfoque tiene sus propios momentos de gloria:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflows secuenciales con lógica compleja&lt;/strong&gt; &lt;br&gt;
Si tu flujo es más "haz esto, luego esto, luego esto" y menos "si esto entonces aquello", el código es más natural.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tu equipo vive en el IDE&lt;/strong&gt;&lt;br&gt;
Developers que prefieren escribir código, hacer tests unitarios, usar breakpoints... esto se siente como casa.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Necesitas reutilizar lógica existente&lt;/strong&gt;&lt;br&gt;
Si ya tienes funciones de negocio en tu codebase, las puedes llamar directamente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transformaciones de datos complejas entre pasos&lt;/strong&gt;&lt;br&gt;
Escribir esa lógica en código es más claro que en JSON.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Las diferencias que importan
&lt;/h2&gt;

&lt;p&gt;Ahora que viste ambos enfoques, aquí están las diferencias que realmente afectan tu decisión:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspecto&lt;/th&gt;
&lt;th&gt;Step Functions&lt;/th&gt;
&lt;th&gt;Durable Functions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modelo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Declarativo (JSON/YAML)&lt;/td&gt;
&lt;td&gt;Code-first (Python, Node.js, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Visualización&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nativa en consola AWS&lt;/td&gt;
&lt;td&gt;Requiere herramientas externas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Debugging&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logs y trazas visuales&lt;/td&gt;
&lt;td&gt;Breakpoints tradicionales&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complejidad&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excelente para flujos con branches&lt;/td&gt;
&lt;td&gt;Excelente para lógica secuencial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Curva de aprendizaje&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sintaxis específica de ASL&lt;/td&gt;
&lt;td&gt;Tu lenguaje de programación&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Límite de payload&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;256 KB entre estados&lt;/td&gt;
&lt;td&gt;6 MB entre pasos&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No es que una sea mejor que la otra. Es que cada una brilla en escenarios diferentes.&lt;/p&gt;
&lt;h3&gt;
  
  
  El límite de payload: un detalle que importa
&lt;/h3&gt;

&lt;p&gt;Hay algo que muchos descubren tarde: &lt;strong&gt;Step Functions tiene un límite de 256 KB&lt;/strong&gt; para los datos que pasan entre estados.&lt;/p&gt;

&lt;p&gt;Suena como mucho, hasta que no lo es.&lt;/p&gt;

&lt;p&gt;Imagina que estás procesando una imagen grande con metadata extensa. O generando múltiples variaciones con información de cada una. O trabajando con respuestas de APIs que devuelven arrays grandes de datos de procesamiento.&lt;/p&gt;

&lt;p&gt;De repente, ese límite de 256 KB se siente pequeño.&lt;/p&gt;

&lt;p&gt;La solución típica es guardar los datos en S3 y pasar solo la referencia:&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;"imageLocation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3://my-bucket/processed/image-123.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&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;"width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1080&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;Funciona, pero agrega complejidad: más código, más servicios, más cosas que pueden fallar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Durable Functions tiene un límite mucho más generoso&lt;/strong&gt;: 6 MB entre pasos. Eso es 24 veces más espacio.&lt;/p&gt;

&lt;p&gt;No significa que debas pasar 6 MB de datos entre pasos (probablemente no deberías). Pero sí significa que tienes más margen antes de necesitar workarounds.&lt;/p&gt;

&lt;p&gt;Si tu workflow maneja datos grandes, esta diferencia puede ser decisiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuándo usar cada una
&lt;/h2&gt;

&lt;p&gt;Aquí está la parte más importante del artículo. La pregunta no es "¿cuál es mejor?" sino "¿cuál necesito para este problema específico?"&lt;/p&gt;

&lt;h3&gt;
  
  
  Usa AWS Step Functions cuando:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tu workflow tiene múltiples ramas condicionales (if/else complejos) → La visualización te ayuda a no perderte.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Necesitas que stakeholders no técnicos vean y entiendan el flujo → Abrir la consola de AWS es más fácil que explicar código.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El workflow cambia frecuentemente → Ajustar JSON es más rápido que reescribir, testear y deployar código.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quieres visualización nativa sin configuración adicional → AWS te da todo out-of-the-box.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trabajas con servicios AWS que tienen integraciones directas → DynamoDB, SNS, SQS... Step Functions los conecta sin escribir código.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Usa Durable Functions cuando:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tu workflow es principalmente secuencial con lógica compleja → El código es más natural que describir cada paso en JSON.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tu equipo prefiere trabajar completamente en código → IDE, tests unitarios, control de versiones... todo en un solo lugar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Necesitas reutilizar lógica de negocio existente → Llamas funciones que ya tienes, sin adaptarlas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quieres debugging tradicional con breakpoints → Step-through, inspección de variables, todo lo que ya conoces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;El workflow requiere transformaciones de datos complejas entre pasos → Escribir esa lógica en código es más claro que en JSON.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Si después de leer esto sigues sin estar seguro... probablemente Step Functions es tu mejor opción. La visualización ayuda más de lo que crees cuando estás empezando.&lt;/p&gt;

&lt;p&gt;Y si quieres una forma rápida de recordarlo:&lt;/p&gt;

&lt;p&gt;📊 *&lt;em&gt;Árbol de decisión *&lt;/em&gt;&lt;br&gt;
Te dejo este árbol de decisión que puedes guardar o imprimir para tenerlo a mano cuando necesites elegir: &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%2F69mrx54mdnaap3aizfpp.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%2F69mrx54mdnaap3aizfpp.png" alt="arbol de decision" width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  La verdad: se complementan
&lt;/h2&gt;

&lt;p&gt;Aquí está el secreto que casi nadie menciona: &lt;strong&gt;Puedes usar ambas en la misma arquitectura.&lt;/strong&gt; Imagina una arquitectura donde:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step Functions&lt;/strong&gt; orquesta el flujo principal de la aplicación:&lt;br&gt;&lt;br&gt;
→ Recibe la imagen&lt;br&gt;
→ Valida formato&lt;br&gt;
→ Procesa transformaciones&lt;br&gt;
→ Notifica al usuario&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Durable Functions&lt;/strong&gt; maneja sub-procesos complejos dentro de cada paso:&lt;br&gt;&lt;br&gt;
→ Aplicar múltiples filtros con lógica compleja&lt;br&gt;
→ Detección de contenido con reglas de negocio&lt;br&gt;
→ Transformaciones de metadata entre sistemas&lt;/p&gt;

&lt;p&gt;Step Functions te da la vista de 10,000 pies. Durable Functions te da el control fino donde lo necesitas. Algunos problemas se resuelven mejor con visualización. Otros se resuelven mejor con código.&lt;/p&gt;

&lt;p&gt;Y ahora tienes ambas opciones.&lt;/p&gt;

&lt;p&gt;Este es el primer artículo de una serie donde vamos a explorar Durable Functions en profundidad:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Construye tu primera AWS Lambda Durable Function&lt;/strong&gt;: Instalación, setup y tu primer workflow funcional paso a paso&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-step workflows que sobreviven fallos&lt;/strong&gt;: Cómo los checkpoints automáticos mantienen tu progreso incluso cuando algo truena&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Callbacks y aprobaciones externas&lt;/strong&gt;: Pausar workflows esperando input humano o eventos externos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waits y condiciones&lt;/strong&gt;: Suspender ejecución por horas o días sin pagar por tiempo idle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ejecución en paralelo&lt;/strong&gt;: Correr múltiples pasos al mismo tiempo y coordinar resultados&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La pregunta no es "¿cuál va a sobrevivir?" Es "¿cuál necesito para este problema específico?" Y ahora ya sabes cómo responderla.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Qué viene después?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
En el próximo artículo, vamos a construir tu primera AWS Lambda Durable Function desde cero: instalación, setup y un workflow funcional paso a paso. Código real, problemas reales, soluciones reales.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Te resultó útil este artículo?&lt;/strong&gt; Compártelo con tu equipo o déjame saber en los comentarios qué otros temas de serverless te gustaría que cubriera. Y si ya estás usando Step Functions o Durable Functions en producción, me encantaría escuchar tu experiencia.&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>stepfunctions</category>
      <category>aws</category>
      <category>español</category>
    </item>
    <item>
      <title>Amazon API Gateway: La puerta de entrada a tu backend en la nube</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Tue, 03 Mar 2026 14:57:58 +0000</pubDate>
      <link>https://dev.to/aws/amazon-api-gateway-la-puerta-de-entrada-a-tu-backend-en-la-nube-1bbi</link>
      <guid>https://dev.to/aws/amazon-api-gateway-la-puerta-de-entrada-a-tu-backend-en-la-nube-1bbi</guid>
      <description>&lt;p&gt;&lt;em&gt;Cómo API Gateway recibe requests y los conecta con tu lógica de backend.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Ya sabes &lt;a href="https://dev.to/aws/que-pasa-realmente-cuando-una-app-pide-algo-19g0"&gt;qué es una API y por qué las aplicaciones se comunican haciendo peticiones&lt;/a&gt;.&lt;br&gt;
Ya entiendes &lt;a href="https://dev.to/aws/a-donde-va-una-peticion-cuando-la-envias-y-que-pasa-en-el-camino-2bap"&gt;cómo una petición viaja desde tu app hasta el servidor&lt;/a&gt;.&lt;br&gt;
Ya viste &lt;a href="https://dev.to/aws/que-es-rest-y-como-responde-a-un-request-22ll"&gt;qué es REST y cómo el backend interpreta esa petición y decide qué responder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pero quedó una pregunta sin responder:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;¿Cómo se implementa todo esto en la nube?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Porque una cosa es entender el concepto de una API REST, y otra muy distinta es desplegarla, gestionarla, escalarla, y mantenerla funcionando en producción.&lt;/p&gt;

&lt;p&gt;Ahí es donde entra &lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;No como una tecnología complicada que tienes que dominar desde cero.   Sino como &lt;strong&gt;la puerta de entrada&lt;/strong&gt; que maneja todo lo que pasa antes de que tu lógica de backend se ejecute.&lt;/p&gt;

&lt;p&gt;Este artículo es para entender eso.&lt;/p&gt;
&lt;h2&gt;
  
  
  El problema que Amazon API Gateway resuelve
&lt;/h2&gt;

&lt;p&gt;Imagina que construiste una aplicación que devuelve información de personajes de Harry Potter. Tu aplicación funciona perfecto: recibe un ID, busca en la base de datos, devuelve el personaje.&lt;/p&gt;

&lt;p&gt;Pero ahora necesitas que tu app móvil pueda llamar a esa aplicación.&lt;/p&gt;

&lt;p&gt;¿Cómo lo haces?&lt;/p&gt;

&lt;p&gt;Podrías montar tu propio servidor. De hecho, eso es lo que los equipos hacían antes. Configuraban servidores con &lt;strong&gt;Nginx o Apache&lt;/strong&gt;, instalaban &lt;strong&gt;load balancers&lt;/strong&gt;, escribían reglas de enrutamiento, configuraban SSL manualmente, y monitoreaban logs constantemente.&lt;/p&gt;

&lt;p&gt;Todo esto funcionaba. Pero requería experiencia en DevOps, mantener servidores 24/7, pagar por ellos aunque nadie los usara, y escalar manualmente cuando cambiaba el tráfico.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt; elimina toda esa complejidad.&lt;/p&gt;

&lt;p&gt;Es un servicio administrado que actúa como la puerta de entrada a tu backend. No es tu backend, no es donde vive tu lógica, no es donde guardas tus datos. Es &lt;strong&gt;el punto de entrada&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Piensa en API Gateway como el recepcionista de un edificio: recibe a todos los visitantes, verifica que tengan permiso, los dirige al piso correcto, pero no hace el trabajo de los que están en las oficinas.&lt;/p&gt;

&lt;p&gt;No tienes que mantener servidores. No pagas cuando no hay tráfico. Escala automáticamente. Maneja HTTPS, configuración de seguridad para navegadores web, autenticación, y límites de peticiones por ti.&lt;/p&gt;

&lt;p&gt;Es como tener un equipo de DevOps administrando tu puerta de entrada, pero sin tener que contratar a nadie.&lt;/p&gt;

&lt;p&gt;Y lo más importante: &lt;strong&gt;te deja enfocarte en tu lógica de negocio&lt;/strong&gt;, no en la infraestructura.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cómo funciona el flujo básico
&lt;/h2&gt;

&lt;p&gt;Cuando tu app hace una petición a una API desplegada con API Gateway:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;La petición llega a API Gateway&lt;/strong&gt; - Tu app hace un &lt;code&gt;GET https://api.tuapp.com/personajes/8&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway valida&lt;/strong&gt; - Verifica que la petición esté bien formada y tenga permisos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Llama a tu backend&lt;/strong&gt; - En este caso, ejecuta tu función Lambda&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Devuelve la respuesta&lt;/strong&gt; - Tu app recibe el JSON con la información del personaje&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Todo ese proceso pasa en milisegundos.&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%2Fgu65g998iiipakok35dy.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%2Fgu65g998iiipakok35dy.png" alt="API Gateway Flow" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Construyamos nuestra primera API con API Gateway + Lambda
&lt;/h2&gt;

&lt;p&gt;Vamos a construir una API simple que devuelve información de un personaje de Harry Potter.&lt;/p&gt;

&lt;p&gt;Para esto usaremos dos servicios de AWS:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;&lt;/strong&gt; es un servicio que ejecuta tu código sin que tengas que administrar servidores. Tú solo subes tu código y Lambda se encarga de ejecutarlo cuando lo necesites. Aquí es donde vivirá nuestra lógica de negocio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Gateway&lt;/strong&gt; será la puerta de entrada que recibe las peticiones HTTP y las conecta con nuestra función Lambda.&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%2Fe1x1z9to3um5fa3ygg29.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%2Fe1x1z9to3um5fa3ygg29.png" alt="API Gateway Demo" width="800" height="336"&gt;&lt;/a&gt;&lt;br&gt;
No te preocupes si es tu primera vez usando AWS. Vamos paso a paso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota importante&lt;/strong&gt;: Este tutorial puede realizarse completamente dentro de la &lt;a href="https://aws.amazon.com/free/" rel="noopener noreferrer"&gt;capa gratuita de AWS&lt;/a&gt;, así que no tendrá ningún costo si tu cuenta es nueva o si no has excedido los límites gratuitos. Al final del artículo te mostraré cómo limpiar los recursos para evitar que se consuman tus créditos gratuitos (no se hará ningún cargo a tu tarjeta).&lt;/p&gt;
&lt;h3&gt;
  
  
  Paso 1: Crear la función Lambda
&lt;/h3&gt;

&lt;p&gt;Primero necesitamos crear la función que contendrá nuestra lógica.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crear la función:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ve a la consola de AWS y busca "Lambda" en el buscador superior&lt;/li&gt;
&lt;li&gt;Haz clic en "Create function" (Crear función)&lt;/li&gt;
&lt;li&gt;Selecciona "Author from scratch" (Crear desde cero)&lt;/li&gt;
&lt;li&gt;Configura tu función:

&lt;ul&gt;
&lt;li&gt;Function name: &lt;code&gt;obtenerPersonaje&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Runtime: Node.js 20.x (o la versión más reciente)&lt;/li&gt;
&lt;li&gt;Architecture: x86_64&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Deja las demás opciones por defecto y haz clic en "Create function"&lt;/li&gt;
&lt;/ol&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%2Fwww.hazelsaenz.tech%2FArticlesMedia%2FNewLambda.gif" 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%2Fwww.hazelsaenz.tech%2FArticlesMedia%2FNewLambda.gif" alt="Lambda configuration - Function name and runtime" width="755" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agregar el código:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Una vez creada, verás el editor de código. Reemplaza el código por defecto con este:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Base de datos simulada de personajes&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;personajes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Harry Potter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;casa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gryffindor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;poder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2&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;id&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="na"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hermione Granger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;casa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gryffindor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;poder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;98&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3&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;id&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="na"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ron Weasley&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;casa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gryffindor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;poder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8&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;id&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="na"&gt;nombre&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ginny Weasley&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;casa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gryffindor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;poder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;83&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// Obtener el ID del personaje desde la petición&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathParameters&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ID recibido:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Buscar el personaje&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;personaje&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;personajes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Si no existe, devolver error&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;personaje&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="na"&gt;statusCode&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="na"&gt;headers&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="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Personaje no encontrado&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="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Devolver el personaje encontrado&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;statusCode&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="na"&gt;headers&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="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;personaje&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;ol&gt;
&lt;li&gt;Haz clic en "Deploy" para guardar los cambios&lt;/li&gt;
&lt;/ol&gt;

   

&lt;p&gt;Tu función Lambda ya está lista. Ahora vamos a conectarla con API Gateway.&lt;/p&gt;
&lt;h3&gt;
  
  
  Paso 2: Crear la API en API Gateway
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ve a la consola de AWS y busca "API Gateway"&lt;/li&gt;
&lt;li&gt;Haz clic en "Create API" (Crear API)&lt;/li&gt;
&lt;li&gt;Selecciona "REST API" (no la opción Private)&lt;/li&gt;
&lt;li&gt;Haz clic en "Build" (Crear)&lt;/li&gt;
&lt;li&gt;Configura tu API:

&lt;ul&gt;
&lt;li&gt;Choose the protocol: REST&lt;/li&gt;
&lt;li&gt;Create new API: New API&lt;/li&gt;
&lt;li&gt;API name: &lt;code&gt;API-Personajes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Description: API para obtener información de personajes&lt;/li&gt;
&lt;li&gt;Endpoint Type: Regional&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Haz clic en "Create API"&lt;/li&gt;
&lt;/ol&gt;

   
&lt;h3&gt;
  
  
  Paso 3: Crear el recurso y método
&lt;/h3&gt;

&lt;p&gt;Ahora vamos a definir la estructura de nuestra API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crear el recurso principal:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;En el panel izquierdo, verás tu API. Haz clic en "Create Resource" (Crear recurso)&lt;/li&gt;
&lt;li&gt;Configura el recurso:

&lt;ul&gt;
&lt;li&gt;Resource Name: &lt;code&gt;personajes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Resource Path: &lt;code&gt;/personajes&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Marca la opción "Enable API Gateway CORS" (esto permite que tu API sea llamada desde navegadores)&lt;/li&gt;
&lt;li&gt;Haz clic en "Create Resource"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Crear el sub-recurso con parámetro:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Con el recurso &lt;code&gt;/personajes&lt;/code&gt; seleccionado, haz clic en "Create Resource" nuevamente para crear un sub-recurso&lt;/li&gt;
&lt;li&gt;Configura:

&lt;ul&gt;
&lt;li&gt;Resource Name: &lt;code&gt;{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Resource Path: &lt;code&gt;/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Marca "Enable API Gateway CORS"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Haz clic en "Create Resource"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ahora tienes la ruta &lt;code&gt;/personajes/{id}&lt;/code&gt; donde &lt;code&gt;{id}&lt;/code&gt; es un parámetro dinámico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crear el método GET:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Con el recurso &lt;code&gt;{id}&lt;/code&gt; seleccionado, haz clic en "Create Method" (Crear método)&lt;/li&gt;
&lt;li&gt;Selecciona "GET" del dropdown y haz clic en el check ✓&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Configurar la integración con Lambda:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configura la integración:

&lt;ul&gt;
&lt;li&gt;Integration type: Lambda Function&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IMPORTANTE: Marca la casilla "Use Lambda Proxy integration"&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Lambda Region: (tu región, por ejemplo us-east-1)&lt;/li&gt;
&lt;li&gt;Lambda Function: &lt;code&gt;obtenerPersonaje&lt;/code&gt; (empieza a escribir y aparecerá)&lt;/li&gt;
&lt;li&gt;Deja las demás opciones por defecto&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Haz clic en "Save"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Nota importante sobre Lambda Proxy Integration&lt;/strong&gt;: Esta opción le dice a API Gateway que pase toda la información de la petición HTTP (headers, path parameters, query strings, body) directamente a tu función Lambda en el objeto &lt;code&gt;event&lt;/code&gt;. Sin esta opción, tendrías que configurar manualmente cómo se mapean los parámetros, lo cual es más complejo y propenso a errores.&lt;/p&gt;

   

&lt;ol&gt;
&lt;li&gt;Aparecerá un mensaje pidiendo permiso para que API Gateway invoque tu Lambda. Haz clic en "OK"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este paso es importante: le estás dando permiso a API Gateway para que pueda ejecutar tu función Lambda.&lt;br&gt;&lt;br&gt;
Sin este permiso, API Gateway no podría llamar a tu función cuando llegue una petición.&lt;br&gt;&lt;br&gt;
AWS maneja esto automáticamente por ti cuando haces clic en "OK".&lt;/p&gt;
&lt;h3&gt;
  
  
  Paso 4: Desplegar la API
&lt;/h3&gt;

&lt;p&gt;Tu API está configurada, pero aún no está disponible públicamente. Necesitas desplegarla.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Haz clic en "Deploy API" en el menú superior&lt;/li&gt;
&lt;li&gt;Configura el despliegue:

&lt;ul&gt;
&lt;li&gt;Deployment stage: [New Stage]&lt;/li&gt;
&lt;li&gt;Stage name: &lt;code&gt;prod&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Stage description: Producción&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Haz clic en "Deploy"&lt;/li&gt;
&lt;/ol&gt;

   

&lt;p&gt;¡Listo! Tu API ya está en producción.&lt;/p&gt;
&lt;h3&gt;
  
  
  Paso 5: Probar tu API
&lt;/h3&gt;

&lt;p&gt;API Gateway te da una URL pública para tu API.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;En la pantalla de "Stages", verás tu stage "prod"&lt;/li&gt;
&lt;li&gt;Expande el árbol: prod → /personajes → /{id} → GET&lt;/li&gt;
&lt;li&gt;En la parte superior verás la "Invoke URL"
La URL se verá algo así:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://abc123xyz.execute-api.us-east-1.amazonaws.com/prod/personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Copia esa URL y ábrela en tu navegador (cambia el &lt;code&gt;8&lt;/code&gt; por &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, u &lt;code&gt;8&lt;/code&gt; para ver diferentes personajes)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;También puedes probarla desde la terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://tu-url-aqui.execute-api.us-east-1.amazonaws.com/prod/personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deberías ver una respuesta como esta:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nombre"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ginny Weasley"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"casa"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gryffindor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"poder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;83&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;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%2F0i26umk6ckgp3iwy2g97.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%2F0i26umk6ckgp3iwy2g97.png" alt="curl JSON response" width="800" height="97"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué acabas de hacer?
&lt;/h3&gt;

&lt;p&gt;Acabas de construir una API REST completa en la nube:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creaste una función Lambda con tu lógica de negocio&lt;/li&gt;
&lt;li&gt;Configuraste API Gateway como punto de entrada&lt;/li&gt;
&lt;li&gt;Definiste una ruta con parámetros dinámicos (&lt;code&gt;/personajes/{id}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Desplegaste tu API en producción&lt;/li&gt;
&lt;li&gt;Obtuviste una URL pública que cualquiera puede llamar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todo sin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Montar servidores&lt;/li&gt;
&lt;li&gt;Configurar balanceadores de carga&lt;/li&gt;
&lt;li&gt;Manejar certificados SSL&lt;/li&gt;
&lt;li&gt;Escribir código de infraestructura&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eso es el poder de serverless + API Gateway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limpieza: Eliminar los recursos
&lt;/h3&gt;

&lt;p&gt;Si solo estás probando y no quieres que estos recursos sigan activos en tu cuenta de AWS, es importante eliminarlos para evitar que se consuman tus créditos gratuitos (si estás en la capa gratuita) o para evitar cargos innecesarios.&lt;/p&gt;

&lt;h4&gt;
  
  
  Eliminar la API en API Gateway
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Ve a la consola de API Gateway&lt;/li&gt;
&lt;li&gt;Selecciona tu API &lt;code&gt;API-Personajes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Haz clic en "Actions" → "Delete API"&lt;/li&gt;
&lt;li&gt;Confirma escribiendo el nombre de la API y haz clic en "Delete API"&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Eliminar la función Lambda
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Ve a la consola de Lambda&lt;/li&gt;
&lt;li&gt;Selecciona tu función &lt;code&gt;obtenerPersonaje&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Haz clic en "Actions" → "Delete"&lt;/li&gt;
&lt;li&gt;Confirma la eliminación&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Con esto, todos los recursos del tutorial están eliminados y no generarán cargos en tu cuenta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué esto importa para arquitecturas serverless
&lt;/h2&gt;

&lt;p&gt;Porque en serverless, tus funciones no están "corriendo" todo el tiempo. Se ejecutan cuando las llamas. Y se apagan cuando terminan. Pero tu app necesita una URL estable. Un punto de entrada que siempre esté disponible. API Gateway es ese punto de entrada.&lt;/p&gt;

&lt;p&gt;Tu app siempre llama a la misma URL. API Gateway siempre está ahí. Y cuando llega una petición, despierta tu Lambda, la ejecuta, y devuelve la respuesta.&lt;/p&gt;

&lt;p&gt;Sin API Gateway, serverless no funcionaría para APIs públicas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que aprendiste
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway es la puerta de entrada, no el backend.
&lt;/li&gt;
&lt;li&gt;Recibe peticiones HTTP y las conecta con tu lógica real.
&lt;/li&gt;
&lt;li&gt;Maneja validación, transformación, seguridad, y throttling.
&lt;/li&gt;
&lt;li&gt;Puede integrarse con Lambda, HTTP endpoints, o servicios de AWS.
&lt;/li&gt;
&lt;li&gt;Incluye características de gestión de APIs sin código adicional.
&lt;/li&gt;
&lt;li&gt;Es esencial para arquitecturas serverless.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No es magia. Es infraestructura que alguien más mantiene por ti.&lt;/p&gt;

&lt;p&gt;Y esa diferencia es lo que te permite construir APIs en producción sin tener que ser experto en DevOps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué sigue
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway es la puerta de entrada, no el backend.
&lt;/li&gt;
&lt;li&gt;Recibe peticiones HTTP y las conecta con tu lógica real.
&lt;/li&gt;
&lt;li&gt;Maneja validación, transformación, seguridad, y límites de peticiones.
&lt;/li&gt;
&lt;li&gt;Puede integrarse con Lambda, HTTP endpoints, o servicios de AWS.
&lt;/li&gt;
&lt;li&gt;Incluye características de gestión de APIs sin código adicional.
&lt;/li&gt;
&lt;li&gt;Es esencial para arquitecturas serverless.
Ahora tienes las bases para construir tus propias APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No porque hayas memorizado sintaxis o comandos.&lt;br&gt;&lt;br&gt;
Sino porque entiendes &lt;strong&gt;cómo funciona la conversación&lt;/strong&gt; de principio a fin.&lt;/p&gt;

&lt;p&gt;Y esa claridad es lo que te permite construir mejor, debuggear más rápido, y diseñar con más confianza.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>api</category>
      <category>apigateway</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Qué es REST y cómo responde a un request</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Tue, 24 Feb 2026 20:52:08 +0000</pubDate>
      <link>https://dev.to/aws/que-es-rest-y-como-responde-a-un-request-22ll</link>
      <guid>https://dev.to/aws/que-es-rest-y-como-responde-a-un-request-22ll</guid>
      <description>&lt;p&gt;Una explicación simple para entender cómo el backend interpreta lo que pides y decide qué responderte.&lt;/p&gt;




&lt;p&gt;Ya sabes que las aplicaciones hacen peticiones, ya sabes que esas peticiones viajan por la red hasta llegar a un servidor, pero quedó una pregunta sin responder:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;¿Qué pasa cuando la petición llega? ¿Cómo sabe el servidor qué hacer con ella?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esa es la parte que casi nunca se explica bien. Y es justo ahí donde entra REST.&lt;/p&gt;

&lt;p&gt;No como una tecnología mágica, no como un framework que instalas. Sino como &lt;strong&gt;una forma de organizar la conversación&lt;/strong&gt; entre quien pide y quien responde.&lt;/p&gt;

&lt;p&gt;Este artículo es para entender eso.&lt;/p&gt;

&lt;h2&gt;
  
  
  La petición llegó. ¿Y ahora qué?
&lt;/h2&gt;

&lt;p&gt;En el &lt;a href="https://dev.to/aws/a-donde-va-una-peticion-cuando-la-envias-y-que-pasa-en-el-camino-2bap"&gt;artículo anterior&lt;/a&gt; vimos el viaje completo de una petición: desde que sale de tu app, viaja por la red, llega al servidor, y regresa con una respuesta.&lt;/p&gt;

&lt;p&gt;Pero quedó pendiente entender qué pasa exactamente cuando esa petición llega al servidor.&lt;/p&gt;

&lt;p&gt;Imagina que tu app envía esta petición:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El servidor la recibe. La lee. Y tiene que decidir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;¿Qué está pidiendo?
&lt;/li&gt;
&lt;li&gt;¿Qué debería responder?
&lt;/li&gt;
&lt;li&gt;¿Cómo debería estructurar esa respuesta?
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si no hay reglas claras, cada servidor podría interpretar eso de forma diferente.&lt;/p&gt;

&lt;p&gt;Uno podría pensar que &lt;code&gt;/personajes/8&lt;/code&gt; significa "dame el personaje con ID 8". &lt;br&gt;
Otro podría pensar que significa "borra el personaje 8".&lt;br&gt;
Otro podría no entender nada.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REST existe para evitar ese caos.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Define un conjunto de reglas que hacen que la conversación sea predecible.&lt;/p&gt;
&lt;h2&gt;
  
  
  REST no es una tecnología
&lt;/h2&gt;

&lt;p&gt;Aquí es donde empieza la confusión.&lt;/p&gt;

&lt;p&gt;REST no es:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un lenguaje de programación
&lt;/li&gt;
&lt;li&gt;Un framework que instalas
&lt;/li&gt;
&lt;li&gt;Una librería que importas
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;REST es &lt;strong&gt;un estilo de comunicación&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Un acuerdo sobre cómo estructurar las peticiones y las respuestas para que ambas partes se entiendan sin necesidad de conocerse por dentro.&lt;/p&gt;

&lt;p&gt;Piensa en REST como las reglas de una conversación educada:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cuando preguntas algo, lo haces de forma clara
&lt;/li&gt;
&lt;li&gt;Cuando respondes, das información útil
&lt;/li&gt;
&lt;li&gt;Ambas partes saben qué esperar del otro
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eso es REST. Nada más. Nada menos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Las peticiones expresan intención
&lt;/h2&gt;

&lt;p&gt;En REST, cada petición tiene dos partes clave:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;El recurso&lt;/strong&gt; (qué estás pidiendo)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El verbo HTTP&lt;/strong&gt; (qué quieres hacer con ese recurso)
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Volviendo al ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recurso&lt;/strong&gt;: &lt;code&gt;/personajes/8&lt;/code&gt; (el personaje con ID 8)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verbo&lt;/strong&gt;: &lt;code&gt;GET&lt;/code&gt; (quiero obtener información)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El verbo no es un comando. Es una &lt;strong&gt;intención&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No le estás diciendo al servidor "ejecuta esta función". Le estás diciendo "esto es lo que quiero hacer". Y el servidor decide cómo hacerlo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Los verbos HTTP como lenguaje
&lt;/h2&gt;

&lt;p&gt;REST usa los verbos HTTP para expresar intenciones comunes:&lt;/p&gt;

&lt;h3&gt;
  
  
  GET: "Quiero ver algo"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Dame información del personaje 8"&lt;/p&gt;

&lt;p&gt;No modifica nada. Solo pide información.&lt;/p&gt;

&lt;h3&gt;
  
  
  POST: "Quiero crear algo nuevo"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /personajes
{
  "nombre": "Luna Lovegood",
  "casa": "Ravenclaw"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Crea un nuevo personaje con esta información"&lt;/p&gt;

&lt;h3&gt;
  
  
  PUT/PATCH: "Quiero actualizar algo"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PATCH /personajes/8
{
  "poder": 90
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Actualiza el poder del personaje 8"&lt;/p&gt;

&lt;h3&gt;
  
  
  DELETE: "Quiero eliminar algo"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DELETE /personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Elimina el personaje 8"&lt;/p&gt;

&lt;p&gt;No tienes que memorizar esto. Solo tienes que entender que &lt;strong&gt;cada verbo expresa una intención diferente&lt;/strong&gt;. Y REST usa esas intenciones para organizar la conversación.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos, no acciones
&lt;/h2&gt;

&lt;p&gt;Aquí hay algo importante que muchas veces se pasa por alto: En REST, las URLs representan &lt;strong&gt;recursos&lt;/strong&gt;, no acciones.&lt;/p&gt;

&lt;p&gt;Por ejemplo:&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Mal diseño&lt;/strong&gt; (acciones en la URL):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /crearPersonaje
POST /eliminarPersonaje
POST /actualizarPersonaje
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Buen diseño&lt;/strong&gt; (recursos + verbos):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /personajes
DELETE /personajes/8
PATCH /personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Ves la diferencia?&lt;/p&gt;

&lt;p&gt;En el primer caso, la URL dice &lt;strong&gt;qué hacer&lt;/strong&gt;. En el segundo caso, la URL dice &lt;strong&gt;sobre qué&lt;/strong&gt; y el verbo dice &lt;strong&gt;qué hacer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Esa separación hace que las APIs sean más claras y predecibles.&lt;/p&gt;

&lt;h2&gt;
  
  
  El servidor interpreta y decide
&lt;/h2&gt;

&lt;p&gt;Cuando el servidor recibe una petición REST, sigue un proceso:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lee el verbo&lt;/strong&gt;: ¿Qué quiere hacer?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lee el recurso&lt;/strong&gt;: ¿Sobre qué?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evalúa&lt;/strong&gt;: ¿Tiene permiso? ¿Existe ese recurso?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ejecuta la lógica&lt;/strong&gt;: Busca en la base de datos, procesa, valida
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Construye la respuesta&lt;/strong&gt;: Decide qué devolver&lt;/li&gt;
&lt;/ol&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%2F7dw55lqh7044xe8zztrh.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%2F7dw55lqh7044xe8zztrh.png" alt="RESTFlow" width="800" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por ejemplo, si recibe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /personajes/8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El servidor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identifica que es una petición GET (quiere información)
&lt;/li&gt;
&lt;li&gt;Identifica que el recurso es &lt;code&gt;/personajes/8&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Busca en la base de datos el personaje con ID 8
&lt;/li&gt;
&lt;li&gt;Si lo encuentra, lo devuelve
&lt;/li&gt;
&lt;li&gt;Si no lo encuentra, responde con un error
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todo eso pasa en el backend.&lt;/p&gt;

&lt;p&gt;La app que hizo la petición &lt;strong&gt;no sabe cómo&lt;/strong&gt; se hizo.&lt;br&gt;&lt;br&gt;
Solo sabe que si pide de esa forma, va a recibir lo que necesita.&lt;/p&gt;
&lt;h2&gt;
  
  
  Las respuestas tienen significado
&lt;/h2&gt;

&lt;p&gt;En REST, las respuestas no son solo datos. Son &lt;strong&gt;decisiones estructuradas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Cada respuesta incluye:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Un código de estado
&lt;/h3&gt;

&lt;p&gt;Que dice &lt;strong&gt;qué pasó&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;200 OK&lt;/code&gt;: Todo bien, aquí está lo que pediste
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;201 Created&lt;/code&gt;: Se creó algo nuevo
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;404 Not Found&lt;/code&gt;: No encontré lo que pediste
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;400 Bad Request&lt;/code&gt;: Tu petición está mal formada
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;500 Internal Server Error&lt;/code&gt;: Algo falló de mi lado
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos son solo algunos de los códigos más comunes. Los códigos de estado HTTP son estándar, pero cada tipo de servidor puede manejar y devolver errores de forma ligeramente diferente. Puedes ver la &lt;a href="https://developer.mozilla.org/es/docs/Web/HTTP/Status" rel="noopener noreferrer"&gt;lista completa de códigos de estado HTTP&lt;/a&gt; en la documentación de MDN.  &lt;/p&gt;
&lt;h3&gt;
  
  
  2. Un cuerpo de respuesta
&lt;/h3&gt;

&lt;p&gt;Que contiene &lt;strong&gt;la información&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nombre"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ginny Weasley"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"casa"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gryffindor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"poder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;83&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;
  
  
  3. Headers (opcional)
&lt;/h3&gt;

&lt;p&gt;Que dan &lt;strong&gt;contexto adicional&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;Content-Type: application/json
Cache-Control: max-age=3600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por ejemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Content-Type: application/json&lt;/code&gt; indica que la respuesta está en formato JSON&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Cache-Control: max-age=3600&lt;/code&gt; indica que la respuesta puede guardarse en caché por 1 hora&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todo eso junto forma una respuesta completa. No es solo "aquí están los datos". Es "esto es lo que pasó, esto es lo que encontré, y así deberías interpretarlo".&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué REST reduce la confusión
&lt;/h2&gt;

&lt;p&gt;Porque cuando todos siguen las mismas reglas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Las peticiones son predecibles
&lt;/li&gt;
&lt;li&gt;Las respuestas tienen estructura
&lt;/li&gt;
&lt;li&gt;Los errores tienen significado
&lt;/li&gt;
&lt;li&gt;No tienes que adivinar cómo funciona cada API
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sin REST (o sin algún estilo similar), cada API sería diferente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unos usarían POST para todo
&lt;/li&gt;
&lt;li&gt;Otros inventarían sus propios códigos de error
&lt;/li&gt;
&lt;li&gt;Otros mezclarían acciones y recursos sin criterio
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;REST no es perfecto. Pero es un acuerdo que funciona.&lt;/p&gt;

&lt;p&gt;Y cuando lo entiendes, dejas de ver las APIs como algo mágico y empiezas a verlas como lo que son: &lt;strong&gt;conversaciones con reglas claras&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que aprendiste
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;REST es un estilo de comunicación, no una tecnología.&lt;/li&gt;
&lt;li&gt;Las peticiones expresan &lt;strong&gt;intención&lt;/strong&gt; a través de verbos HTTP.&lt;/li&gt;
&lt;li&gt;Los recursos representan &lt;strong&gt;qué&lt;/strong&gt;, no &lt;strong&gt;cómo&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;El servidor &lt;strong&gt;interpreta&lt;/strong&gt; la petición y &lt;strong&gt;decide&lt;/strong&gt; qué responder.&lt;/li&gt;
&lt;li&gt;Las respuestas tienen &lt;strong&gt;significado&lt;/strong&gt;, no solo datos.&lt;/li&gt;
&lt;li&gt;REST reduce el caos al establecer reglas claras para la conversación.&lt;/li&gt;
&lt;li&gt;Entender REST no es memorizar verbos. Es entender &lt;strong&gt;por qué&lt;/strong&gt; las APIs se diseñan de cierta forma. Y esa claridad es lo que te permite construir mejor, debuggear más rápido, y diseñar con más confianza.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Qué sigue
&lt;/h2&gt;

&lt;p&gt;Ya entiendes qué es REST y cómo organiza la conversación entre quien pide y quien responde.&lt;/p&gt;

&lt;p&gt;En el siguiente artículo vamos a ver &lt;strong&gt;cómo se implementa esto en la nube&lt;/strong&gt; usando &lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Vas a entender cómo API Gateway actúa como la puerta de entrada a tu backend, cómo recibe peticiones REST, y cómo las conecta con tu lógica (ya sea en Lambda, en un servidor HTTP, o en otros servicios de AWS).&lt;/p&gt;

&lt;p&gt;Ya sabes cómo funciona la conversación. Ahora es momento de ver cómo se despliega en producción.&lt;/p&gt;

</description>
      <category>api</category>
      <category>programming</category>
      <category>espanol</category>
      <category>development</category>
    </item>
    <item>
      <title>A dónde va una petición cuando la envías (y qué pasa en el camino)</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Tue, 17 Feb 2026 14:35:30 +0000</pubDate>
      <link>https://dev.to/aws/a-donde-va-una-peticion-cuando-la-envias-y-que-pasa-en-el-camino-2bap</link>
      <guid>https://dev.to/aws/a-donde-va-una-peticion-cuando-la-envias-y-que-pasa-en-el-camino-2bap</guid>
      <description>&lt;p&gt;&lt;em&gt;Una explicación simple del viaje completo: desde que tu app pide algo hasta que recibe respuesta.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Ya sabes que las aplicaciones se comunican haciendo peticiones.&lt;/p&gt;

&lt;p&gt;Tocas un botón. ➡️ La app pide algo. ➡️ Algo responde.&lt;/p&gt;

&lt;p&gt;Pero entre ese "pedir" y ese "responder" hay un viaje completo. Y casi nunca se explica.&lt;/p&gt;

&lt;p&gt;La mayoría de las veces, cuando aprendes sobre APIs, te dicen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"La app hace una petición"
&lt;/li&gt;
&lt;li&gt;"El servidor responde"
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y listo.&lt;/p&gt;

&lt;p&gt;Como si todo pasara instantáneamente. Como si no hubiera nada en el medio. Pero sí lo hay.&lt;/p&gt;

&lt;p&gt;Y entender ese recorrido es lo que te ayuda a dejar de ver las APIs como algo abstracto y empezar a verlas como lo que son: &lt;strong&gt;conversaciones con pasos claros&lt;/strong&gt;. Este artículo es ese mapa.&lt;/p&gt;

&lt;p&gt;En el &lt;a href="https://dev.to/aws/que-pasa-realmente-cuando-una-app-pide-algo-19g0"&gt;artículo anterior&lt;/a&gt; vimos que las aplicaciones no guardan todo localmente.&lt;/p&gt;

&lt;p&gt;Cuando necesitan algo, &lt;strong&gt;preguntan&lt;/strong&gt;, hacen una petición y esperan una respuesta.&lt;/p&gt;

&lt;p&gt;Eso es una API: el acuerdo que define cómo se hace esa conversación. Pero quedó una pregunta sin responder:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;¿Qué pasa entre el momento en que la app envía la petición y el momento en que recibe la respuesta?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Eso es lo que vamos a ver ahora.&lt;/p&gt;

&lt;h2&gt;
  
  
  Una petición sale de la app
&lt;/h2&gt;

&lt;p&gt;Imagina que abres una app de Harry Potter y buscas información sobre "Ginny Weasley". (Y sí, si me conoces sabes que soy fan de Harry Potter, así que  este ejemplo me hace especialmente feliz 😊)&lt;/p&gt;

&lt;p&gt;La app no tiene todos los datos de los personajes guardados en tu teléfono. Así que hace una petición:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /personajes?nombre=Ginny+Weasley
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esa petición es un &lt;strong&gt;mensaje&lt;/strong&gt;, no es código que se ejecuta en otro lugar, no es un archivo que se envía, es simplemente información estructurada que dice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Qué quiero&lt;/strong&gt;: información de personajes
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sobre quién&lt;/strong&gt;: Ginny Weasley
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cómo lo pido&lt;/strong&gt;: usando el método GET
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ese mensaje sale de tu app. Y empieza su viaje.➡️ ✉️ &lt;/p&gt;

&lt;h2&gt;
  
  
  El viaje a través de la red
&lt;/h2&gt;

&lt;p&gt;Tu petición no llega directamente al servidor, pasa por varios puntos en el camino:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sale de tu dispositivo&lt;/strong&gt; (tu teléfono, tu computadora)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pasa por tu red local&lt;/strong&gt; (tu WiFi o datos móviles)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viaja por internet&lt;/strong&gt; (a través de routers, cables, infraestructura)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Llega al servidor&lt;/strong&gt; que tiene la información
&lt;/li&gt;
&lt;/ol&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%2F5mzin8goyly1hb31igfe.gif" 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%2F5mzin8goyly1hb31igfe.gif" alt="Request" width="720" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cada uno de esos pasos toma tiempo, a veces milisegundos y a veces segundos; por eso a veces una app carga rápido y otras veces tarda, no siempre es culpa de la app. A veces es el camino.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://hsaenzg.github.io/api_call/" rel="noopener noreferrer"&gt;Prueba este ejemplo interactivo&lt;/a&gt;&lt;/strong&gt; para ver en acción cómo funciona una petición a una API de Harry Potter. Puedes ver el &lt;a href="https://github.com/hsaenzG/api_call.git" rel="noopener noreferrer"&gt;código de la demo en GitHub&lt;/a&gt; para entender cómo está construida.&lt;/p&gt;

&lt;h2&gt;
  
  
  El servidor recibe la petición
&lt;/h2&gt;

&lt;p&gt;Cuando la petición llega al servidor, no se ejecuta automáticamente.&lt;/p&gt;

&lt;p&gt;El servidor la &lt;strong&gt;recibe&lt;/strong&gt; y la &lt;strong&gt;evalúa&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Piensa en el servidor como un portero que revisa cada mensaje que llega:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;¿Esta petición está bien formada?
&lt;/li&gt;
&lt;li&gt;¿Tiene permiso para pedir esto?
&lt;/li&gt;
&lt;li&gt;¿Entiendo lo que está pidiendo?
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si algo falla en esta etapa, el servidor responde con un error.&lt;/p&gt;

&lt;p&gt;Por ejemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si pediste algo que no existe: &lt;code&gt;404 Not Found&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Si no tienes permiso: &lt;code&gt;403 Forbidden&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Si la petición está mal hecha: &lt;code&gt;400 Bad Request&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pero si todo está bien, el servidor pasa a la siguiente etapa.&lt;/p&gt;

&lt;h2&gt;
  
  
  El proceso de decisión
&lt;/h2&gt;

&lt;p&gt;Aquí es donde pasa la magia. El servidor no solo devuelve información, &lt;strong&gt;decide&lt;/strong&gt; qué devolver.&lt;/p&gt;

&lt;p&gt;Siguiendo el ejemplo de la app de Harry Potter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;El servidor recibe: &lt;code&gt;GET /personajes?nombre=Ginny+Weasley&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Busca en su base de datos información sobre "Ginny Weasley"
&lt;/li&gt;
&lt;li&gt;Recopila todos los datos del personaje (casa, varita, patronus, etc.)
&lt;/li&gt;
&lt;li&gt;Puede que incluya información relacionada (amigos, hechizos favoritos)
&lt;/li&gt;
&lt;li&gt;Procesa esa información
&lt;/li&gt;
&lt;li&gt;La estructura en el formato acordado (generalmente JSON)
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Todo eso pasa en el backend.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La app que hizo la petición &lt;strong&gt;no sabe&lt;/strong&gt; cómo funciona ese proceso.
&lt;/li&gt;
&lt;li&gt;No sabe si el servidor usa una base de datos SQL o NoSQL.
&lt;/li&gt;
&lt;li&gt;No sabe cómo funciona el algoritmo de recomendación.
&lt;/li&gt;
&lt;li&gt;No sabe si está en un servidor en California o en Singapur.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solo sabe que si pide de cierta forma, va a recibir lo que necesita.&lt;/p&gt;

&lt;p&gt;Esa es la belleza de las APIs: &lt;strong&gt;separan el "qué" del "cómo"&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  La respuesta regresa
&lt;/h2&gt;

&lt;p&gt;Una vez que el servidor termina de procesar, construye una respuesta:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nombre"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ginny Weasley"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"casa"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gryffindor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"poder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hechizo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Reducto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"defensa"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;77&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"imagen"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esa respuesta hace el viaje de regreso:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sale del servidor
&lt;/li&gt;
&lt;li&gt;Viaja por internet
&lt;/li&gt;
&lt;li&gt;Pasa por tu red local
&lt;/li&gt;
&lt;li&gt;Llega a tu dispositivo
&lt;/li&gt;
&lt;li&gt;Tu app la recibe
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;El mismo camino, pero en reversa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cómo reacciona la app
&lt;/h2&gt;

&lt;p&gt;Cuando la app recibe la respuesta, &lt;strong&gt;reacciona&lt;/strong&gt;, no decide, no procesa lógica compleja, solo toma lo que recibió y lo muestra.&lt;/p&gt;

&lt;p&gt;En este caso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Muestra la foto del personaje
&lt;/li&gt;
&lt;li&gt;Muestra su casa y escudo de Gryffindor
&lt;/li&gt;
&lt;li&gt;Muestra información sobre su hechizo
&lt;/li&gt;
&lt;li&gt;Muestra información de defensa
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si la respuesta hubiera sido un error, la app mostraría un mensaje de error.&lt;/p&gt;

&lt;p&gt;La app &lt;strong&gt;depende completamente&lt;/strong&gt; de lo que el servidor responda.&lt;/p&gt;

&lt;p&gt;Por eso cuando una API falla, la app no puede hacer nada, no puede inventar personajes, no puede adivinar información, solo puede mostrar que algo salió mal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué importa entender este flujo
&lt;/h2&gt;

&lt;p&gt;Porque cuando entiendes que una petición es un &lt;strong&gt;viaje&lt;/strong&gt;, no un evento instantáneo, empiezas a ver por qué:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Las apps a veces tardan en cargar (el viaje puede ser largo)
&lt;/li&gt;
&lt;li&gt;Los errores no siempre son culpa de la app (pueden pasar en cualquier punto del camino)
&lt;/li&gt;
&lt;li&gt;El backend tiene que ser confiable (es el que decide qué responder)
&lt;/li&gt;
&lt;li&gt;Las APIs bien diseñadas importan (hacen que todo este proceso sea predecible)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No es magia.n Es un proceso con pasos claros.&lt;/p&gt;

&lt;p&gt;Y cuando algo falla, saber dónde buscar hace toda la diferencia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que aprendiste
&lt;/h2&gt;

&lt;p&gt;Una petición no es un solo paso, es un viaje completo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;La app envía un mensaje
&lt;/li&gt;
&lt;li&gt;Ese mensaje viaja por la red
&lt;/li&gt;
&lt;li&gt;El servidor lo recibe y evalúa
&lt;/li&gt;
&lt;li&gt;El servidor decide qué responder
&lt;/li&gt;
&lt;li&gt;La respuesta regresa por el mismo camino
&lt;/li&gt;
&lt;li&gt;La app reacciona a lo que recibió
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Las aplicaciones &lt;strong&gt;dependen&lt;/strong&gt; de las respuestas.&lt;br&gt;&lt;br&gt;
Los servidores &lt;strong&gt;deciden&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Las APIs &lt;strong&gt;definen las reglas&lt;/strong&gt; de esa conversación.&lt;/p&gt;

&lt;p&gt;Entender este flujo te da claridad, y esa claridad es lo que te permite construir mejor, debuggear más rápido, y diseñar con más confianza.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué sigue
&lt;/h2&gt;

&lt;p&gt;En el siguiente artículo vamos a dar el siguiente paso: &lt;strong&gt;construiremos nuestra primera API REST&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Vas a ver cómo crear un servidor que reciba peticiones, procese información y devuelva respuestas.&lt;/p&gt;

&lt;p&gt;Ya entiendes el viaje completo de una petición.&lt;br&gt;&lt;br&gt;
Ahora es momento de construir el destino.&lt;/p&gt;

</description>
      <category>api</category>
      <category>español</category>
      <category>programming</category>
      <category>development</category>
    </item>
    <item>
      <title>AWS Valentine’s LATAM: cuando el amor también se despliega en la nube</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Thu, 12 Feb 2026 01:22:37 +0000</pubDate>
      <link>https://dev.to/aws/aws-valentines-latam-cuando-el-amor-tambien-se-despliega-en-la-nube-28i9</link>
      <guid>https://dev.to/aws/aws-valentines-latam-cuando-el-amor-tambien-se-despliega-en-la-nube-28i9</guid>
      <description>&lt;p&gt;Una colección de frases dev-amor inspiradas en AWS, creadas desde LATAM para celebrar San Valentín con humor, ternura y comunidad.&lt;/p&gt;

&lt;p&gt;San Valentín no siempre se trata de flores o chocolates. A veces se trata de &lt;strong&gt;cómo explicamos lo que sentimos&lt;/strong&gt;, usando el lenguaje que mejor conocemos.&lt;/p&gt;

&lt;p&gt;En nuestro caso: &lt;strong&gt;el lenguaje de los devs&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  El origen de esta idea
&lt;/h2&gt;

&lt;p&gt;Hace unos días vi una serie de tarjetas de San Valentín creadas por &lt;strong&gt;&lt;a href="https://dev.to/aws/brookes-aws-valentines-day-cards-2026-5hhj"&gt;Brooke Jamieson&lt;/a&gt;&lt;/strong&gt; para la comunidad de AWS.  &lt;br&gt;
Eran divertidas, simples y muy nerd… y me hicieron sonreír.&lt;/p&gt;

&lt;p&gt;Pero sobre todo, me hicieron pensar:&lt;/p&gt;

&lt;p&gt;¿Cómo se vería esto si lo contáramos &lt;strong&gt;desde LATAM&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Con nuestro humor. Nuestra cercanía. Nuestra forma intensa, caótica y honesta de vivir tanto el código como las relaciones.&lt;/p&gt;

&lt;p&gt;Así nació &lt;strong&gt;AWS Valentine’s LATAM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No como una traducción. Sino como una reinterpretación con identidad propia.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dev-amor, pero con acento latino
&lt;/h2&gt;

&lt;p&gt;Estas frases no están pensadas solo para ingenieras o ingenieros.  &lt;br&gt;
Están pensadas para cualquiera que haya:&lt;/p&gt;

&lt;p&gt;deployado con miedo, celebrado que &lt;em&gt;“ya funciona”&lt;/em&gt;, sufrido un outage o encontrado refugio en alguien que se queda cuando todo falla.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eres mi región primaria 
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(Amazon Route 53 / Multi-Region)&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Porque mi tráfico siempre apunta a ti.&lt;/em&gt;  &lt;strong&gt;Eres mi región primaria (y no hago failover).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyaoddifhc0mghuppzj42.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%2Fyaoddifhc0mghuppzj42.png" alt="route53" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Eres la respuesta correcta 
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(Amazon API Gateway)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eres la respuesta correcta,  a todas mis peticiones.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0n10a0ofami455u4wc9.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%2Fm0n10a0ofami455u4wc9.png" alt="ApiGateway" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  No importa la distancia 
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(Amazon CloudFront)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No importa la distancia,&lt;/em&gt;  &lt;strong&gt;igual llegas a mi edge.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzaq7n4yqfov38ahg2vds.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%2Fzaq7n4yqfov38ahg2vds.png" alt="CloudFront" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Funciona por fe 
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(AWS Lambda)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Funciona por fe,&lt;/em&gt;  &lt;strong&gt;y porque tú estás ahí.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7u3bu6swrvgz4bgtsjf2.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%2F7u3bu6swrvgz4bgtsjf2.png" alt="lambda" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Nuestro amor sobrevivió 
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(Amazon CloudWatch / Outage vibes)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Se cayó todo…&lt;/em&gt;  &lt;strong&gt;menos nosotros.&lt;/strong&gt;  Nuestro amor sobrevivió al outage.&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%2Fkwpkcseioe1uc3vh5chd.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%2Fkwpkcseioe1uc3vh5chd.png" alt="Cloudwatch" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  No me asustas, me acompañas 
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(Kiro – agentic AI, spec-driven dev)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No me asustas, me acompañas.&lt;/em&gt;  Contigo todo empieza como idea  &lt;strong&gt;y termina en algo real.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvenbvjr79utjlcqu3idu.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%2Fvenbvjr79utjlcqu3idu.png" alt="Kiro" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Guardado para siempre 
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(Amazon S3)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Aunque el mundo se mueva,&lt;/em&gt;  &lt;strong&gt;lo nuestro no se pierde.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7kxidru51qjqac7lakbt.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%2F7kxidru51qjqac7lakbt.png" alt="S3" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ¿Por qué compartir esto?
&lt;/h2&gt;

&lt;p&gt;Porque la tecnología también puede ser &lt;strong&gt;suave&lt;/strong&gt;.  &lt;br&gt;
Porque no todo contenido técnico tiene que ser rígido.  &lt;br&gt;
Porque las comunidades se construyen con conocimiento, sí…  &lt;br&gt;
pero también con &lt;strong&gt;emoción, cercanía y humanidad&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Y porque en LATAM: &lt;strong&gt;amamos intenso, incluso cuando hablamos de la nube.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Para la comunidad
&lt;/h2&gt;

&lt;p&gt;Si alguna de estas frases te hizo sonreír, si te recordó a alguien, o si te dan ganas de compartirla en tu equipo, comunidad o meetup: misión cumplida.&lt;/p&gt;

&lt;p&gt;Gracias a la comunidad de AWS por inspirar, y a personas como &lt;strong&gt;Brooke&lt;/strong&gt; por recordarnos que el tech también puede ser divertido.&lt;/p&gt;

&lt;p&gt;Feliz San Valentín, desde LATAM, con amor y con cloud.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>watercooler</category>
      <category>español</category>
      <category>latam</category>
    </item>
    <item>
      <title>Qué pasa realmente cuando una app pide algo</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Fri, 06 Feb 2026 01:40:19 +0000</pubDate>
      <link>https://dev.to/aws/que-pasa-realmente-cuando-una-app-pide-algo-19g0</link>
      <guid>https://dev.to/aws/que-pasa-realmente-cuando-una-app-pide-algo-19g0</guid>
      <description>&lt;h2&gt;
  
  
  &lt;em&gt;Una explicación simple para entender cómo se comunican las aplicaciones (y por qué a eso le llamamos API).&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Abres una app. ➡️ Tocas un botón. ➡️ Algo carga.&lt;br&gt;
No piensas mucho en eso. Solo esperas que funcione.&lt;br&gt;
Pero detrás de ese gesto tan simple, hay una conversación ocurriendo.&lt;/p&gt;

&lt;p&gt;Tu app de música no guarda millones de canciones en tu teléfono.&lt;br&gt;
Tu app del clima no tiene sensores en cada ciudad.&lt;br&gt;
Tu app de delivery no cocina la comida.&lt;/p&gt;

&lt;p&gt;Lo que hacen es pedirle esa información a otros sistemas.&lt;/p&gt;

&lt;p&gt;Esa conversación casi nunca se explica.&lt;/p&gt;

&lt;p&gt;Si alguna vez viste que una app “pide algo” y otra le responde, y sentiste que entendías lo suficiente para seguir, pero no tanto como para explicarlo… este artículo es para ti.&lt;/p&gt;
&lt;h2&gt;
  
  
  No es magia. Es una conversación.
&lt;/h2&gt;

&lt;p&gt;Cuando una aplicación necesita algo que no tiene —datos, resultados, información— no entra al sistema del otro lado como si fuera su casa.&lt;/p&gt;

&lt;p&gt;No toca lo que no le corresponde.&lt;br&gt;
No improvisa.&lt;br&gt;
No adivina.&lt;/p&gt;

&lt;p&gt;Hace algo más simple:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;pregunta&lt;/strong&gt;. Y espera una &lt;strong&gt;respuesta&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagina que abres Spotify y buscas "Bad Bunny".&lt;br&gt;
La app no tiene todas las canciones guardadas en tu teléfono.&lt;br&gt;
Hace una petición: "Dame las canciones de Bad Bunny".&lt;br&gt;
El servidor responde con la lista.&lt;/p&gt;

&lt;p&gt;La app hace una petición clara.&lt;br&gt;
El sistema del otro lado responde solo lo que prometió responder.&lt;/p&gt;

&lt;p&gt;Ni más. Ni menos. No hay magia. Hay reglas.&lt;/p&gt;
&lt;h2&gt;
  
  
  Antes de ponerle nombre, mira lo que pasa
&lt;/h2&gt;

&lt;p&gt;Una app necesita información.&lt;br&gt;
No sabe cómo está construido el sistema del otro lado.&lt;br&gt;
No le importa si usa Java, Python o cualquier otra cosa.&lt;/p&gt;

&lt;p&gt;Solo sabe dos cosas: qué puede pedir y qué va a recibir a cambio.&lt;/p&gt;

&lt;p&gt;Volviendo al ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Petición:
GET /buscar?artista=bad-bunny

Respuesta:
{
  "artista": "Bad Bunny",
  "canciones": ["DÁKITI", "Tití Me Preguntó", "Callaíta", ...]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La app no sabe dónde están guardadas esas canciones.&lt;br&gt;
No sabe si el servidor usa una base de datos SQL o NoSQL.&lt;br&gt;
Solo sabe que si pide de esa forma, va a recibir lo que necesita.&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%2F7kqplofiy2whpjo7ok4k.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%2F7kqplofiy2whpjo7ok4k.png" alt="comunications" width="800" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ese intercambio existe aunque casi nunca lo nombremos. Está ahí cada vez que una app pide algo y otra responde.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eso tiene un nombre: API
&lt;/h2&gt;

&lt;p&gt;A esa forma de comunicarse se le llama &lt;strong&gt;API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No es el sistema completo.&lt;br&gt;
No es la base de datos.&lt;br&gt;
No es la lógica interna.&lt;/p&gt;

&lt;p&gt;Es el &lt;strong&gt;acuerdo&lt;/strong&gt; que define cómo dos partes se hablan sin conocerse por dentro.&lt;br&gt;
Y aquí es donde empiezan muchos de los malentendidos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mito #1: “Una API es el backend”
&lt;/h2&gt;

&lt;p&gt;No. El backend es todo lo que pasa detrás:lógica, datos, procesos, decisiones.&lt;/p&gt;

&lt;p&gt;La API es &lt;strong&gt;la puerta&lt;/strong&gt;, no la casa.&lt;/p&gt;

&lt;p&gt;Es lo único que se muestra hacia afuera.&lt;br&gt;
Lo que marca el límite entre lo que se puede usar y lo que no.&lt;/p&gt;

&lt;p&gt;Cuando estas dos cosas se confunden, suele pasar que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;se exponen cosas que no deberían&lt;/li&gt;
&lt;li&gt;se rompen acuerdos sin darse cuenta&lt;/li&gt;
&lt;li&gt;se diseña pensando en el sistema, no en quien lo usa
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mito #2: “Una API es solo una dirección”
&lt;/h2&gt;

&lt;p&gt;Muchas veces se piensa que una API es solo “el lugar al que haces la petición”.&lt;/p&gt;

&lt;p&gt;Como si todo se redujera a mandar algo y esperar respuesta.&lt;br&gt;
Pero una dirección por sí sola no explica nada.&lt;/p&gt;

&lt;p&gt;Puede decirte &lt;strong&gt;a dónde&lt;/strong&gt; ir, pero no te dice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;qué puedes pedir&lt;/li&gt;
&lt;li&gt;cómo hacerlo&lt;/li&gt;
&lt;li&gt;ni qué significa lo que recibes de vuelta
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por ejemplo, &lt;code&gt;/buscar?artista=bad-bunny&lt;/code&gt; es una dirección.&lt;br&gt;
Pero sin saber que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;debes usar el método GET&lt;/li&gt;
&lt;li&gt;el parámetro se llama &lt;code&gt;artista&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;la respuesta será un JSON con canciones
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...esa dirección no te sirve de mucho.&lt;/p&gt;

&lt;p&gt;Esa dirección —a la que luego llamamos &lt;em&gt;endpoint&lt;/em&gt;—, el punto específico donde se hace la petición, solo cobra sentido cuando existen reglas claras alrededor.&lt;/p&gt;

&lt;p&gt;Una API no es solo el punto de entrada. Es el acuerdo completo que le da significado a la conversación.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entonces… ¿qué hacen realmente las APIs?
&lt;/h2&gt;

&lt;p&gt;Las APIs &lt;strong&gt;reducen el caos&lt;/strong&gt;. Permiten que sistemas distintos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;trabajen juntos
&lt;/li&gt;
&lt;li&gt;sin depender uno del otro
&lt;/li&gt;
&lt;li&gt;sin romperse cada vez que algo cambia
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por ejemplo:&lt;/p&gt;

&lt;p&gt;Spotify puede mostrar canciones de Bad Bunny sin importar si:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;el servidor de música está en AWS o en otro cloud provider
&lt;/li&gt;
&lt;li&gt;la base de datos cambió de MySQL a PostgreSQL
&lt;/li&gt;
&lt;li&gt;el equipo de backend reescribió todo en otro lenguaje
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mientras la API siga respondiendo de la misma forma, la app sigue funcionando.&lt;/p&gt;

&lt;p&gt;Eso es lo que hace que puedas usar la misma app en tu teléfono durante años, aunque todo detrás haya cambiado varias veces.&lt;/p&gt;

&lt;p&gt;Cuando una API está bien diseñada, casi no se nota. Cuando no lo está, se siente en cada error, en cada confusión, en cada workaround.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué importa entender esto desde el inicio
&lt;/h2&gt;

&lt;p&gt;Porque cuando no tienes claro qué es una API, todo parece más complejo de lo que es.&lt;/p&gt;

&lt;p&gt;No porque falte aprender más, sino porque muchas veces nadie explicó bien el contexto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Este es solo el comienzo
&lt;/h2&gt;

&lt;p&gt;Este artículo no es para memorizar definiciones.&lt;br&gt;
Es para empezar a &lt;strong&gt;ver&lt;/strong&gt; algo que ya estaba ocurriendo.&lt;/p&gt;

&lt;p&gt;En los siguientes artículos vamos a mirar con más detalle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;qué pasa realmente cuando una app hace una petición&lt;/li&gt;
&lt;li&gt;por qué REST no es el problema &lt;/li&gt;
&lt;li&gt;por qué muchas APIs fallan sin estar “rotas”&lt;/li&gt;
&lt;li&gt;y cómo diseñarlas pensando en personas, no solo en sistemas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si alguna vez sentiste que las APIs eran algo que usabas, pero que nadie te había explicado con claridad… A veces no falta aprender más, sino que alguien explique mejor.&lt;/p&gt;

</description>
      <category>api</category>
      <category>softwaredevelopment</category>
      <category>backend</category>
      <category>español</category>
    </item>
    <item>
      <title>Guía práctica de colas: el secreto para sobrevivir picos de tráfico</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Thu, 29 Jan 2026 16:24:04 +0000</pubDate>
      <link>https://dev.to/aws/guia-practica-de-colas-el-secreto-para-sobrevivir-picos-de-trafico-2g6l</link>
      <guid>https://dev.to/aws/guia-practica-de-colas-el-secreto-para-sobrevivir-picos-de-trafico-2g6l</guid>
      <description>&lt;p&gt;Construir servicios en la nube es emocionante… hasta que llega el primer pico de tráfico serio. Ese día, un servicio que funcionaba perfecto durante semanas, de pronto empieza a fallar, a lanzar timeouts y a colapsar sin piedad.&lt;/p&gt;

&lt;p&gt;Cuando lo viví la primera vez, pensé:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"¿Qué hice mal? ¿Por qué si el sistema está bien diseñado… simplemente no aguanta?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Con el tiempo descubrí que el problema no era el código, ni la infraestructura, ni la configuración. Era algo mucho más básico:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No todos los servicios procesan trabajo al mismo ritmo.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Y cuando un servicio produce más de lo que otro puede consumir… algo truena. Ahí es donde entran las colas. Y una vez las entiendes, te preguntas cómo viviste sin ellas tanto tiempo.&lt;/p&gt;

&lt;h2&gt;
  
  
  El problema real: servicios que no respiran igual
&lt;/h2&gt;

&lt;p&gt;Imagina un sistema donde un proceso genera miles de operaciones por segundo. Pero el servicio que las recibe sólo puede procesar una parte antes de saturarse. Si no hay nada entre ellos, ocurre el desastre perfecto: el servicio receptor se ahoga, se detiene, entra en cascada el resto de la arquitectura, y llega el apagón.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔴 El servicio se satura sin un buffer intermedio
&lt;/h3&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%2Fe6w7aps73u7pwej663yx.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%2Fe6w7aps73u7pwej663yx.png" alt="Servicio saturándose por exceso de solicitudes" width="800" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tal como vemos en el gráfico: cuando el proceso genera miles de operaciones por segundo, pero el servicio tiene un límite de procesamiento. Si le llegan más solicitudes de las que puede manejar, colapsa. No hay nada que absorba el impacto, no hay espacio para respirar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Los tres pilares: eventos, mensajes y colas
&lt;/h2&gt;

&lt;p&gt;Antes de hablar de colas es importante entender tres piezas que siempre trabajan juntas y forman la base de cómo se comunican los sistemas distribuidos: &lt;strong&gt;los eventos&lt;/strong&gt;, &lt;strong&gt;los mensajes&lt;/strong&gt; y &lt;strong&gt;las colas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Vamos de uno en uno.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es un evento?
&lt;/h3&gt;

&lt;p&gt;Un &lt;strong&gt;evento&lt;/strong&gt; es algo que ocurrió en tu sistema y que podría ser relevante para otros componentes o servicios, como por ejemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se registró un usuario&lt;/li&gt;
&lt;li&gt;Se pagó una orden&lt;/li&gt;
&lt;li&gt;Se generó una factura&lt;/li&gt;
&lt;li&gt;Se cargó un archivo&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Un evento representa un cambio de estado.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ¿Qué es un mensaje y cómo se relaciona con un evento?
&lt;/h3&gt;

&lt;p&gt;El evento no se mueve solo: lo empaquetamos dentro de un mensaje.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;El mensaje&lt;/strong&gt; es el sobre/contenedor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El evento&lt;/strong&gt; es el contenido que va dentro&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Un mensaje suele tener:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;body&lt;/strong&gt;: contiene el evento serializado (generalmente JSON)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;metadata&lt;/strong&gt;: información útil (correlationId, timestamps, tipo de evento, origen)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvc7qc8i0a49do7dkyc49.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%2Fvc7qc8i0a49do7dkyc49.png" alt="Relación entre eventos y mensajes" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es una cola?
&lt;/h3&gt;

&lt;p&gt;Una cola es un lugar intermedio donde los mensajes esperan hasta que alguien los procese. Si lo llevamos a la vida real, es como la fila del banco o del súper:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Las personas (mensajes) llegan, se forman, avanzan cuando les toca y, cuando las atienden, salen de la fila.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En software pasa lo mismo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;El productor envía mensajes a la cola&lt;/li&gt;
&lt;li&gt;La cola los almacena de forma temporal&lt;/li&gt;
&lt;li&gt;Uno o varios consumidores los van tomando para procesarlos&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Lo importante de una cola no es solo "guardar cosas", sino lo que habilita en tu arquitectura:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Desacopla&lt;/strong&gt; al que envía del que procesa&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protege&lt;/strong&gt; a tu sistema de picos de tráfico, actuando como un buffer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permite escalar&lt;/strong&gt; consumidores sin cambiar la forma en que los mensajes llegan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Puede ofrecer garantías&lt;/strong&gt; de orden (como las colas FIFO) o priorizar la velocidad (como las colas estándar)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si lo vemos en nuestro ejemplo se vería de la siguiente forma:&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%2Fjm3o8jx9ji58f3f9wp3s.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%2Fjm3o8jx9ji58f3f9wp3s.png" alt="Sistema con cola protegiendo el servicio" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué significa enviar un evento a una cola?
&lt;/h3&gt;

&lt;p&gt;El flujo conceptual siempre es el mismo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Algo ocurre&lt;/li&gt;
&lt;li&gt;Se construye un evento&lt;/li&gt;
&lt;li&gt;Se crea un mensaje&lt;/li&gt;
&lt;li&gt;El mensaje se envía a la cola&lt;/li&gt;
&lt;li&gt;La cola lo almacena&lt;/li&gt;
&lt;li&gt;Un consumidor lo procesa&lt;/li&gt;
&lt;li&gt;Tras procesarlo, el mensaje se elimina&lt;/li&gt;
&lt;/ol&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%2F3sclzojdbltgbjm4g527.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%2F3sclzojdbltgbjm4g527.png" alt="Flujo completo de colas" width="800" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tipos de colas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cola FIFO (First In First Out)
&lt;/h3&gt;

&lt;p&gt;Garantizan que el primer mensaje en entrar es el primero en salir. Características:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Deduplicación automática&lt;/li&gt;
&lt;li&gt;⚠️ Throughput menor&lt;/li&gt;
&lt;li&gt;🎯 Perfectas para flujos secuenciales: pagos, órdenes, pasos obligatorios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnpj3t71kl2e34spmvxgc.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%2Fnpj3t71kl2e34spmvxgc.png" alt="Cola FIFO" width="800" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cola estándar (Standard)
&lt;/h3&gt;

&lt;p&gt;No garantiza orden estricto. Características:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Alta velocidad&lt;/li&gt;
&lt;li&gt;✅ Throughput masivo&lt;/li&gt;
&lt;li&gt;🎯 Ideales para procesamiento masivo: logs, telemetría, tareas repetitivas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F923t9xolqrdmr0b9z4nh.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%2F923t9xolqrdmr0b9z4nh.png" alt="Cola estándar (Standard Queue)" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Restricciones importantes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ⚠️ Restricciones de tamaño
&lt;/h3&gt;

&lt;p&gt;Toma en cuenta que las colas &lt;em&gt;no&lt;/em&gt; están diseñadas para transportar información pesada como por ejemplo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Videos&lt;/li&gt;
&lt;li&gt;❌ PDFs enormes&lt;/li&gt;
&lt;li&gt;❌ Imágenes grandes&lt;/li&gt;
&lt;li&gt;❌ Binarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El mensaje debe ser &lt;strong&gt;pequeño&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si necesitas manejar algo grande, envía solo una referencia, por ejemplo una URL a un archivo en &lt;a href="https://docs.aws.amazon.com/es_es/s3/" rel="noopener noreferrer"&gt;Amazon Simple Storage Service (Amazon S3)&lt;/a&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;"fileUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://s3.com/bucket/reporte.pdf"&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;"PROCESS_FILE"&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;em&gt;Este patrón es universal en casi todos los sistemas de colas.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Por qué usar colas? ¿Cuándo sí y cuándo no?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Cuándo SÍ usar colas
&lt;/h3&gt;

&lt;p&gt;Las colas resuelven problemas concretos como el que comenté al inicio, pero existen más casos donde son una buena idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Cuando tu backend tarda más de lo que el cliente puede esperar&lt;/li&gt;
&lt;li&gt;✅ Cuando necesitas reintentos automáticos&lt;/li&gt;
&lt;li&gt;✅ Cuando una dependencia es lenta o poco confiable&lt;/li&gt;
&lt;li&gt;✅ Cuando quieres desacoplar partes del sistema&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ❌ Cuándo NO usar colas
&lt;/h3&gt;

&lt;p&gt;Pero ten cuidado, como todo, existen casos donde no las necesitas y es mejor evitarlas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Chats o videojuegos en tiempo real&lt;/li&gt;
&lt;li&gt;❌ Procesos que requieren respuesta inmediata&lt;/li&gt;
&lt;li&gt;❌ Lógica que depende del orden exacto en escenarios donde este no puede garantizarse&lt;/li&gt;
&lt;li&gt;❌ Situaciones donde necesitas sincronización estricta entre servicios&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementación práctica con &lt;a href="https://docs.aws.amazon.com/es_es/sqs/" rel="noopener noreferrer"&gt;Amazon Simple Queue Service (Amazon SQS)&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Para entender en la vida real cómo una cola puede salvar tu arquitectura de un colapso durante picos de tráfico, preparé un demo completo que compara ambos escenarios: con y sin colas.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/hsaenzG/queue-101-demo" rel="noopener noreferrer"&gt;Queue 101 Demo - Repositorio en GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El demo incluye ejemplos de código funcional, configuración de infraestructura con AWS CDK, y una comparación práctica que demuestra cómo las colas protegen tu sistema durante picos de tráfico. Incluye instrucciones paso a paso para reproducir ambos escenarios y ver la diferencia en acción.&lt;/p&gt;

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

&lt;p&gt;Las colas no son un detalle técnico opcional. Son una herramienta esencial cuando buscas construir aplicaciones confiables, escalables y resilientes.&lt;/p&gt;

&lt;p&gt;No importa si usas AWS, RabbitMQ, Kafka o cualquier otra plataforma: &lt;strong&gt;los conceptos son los mismos&lt;/strong&gt;. Y con esto en mente ya dominas el superpoder de evitar que tus servicios colapsen durante un pico de tráfico.&lt;/p&gt;




&lt;p&gt;🌟 &lt;strong&gt;Sigue explorando, sigue aprendiendo y disfruta del proceso.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>espanol</category>
      <category>programming</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Chatea con tu propia data: guía práctica con Strands y Amazon Bedrock</title>
      <dc:creator>Hazel Saenz</dc:creator>
      <pubDate>Fri, 12 Sep 2025 03:33:39 +0000</pubDate>
      <link>https://dev.to/aws-espanol/chatea-con-tu-propia-data-guia-practica-con-strands-y-amazon-bedrock-222b</link>
      <guid>https://dev.to/aws-espanol/chatea-con-tu-propia-data-guia-practica-con-strands-y-amazon-bedrock-222b</guid>
      <description>&lt;p&gt;En los últimos meses he estado experimentando con diferentes formas de conectar agentes inteligentes con bases de conocimiento en AWS, y uno de los enfoques que más me ha gustado es combinar Strands con una Knowledge Base de Amazon Bedrock.&lt;/p&gt;

&lt;p&gt;Cuando comencé esta prueba de concepto, mi objetivo era claro: construir una API de chat que no solo respondiera con información general, sino que también pudiera apoyarse en datos contextuales —en este caso, una Knowledge Base con información de libros de Harry Potter. Y aunque suene complejo, la buena noticia es que con la arquitectura serverless de AWS y librerías como strands-agents, el proceso se vuelve mucho más accesible.&lt;/p&gt;

&lt;p&gt;En este artículo te mostraré cómo usar el repositorio strands-poc&lt;br&gt;
 para crear tu propia integración paso a paso.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Qué vas a lograr?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Una API con dos endpoints: /health y /chat.&lt;/li&gt;
&lt;li&gt;Una Lambda en contenedor que usa strands-agents para manejar el flujo conversacional.&lt;/li&gt;
&lt;li&gt;Una Knowledge Base en Amazon Bedrock conectada para responder con datos relevantes.&lt;/li&gt;
&lt;li&gt;Toda la infraestructur
a desplegada con AWS CDK.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Requisitos previos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cuenta de AWS con acceso a Bedrock y Knowledge Bases.&lt;/li&gt;
&lt;li&gt;Python 3.12.&lt;/li&gt;
&lt;li&gt;Docker y AWS CLI configurados.&lt;/li&gt;
&lt;li&gt;AWS CDK instalado.&lt;/li&gt;
&lt;li&gt;Permisos IAM adecuados para Bedrock, Lambda y API Gateway.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Arquitectura general
&lt;/h2&gt;

&lt;p&gt;La solución se compone de:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway con dos endpoints.&lt;/li&gt;
&lt;li&gt;Lambda containerizada (Python 3.12) con Strands.&lt;/li&gt;
&lt;li&gt;Knowledge Base en Bedrock (fuente de datos sincronizada).&lt;/li&gt;
&lt;li&gt;CDK para desplegar todo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Paso a paso
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Crear la Knowledge Base en Bedrock&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Ve a la consola de Amazon Bedrock → Knowledge bases.&lt;/li&gt;
&lt;li&gt;Crea una nueva KB con tu modelo de embeddings favorito.&lt;/li&gt;
&lt;li&gt;Configura el origen de datos (ejemplo: documentos en S3).&lt;/li&gt;
&lt;li&gt;Sincroniza el contenido y toma nota de los IDs (KnowledgeBaseId, DataSourceId).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Documentación oficial: &lt;a href="https://docs.aws.amazon.com/es_es/bedrock/latest/userguide/knowledge-base-create.html?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Create a Knowledge Base&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clonar y configurar el repositorio
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/hsaenzG/strands-poc.git
cd strands-poc

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

&lt;/div&gt;


&lt;p&gt;Copia env.template a .env y edita con tus valores reales (IDs, región, modelo, etc.).&lt;/p&gt;

&lt;p&gt;Instala dependencias locales:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Construir y desplegar la Lambda&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Construye la imagen con Docker (ya preparada para linux/amd64).&lt;/p&gt;

&lt;p&gt;Despliega con CDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk bootstrap
cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto creará API Gateway, la Lambda containerizada y toda la configuración necesaria.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Probar los endpoints&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verifica la salud de la API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://&amp;lt;api_url&amp;gt;/prod/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Haz una consulta al chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST https://&amp;lt;api_url&amp;gt;/prod/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "¿Quién es Dumbledore?", "user_id": "usuario1"}'

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

&lt;/div&gt;



&lt;p&gt;La respuesta vendrá del modelo, enriquecida con información de la Knowledge Base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lecciones aprendidas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Permisos IAM:&lt;/strong&gt; gran parte de los errores iniciales vienen de no asignar correctamente permisos a la Lambda para acceder a Bedrock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Región:&lt;/strong&gt; tanto el modelo, la KB como la Lambda deben estar en la misma región.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking de documentos:&lt;/strong&gt; la calidad de las respuestas depende mucho de cómo fragmentes tu información antes de subirla a la KB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Latencia:&lt;/strong&gt; al usar Knowledge Base + modelos de lenguaje, las llamadas pueden tardar un poco más; considera caching si lo llevas a producción.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda en contenedor:&lt;/strong&gt; la librería de Strands es considerablemente grande y, aun con layers, excederás los límites de tamaño de Lambda. Evítate dolores de cabeza y despliega tu función directamente como una imagen de Docker.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Usar Strands junto con una Knowledge Base de Amazon Bedrock te permite crear asistentes inteligentes que combinan el poder de los LLMs con el conocimiento específico de tus datos. El ejemplo del repo &lt;a href="https://github.com/hsaenzG/strands-poc/blob/main/README.md" rel="noopener noreferrer"&gt;strands-poc&lt;/a&gt; es solo el inicio: puedes reemplazar los libros de Harry Potter por documentación de tu empresa, FAQs de soporte o manuales internos.&lt;/p&gt;

&lt;p&gt;Mi invitación es a que lo pruebes, lo adaptes a tu contexto y me cuentes qué casos de uso se te ocurren. ¡Estoy segura de que encontrarás formas sorprendentes de aplicar este patrón!&lt;/p&gt;

</description>
      <category>strands</category>
      <category>genai</category>
      <category>knowledgebases</category>
      <category>amazonbedrok</category>
    </item>
  </channel>
</rss>
