<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[padz.dev: System Design]]></title><description><![CDATA[System Design do jeito que deveria ser ensinado: com as decisões difíceis, os tradeoffs reais e os erros que custam caro em produção.]]></description><link>https://blog.padz.dev/s/system-design</link><image><url>https://substackcdn.com/image/fetch/$s_!d0XQ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28f3aae4-c6f9-4a2b-9671-b0ff6175501a_512x512.png</url><title>padz.dev: System Design</title><link>https://blog.padz.dev/s/system-design</link></image><generator>Substack</generator><lastBuildDate>Fri, 29 May 2026 18:56:19 GMT</lastBuildDate><atom:link href="https://blog.padz.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Bruno Padilha]]></copyright><language><![CDATA[pt-br]]></language><webMaster><![CDATA[brunopadz@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[brunopadz@substack.com]]></itunes:email><itunes:name><![CDATA[Bruno Padilha]]></itunes:name></itunes:owner><itunes:author><![CDATA[Bruno Padilha]]></itunes:author><googleplay:owner><![CDATA[brunopadz@substack.com]]></googleplay:owner><googleplay:email><![CDATA[brunopadz@substack.com]]></googleplay:email><googleplay:author><![CDATA[Bruno Padilha]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Entendendo falhas em cascata e como construir serviços que sabem quebrar]]></title><description><![CDATA[Por que seu sistema precisa saber falhar antes de saber funcionar]]></description><link>https://blog.padz.dev/p/entendendo-falhas-em-cascata-e-como</link><guid isPermaLink="false">https://blog.padz.dev/p/entendendo-falhas-em-cascata-e-como</guid><dc:creator><![CDATA[Bruno Padilha]]></dc:creator><pubDate>Wed, 29 Apr 2026 17:24:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!-xHL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-xHL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-xHL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 424w, https://substackcdn.com/image/fetch/$s_!-xHL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 848w, https://substackcdn.com/image/fetch/$s_!-xHL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!-xHL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-xHL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg" width="728" height="395.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:791,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:3179142,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/193454324?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-xHL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 424w, https://substackcdn.com/image/fetch/$s_!-xHL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 848w, https://substackcdn.com/image/fetch/$s_!-xHL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!-xHL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e0c2e86-2049-4d49-a5dc-5da206c0598e_3462x1880.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Foto por <a href="https://unsplash.com/@egorkomarov?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Egor Komarov</a> no <a href="https://unsplash.com/photos/distorted-pink-and-black-screen-with-digital-glitch-effects-lR9w7YYglvo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure></div><p style="text-align: justify;">Com o avan&#231;o da utiliza&#231;&#227;o de AI para escrita de c&#243;digo, tenho percebido nos &#250;ltimos meses v&#225;rios novos empreendedores (ou builders), se posso cham&#225;-los assim, prototipando e construindo sistemas e aplica&#231;&#245;es em velocidade assustadora.</p><p style="text-align: justify;">N&#227;o me entendam mal, eu sou totalmente a favor da AI, utilizo muito no trabalho e tamb&#233;m dou risada e concordo com alguns rants do <a href="https://www.linkedin.com/in/kelsey-hightower-849b342b1/">Kelsey Hightower</a> no Linkedin, porque acho que ele tem bons pontos.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dQuD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dQuD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 424w, https://substackcdn.com/image/fetch/$s_!dQuD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 848w, https://substackcdn.com/image/fetch/$s_!dQuD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 1272w, https://substackcdn.com/image/fetch/$s_!dQuD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dQuD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png" width="575" height="205" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:205,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:31878,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/193454324?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dQuD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 424w, https://substackcdn.com/image/fetch/$s_!dQuD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 848w, https://substackcdn.com/image/fetch/$s_!dQuD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 1272w, https://substackcdn.com/image/fetch/$s_!dQuD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ad9ce59-24e6-4b7f-9333-5c57b8f5d43c_575x205.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption"><a href="https://www.linkedin.com/feed/update/urn:li:activity:7444905131743191040/?originTrackingId=5MT4CjNs%2BsWyagYnrdH86Q%3D%3D">Post do Kelsey Hightower no LinkedIn</a></figcaption></figure></div><p style="text-align: justify;">&#201; com esse gancho que eu inicio esse texto. N&#227;o para criticar o mercado, nem os builders, mas para refor&#231;ar que velocidade sem fundamento t&#233;cnico tem prazo de validade e essa &#233; a real. Seu sistema pode nascer r&#225;pido, mas sem uma base s&#243;lida, ele n&#227;o sobrevive por muito tempo.   </p><p style="text-align: justify;">Uma das grandes &#8220;vulnerabilidades&#8221; (al&#233;m as de seguran&#231;a) hoje em dia &#233; como lidar com falhas. Quanto maior o sistema, ou a quantidade de microsservi&#231;os voc&#234; tem, maior a probabilidade que eles falhem. Novamente, precisamos dessa base fundamental, pois sem ela meu amigo, voc&#234; est&#225; lascado para lidar com falhas sem que seu sistema fique inst&#225;vel.</p><div><hr></div><h2>O que s&#227;o Falhas em Cascata</h2><p style="text-align: justify;">Considere um servi&#231;o que voc&#234; administra, ele possui depend&#234;ncias e outros servi&#231;os dependem dele.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9DxO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9DxO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 424w, https://substackcdn.com/image/fetch/$s_!9DxO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 848w, https://substackcdn.com/image/fetch/$s_!9DxO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 1272w, https://substackcdn.com/image/fetch/$s_!9DxO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9DxO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png" width="974" height="402" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:402,&quot;width&quot;:974,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69287,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/193454324?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9DxO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 424w, https://substackcdn.com/image/fetch/$s_!9DxO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 848w, https://substackcdn.com/image/fetch/$s_!9DxO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 1272w, https://substackcdn.com/image/fetch/$s_!9DxO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00c2e011-c68a-4457-a115-6e4c80c59e06_974x402.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p style="text-align: justify;">O que acontece caso uma das depend&#234;ncias falhe? Se voc&#234; n&#227;o implementar nenhum mecanismo de seguran&#231;a, provavelmente o seu servi&#231;o ir&#225; falhar.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0Eq5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0Eq5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 424w, https://substackcdn.com/image/fetch/$s_!0Eq5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 848w, https://substackcdn.com/image/fetch/$s_!0Eq5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 1272w, https://substackcdn.com/image/fetch/$s_!0Eq5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0Eq5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png" width="974" height="445" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:445,&quot;width&quot;:974,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:74465,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/193454324?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0Eq5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 424w, https://substackcdn.com/image/fetch/$s_!0Eq5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 848w, https://substackcdn.com/image/fetch/$s_!0Eq5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 1272w, https://substackcdn.com/image/fetch/$s_!0Eq5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45d1b527-e4c4-4c72-b88c-fa1fdfc5768c_974x445.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p style="text-align: justify;">Agora se o seu servi&#231;o falha, essa falha pode fazer com que os Servi&#231;os A e B tamb&#233;m falhem, causando um caos em toda sua aplica&#231;&#227;o. Muito prazer, o nome disso &#233; falha em cascata. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BStj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BStj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 424w, https://substackcdn.com/image/fetch/$s_!BStj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 848w, https://substackcdn.com/image/fetch/$s_!BStj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 1272w, https://substackcdn.com/image/fetch/$s_!BStj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BStj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png" width="974" height="445" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:445,&quot;width&quot;:974,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81997,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/193454324?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BStj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 424w, https://substackcdn.com/image/fetch/$s_!BStj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 848w, https://substackcdn.com/image/fetch/$s_!BStj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 1272w, https://substackcdn.com/image/fetch/$s_!BStj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b8b3a18-a694-42ac-9a9b-a9f1e12c7a22_974x445.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p style="text-align: justify;">E o que podemos fazer para prevenir isso? Na real &#233; que &#224;s vezes n&#227;o podemos fazer nada, outras vezes um erro em uma depend&#234;ncia cr&#237;tica simplesmente n&#227;o tem contorno. Imagine um cen&#225;rio onde o banco de dados principal est&#225; fora do ar, por exemplo, n&#227;o h&#225; m&#225;gica que salve uma opera&#231;&#227;o de escrita e seu servi&#231;o n&#227;o vai conseguir realizar o que precisa porque essa depend&#234;ncia falhou, por&#233;m, nem sempre esse &#233; o caso e existem v&#225;rias maneiras de &#8220;salvar&#8221; seus servi&#231;os em caso de uma falha de depend&#234;ncia.</p><div><hr></div><h2>Respondendo a Falhas</h2><p style="text-align: justify;">Quando um servi&#231;o que voc&#234; depende falha, como voc&#234; deve responder? A resposta para uma falha de depend&#234;ncia deve ser, previs&#237;vel, de f&#225;cil entendimento e adequada para a situa&#231;&#227;o. Vamos entrar em mais detalhes.</p><h3>Previsibilidade</h3><p style="text-align: justify;">Previsibilidade &#233; uma das caracter&#237;sticas mais importantes que um servi&#231;o pode ter. Dado um conjunto espec&#237;fico de circunst&#226;ncias e requisi&#231;&#245;es, o seu servi&#231;o deve sempre produzir respostas que os consumidores consigam antecipar e tratar. Sem isso, cada falha de depend&#234;ncia se transforma em uma surpresa para quem consome o seu servi&#231;o, e surpresas s&#227;o exatamente o combust&#237;vel das falhas em cascata. </p><p style="text-align: justify;">Assim, se uma de suas depend&#234;ncias downstream falhar voc&#234; consegue gerar uma resposta previs&#237;vel, que pode tranquilamente ser uma mensagem de erro.</p><p style="text-align: justify;">Vale ressaltar que uma resposta de erro n&#227;o &#233; o mesmo que uma resposta imprevis&#237;vel. Uma resposta imprevis&#237;vel &#233; aquela que os servi&#231;os consumidores n&#227;o esperam receber. J&#225; uma resposta de erro &#233; uma resposta v&#225;lida, informando que n&#227;o foi poss&#237;vel executar a opera&#231;&#227;o solicitada. Isso s&#227;o coisas fundamentalmente diferentes.                                                                  </p><p style="text-align: justify;">Imagine o cen&#225;rio: se o seu servi&#231;o de pagamentos recebe uma requisi&#231;&#227;o para cobrar R$50 de um cliente, &#233; esperado que ele retorne uma confirma&#231;&#227;o com o ID da transa&#231;&#227;o. Essa &#233; uma resposta previs&#237;vel. Se esse mesmo servi&#231;o recebe uma requisi&#231;&#227;o com um ID de cliente inexistente, uma resposta previs&#237;vel seria um 404 Not Found ou 400 Bad Request. Ambas s&#227;o respostas previs&#237;veis, pois o servi&#231;o que fez a requisi&#231;&#227;o saber&#225; como interpret&#225;-las e reagir.  </p><p style="text-align: justify;">Agora, uma resposta imprevis&#237;vel seria se esse mesmo servi&#231;o, ao receber uma requisi&#231;&#227;o com um ID de cliente inexistente, retornasse uma confirma&#231;&#227;o de cobran&#231;a com um ID de transa&#231;&#227;o gerado aleatoriamente, como se o pagamento tivesse sido processado com sucesso. Ou pior, retornasse os dados de outro cliente. O consumidor n&#227;o tem como se preparar para esse tipo de resposta porque ela n&#227;o faz parte de nenhum cen&#225;rio esperado. &#201; o tipo de comportamento que transforma uma falha simples em um problema silencioso que s&#243; vai ser descoberto dias depois, numa concilia&#231;&#227;o financeira.                    </p><h3>F&#225;cil Entendimento</h3><p style="text-align: justify;">Aqui &#233; mais simples e direto, f&#225;cil entendimento &#233; formatar uma estrutura acordada entre o servi&#231;o e os servi&#231;os consumidores, ou seja, um contrato onde as respostas devem respeitar seus limites, mesmo quando uma depend&#234;ncia se comporta de forma inesperada.</p><p style="text-align: justify;">Violar esse contrato da sua API com seus consumidores s&#243; porque uma depend&#234;ncia violou o contrato dela com voc&#234; &#233; um super anti-pattern. Ao inv&#233;s disso, garanta que voc&#234; cobriu todas as possibilidades de resposta do seu servi&#231;o, incluindo cen&#225;rios de falha nas suas depend&#234;ncias.</p><p style="text-align: justify;">Um exemplo cl&#225;ssico de viola&#231;&#227;o de contrato &#233; retornar <code>200 OK</code> quando algo deu errado. </p><p style="text-align: justify;">Voltando ao servi&#231;o de pagamentos, se o gateway de cobran&#231;a come&#231;a a falhar e o seu servi&#231;o responde <code>200 OK</code> com uma mensagem de erro no body, o consumidor pode registrar a cobran&#231;a como conclu&#237;da quando ela nunca aconteceu. Um <code>502 Bad Gateway</code> ou <code>503 Service Unavailable</code> seria uma resposta compreens&#237;vel, onde o servi&#231;o que fez a requisi&#231;&#227;o saberia exatamente o que fazer.</p><h3>Respostas Adequadas</h3><p style="text-align: justify;">As respostas devem refletir o que de fato est&#225; acontecendo com o seu servi&#231;o, mesmo quando as depend&#234;ncias est&#227;o falhando, a resposta precisa fazer sentido dentro do dom&#237;nio da opera&#231;&#227;o. Retornar &#8220;n&#227;o foi poss&#237;vel processar a cobran&#231;a&#8221; ou &#8220;tente novamente mais tarde&#8221; s&#227;o respostas razo&#225;veis. Retornar um ID de transa&#231;&#227;o fict&#237;cio ou um valor aleat&#243;rio, n&#227;o s&#227;o.</p><p style="text-align: justify;">Isso parece &#243;bvio, mas respostas absurdas causam problemas com mais frequ&#234;ncia do que se imagina. Considere o seguinte cen&#225;rio onde um servi&#231;o de concilia&#231;&#227;o financeira consulta o servi&#231;o de pagamentos para obter a lista de todas as cobran&#231;as pendentes que precisam ser estornadas. Em condi&#231;&#245;es normais, o servi&#231;o retorna a lista correta e os estornos s&#227;o processados sem problema.                                                   </p><p style="text-align: justify;">Agora imagine que o servi&#231;o de pagamentos est&#225; com uma depend&#234;ncia falhando e, em vez de retornar um erro, retorna uma lista vazia, ou pior, retorna a lista completa de transa&#231;&#245;es, sem filtrar as que s&#227;o pendentes. E o resultado &#233; puro caos! O servi&#231;o de concilia&#231;&#227;o confia nessa resposta e executa estornos em massa, incluindo cobran&#231;as que j&#225; foram liquidadas. O resultado &#233; um desastre financeiro enorme causado n&#227;o por uma falha vis&#237;vel, mas por uma resposta que parecia razo&#225;vel &#224; primeira vista.</p><p style="text-align: justify;">Outro cen&#225;rio perigoso &#233; quando a opera&#231;&#227;o &#233; conclu&#237;da com sucesso, mas a resposta indica falha. Imagine que o servi&#231;o de pagamentos cobra os R$ 50,00 do cliente, o valor &#233; debitado, mas na hora de retornar a confirma&#231;&#227;o algo d&#225; errado e o servi&#231;o responde com um <code>500 Internal Server Error</code>. O consumidor interpreta que a cobran&#231;a n&#227;o aconteceu e faz um retry. Resultado: o cliente &#233; cobrado duas, tr&#234;s, cinco vezes pelos mesmos R$ 50,00.</p><p style="text-align: justify;">Esse &#233; um caso cl&#225;ssico onde a resposta n&#227;o &#233; adequada ao que de fato aconteceu. A cobran&#231;a foi bem-sucedida, mas a resposta disse o contr&#225;rio. Aqui, mecanismos como idempot&#234;ncia, onde o consumidor envia uma chave &#250;nica por requisi&#231;&#227;o e o servi&#231;o garante que a mesma opera&#231;&#227;o n&#227;o ser&#225; executada duas vezes s&#227;o essenciais para evitar esse tipo de estrago.       </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.padz.dev/subscribe?&quot;,&quot;text&quot;:&quot;Inscreva-se&quot;,&quot;language&quot;:&quot;pt-br&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Gostou do que leu at&#233; aqui? Ent&#227;o se inscreva para receber mais conte&#250;dos. &#128640;</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Digite seu e-mail&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Inscreva-se"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Determinando Falhas</h2><p style="text-align: justify;">Agora que sabemos o b&#225;sico do b&#225;sico de como responder a falhas, precisamos determinar quando uma depend&#234;ncia come&#231;a a falhar em primeiro lugar. E isso depende de como a falha aconteceu, vou dar alguns exemplos:</p><h4>Garbled Responses (ou Respostas Confusas)</h4><p style="text-align: justify;">Direto ao ponto, a resposta foi dada em um formato irreconhec&#237;vel pelo servi&#231;o consumidor, exemplo, voc&#234; aguarda um array e a resposta chegou em string.</p><h4>Respostas indicando erro fatal</h4><p style="text-align: justify;">Aqui a resposta j&#225; foi parseada corretamente, indicando um problema ocorreu durante o processamento da requisi&#231;&#227;o. Geralmente, n&#227;o &#233; uma falha na camada de comunica&#231;&#227;o, mas com o servi&#231;o em si.</p><p style="text-align: justify;">No contexto do servi&#231;o de pagamentos, seria o equivalente a enviar uma requisi&#231;&#227;o de cobran&#231;a com um payload inv&#225;lido, por exemplo, sem o valor da transa&#231;&#227;o ou com um formato de moeda que o servi&#231;o n&#227;o reconhece. A resposta <code>400 Bad Request</code> ou <code>500 Internal Server Error</code> &#233; perfeitamente compreens&#237;vel, algo deu errado e o servi&#231;o consumidor sabe que n&#227;o deve confiar em nenhum resultado dessa opera&#231;&#227;o.</p><h4>Resposta compreens&#237;vel, mas com resultados inesperados</h4><p style="text-align: justify;">A resposta &#233; compreens&#237;vel e indica que a opera&#231;&#227;o foi executada sem erros graves, mas os dados retornados n&#227;o correspondem ao esperado. No servi&#231;o de pagamentos, seria como solicitar o extrato de cobran&#231;as de um cliente e receber as cobran&#231;as de outro. A resposta est&#225; bem formatada, o status code &#233; <code>200 OK</code>, mas o conte&#250;do est&#225; errado. Esse tipo de falha &#233; perigoso porque passa despercebido por valida&#231;&#245;es superficiais.</p><h4>Resultado fora dos limites esperados</h4><p style="text-align: justify;">A resposta &#233; compreens&#237;vel pelo servi&#231;o consumidor, a opera&#231;&#227;o foi executada com sucesso, e os dados est&#227;o em um formato &#8220;razo&#225;vel&#8221;, mas os valores em si n&#227;o fazem sentido. Usando nosso exemplo de servi&#231;o de pagamentos &#233; retornado o total de cobran&#231;as pendentes de um cliente e o valor &#233; R$ 9.999,99 para uma assinatura mensal de R$ 49,90. A resposta &#233; v&#225;lida, parse&#225;vel e n&#227;o indica erro, mas est&#225; claramente fora dos limites esperados. Sem uma valida&#231;&#227;o de limites no consumidor, esse valor poderia ser cobrado de fato.                                                                </p><h4>A resposta n&#227;o chegou</h4><p style="text-align: justify;">A requisi&#231;&#227;o foi enviada, mas nenhuma resposta foi recebida. Isso pode acontecer por um problema de rede, uma falha no servi&#231;o ou uma indisponibilidade total. No caso do servi&#231;o de pagamentos, o chamador fica sem saber se a cobran&#231;a foi efetuada ou n&#227;o, ou seja, um cen&#225;rio que exige estrat&#233;gias como idempot&#234;ncia e retry com backoff para ser tratado de forma segura.</p><h4>E quando a resposta demorou pra chegar?</h4><p style="text-align: justify;">A requisi&#231;&#227;o foi enviada e a resposta chegou v&#225;lida, &#250;til e dentro dos limites esperados. Por&#233;m, levou muito mais tempo que o normal. Isso costuma ser um sinal de que o servi&#231;o ou a rede est&#225; sobrecarregada. No servi&#231;o de pagamentos, uma resposta lenta pode significar que o gateway de cobran&#231;a est&#225; sob uma press&#227;o muito alta. Se o servi&#231;o consumidor n&#227;o tiver um timeout adequado, essa lentid&#227;o se propaga para cima, degradando toda a cadeia, o cen&#225;rio cl&#225;ssico de in&#237;cio de uma falha em cascata.</p><div class="callout-block" data-callout="true"><p style="text-align: justify;">Comentei sobre timeout no exemplo acima, mas nem sempre ele funciona. Imagina que um servi&#231;o geralmente leva 70ms para responder, mas esse valor pode variar entre 30ms e 200ms. Como voc&#234; setaria timeout nesses casos?</p><p style="text-align: justify;">Uma resposta &#243;bvia e talvez inocente, voc&#234; seta para um valor acima de 180ms, mas e se o contrato com servi&#231;os e depend&#234;ncias for menor que 140ms? Obviamente, setar o timeout para qualquer valor acima de 180ms n&#227;o &#233; uma boa op&#231;&#227;o, uma vez que voc&#234; estar&#225; passando o erro da sua depend&#234;ncia pro consumidor e isso viola tudo que falei at&#233; agora, principalmente sobre previsibilidade e interpreta&#231;&#227;o.</p><p style="text-align: justify;">Um dos caminhos aqui &#233; utilizar um circuit-breaker. Esse padr&#227;o consiste em monitorar as chamadas que o seu servi&#231;o faz a uma depend&#234;ncia, rastreando quantas s&#227;o bem-sucedidas e quantas falham ou excedem o timeout. Quando um determinado limite de falhas &#233; atingido, o circuit breaker &#8220;abre&#8221;, fazendo com que o servi&#231;o assuma que a depend&#234;ncia est&#225; indispon&#237;vel e pare de enviar requisi&#231;&#245;es para ela. Isso permite que o servi&#231;o detecte a falha imediatamente e tome uma a&#231;&#227;o alternativa. </p><p style="text-align: justify;">No contexto do nosso servi&#231;o de pagamentos, se o gateway de cobran&#231;a come&#231;a a falhar consistentemente, o circuit breaker abre e o servi&#231;o para de tentar processar cobran&#231;as por aquele gateway. Em vez de acumular requisi&#231;&#245;es que v&#227;o dar timeout e degradar toda a cadeia, o servi&#231;o pode retornar imediatamente um erro claro como <code>503 Service Unavailable</code> ou acionar um gateway alternativo, se houver (a&#237; vai da sua arquitetura).</p><p style="text-align: justify;">Periodicamente, o circuit breaker envia uma requisi&#231;&#227;o de teste para a depend&#234;ncia, se ela voltar a responder com sucesso acima de um limite predefinido, o circuito &#8220;fecha&#8221; novamente e o servi&#231;o retoma o fluxo normal. </p></div><p style="text-align: justify;">Uma resposta que demora a chegar de um servi&#231;o (ao inv&#233;s de nunca chegar) &#233; talvez a mais dif&#237;cil de ser detectada, pois o problema come&#231;a em determinar o qu&#227;o lento &#233; lento e aqui o bicho pega por que, usando timeouts ou circuit breakers &#233; geralmente insuficiente para lidar com a situa&#231;&#227;o, porque uma resposta lenta &#224;s vezes pode ser r&#225;pida o suficiente, gerando resultados err&#225;ticos.</p><p style="text-align: justify;">Vale lembrar que previsibilidade da resposta &#233; uma caracter&#237;stica bem importante para seu servi&#231;o e a depend&#234;ncia que falha de forma n&#227;o previs&#237;vel vai complicar a sua habilidade de criar respostas previs&#237;veis para suas depend&#234;ncias. &#201; complicado entender de in&#237;cio, mas depois fica f&#225;cil.</p><div class="callout-block" data-callout="true"><p style="text-align: justify;">Um mecanismo de timeout mais sofisticado, combinado com circuit breaker, pode ajudar a detectar depend&#234;ncias lentas com mais precis&#227;o. A ideia &#233; criar &#8220;buckets&#8221; que categorizam as chamadas recentes a uma depend&#234;ncia com base no tempo de resposta. Cada chamada &#233; registrada no bucket correspondente &#224; sua lat&#234;ncia, e os registros s&#227;o mantidos apenas por um per&#237;odo espec&#237;fico de tempo.                               </p><p style="text-align: justify;">A partir desses buckets, voc&#234; define regras em camadas para acionar o circuit breaker. No servi&#231;o de pagamentos, por exemplo:</p><ul><li><p style="text-align: justify;">Se 500 requisi&#231;&#245;es em um minuto levam mais de 180ms para o gateway de cobran&#231;a responder, o circuit breaker abre;</p></li><li><p style="text-align: justify;">Se 50 requisi&#231;&#245;es em um minuto levam mais de 300ms, o circuit breaker abre;                             </p></li><li><p style="text-align: justify;">Se 5 requisi&#231;&#245;es em um minuto levam mais de 1000 ms, o circuit breaker abre.                                                                                                           </p></li></ul><p style="text-align: justify;">Essa abordagem em camadas captura degrada&#231;&#245;es severas mais rapidamente (bastam 5 requisi&#231;&#245;es muito lentas) sem ignorar degrada&#231;&#245;es mais sutis que se acumulam em volume. Uma lentid&#227;o generalizada de 180ms pode n&#227;o parecer cr&#237;tica em uma &#250;nica requisi&#231;&#227;o, mas 500 delas em um minuto indicam que algo est&#225; errado e que a cascata de falhas est&#225; prestes a come&#231;ar.</p></div><h2>Tomando a&#231;&#245;es</h2><p style="text-align: justify;">Beleza, agora que voc&#234; j&#225; entende como falhas acontecem e como responder a elas, &#233; hora de falar sobre as a&#231;&#245;es que o seu servi&#231;o pode tomar quando uma depend&#234;ncia falha.</p><div class="callout-block" data-callout="true"><p style="text-align: justify;">Recomendo tamb&#233;m a leitura desse post que escrevi em Janeiro/26 sobre Graceful Shutdown. Ele vai complementar muito bem o tema. &#128521;</p><div><hr></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;527f1e7d-a779-4cff-8b59-31fd8e0c45c0&quot;,&quot;caption&quot;:&quot;Imagina o seguinte cen&#225;rio: voc&#234; trabalha em um e-commerce com alto volume de tr&#225;fego e logo no in&#237;cio do ano a diretoria comercial junto ao marketing decide realizar uma mega promo&#231;&#227;o de queima de estoque de produtos que n&#227;o venderam na Black Friday, com desconto agressivo e prazo curto.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Graceful Shutdown - Como n&#227;o perder milhares de Reais em 5 minutos de deploy&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:237891011,&quot;name&quot;:&quot;Bruno Padilha&quot;,&quot;bio&quot;:&quot;Staff Engineer, SRE, container nerd, metalhead, falo e dou pitacos sobre carreira, engenharia de plataforma e resili&#234;ncia, system design e tudo mais relacionado a isso.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d9b6a93-a726-42ee-8a76-12c0456f87ab_800x800.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-01-13T13:03:07.869Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!d7B8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.padz.dev/p/graceful-shutdown-como-nao-perder&quot;,&quot;section_name&quot;:&quot;System Design&quot;,&quot;video_upload_id&quot;:null,&quot;id&quot;:184042490,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:6,&quot;comment_count&quot;:0,&quot;publication_id&quot;:2644309,&quot;publication_name&quot;:&quot;padz.dev&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!FMMt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a90cab4-053c-4135-b892-fb50292d13fd_512x512.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div></div><h3>Graceful Degradation</h3><p style="text-align: justify;">Se uma depend&#234;ncia falha, o seu servi&#231;o consegue continuar operando sem a resposta dessa depend&#234;ncia? Consegue executar ao menos uma parte do trabalho esperado? Se sim, isso &#233; um exemplo de Graceful Degradation, ou usando um termo em portugu&#234;s &#8220;degrada&#231;&#227;o graciosa&#8221;.     </p><p style="text-align: justify;">Graceful Degradation &#233; quando um servi&#231;o reduz o m&#237;nimo poss&#237;vel a quantidade de trabalho que realiza diante da indisponibilidade de uma depend&#234;ncia.</p><div class="callout-block" data-callout="true"><p><strong>Funcionalidade reduzida</strong></p><p style="text-align: justify;">Imagine que nosso servi&#231;o de pagamentos possui uma tela de checkout que exibe, al&#233;m do formul&#225;rio de cobran&#231;a, o hist&#243;rico recente de compras do cliente. Esse hist&#243;rico &#233; fornecido por um servi&#231;o de pedidos. Se o servi&#231;o de pedidos falha, o que o checkout deveria fazer?</p><p style="text-align: justify;">Uma op&#231;&#227;o &#233; continuar exibindo o formul&#225;rio de pagamento normalmente sem o hist&#243;rico de compras, ou com uma mensagem como &#8220;n&#227;o foi poss&#237;vel carregar suas compras recentes&#8221;. </p><p style="text-align: justify;">O cliente ainda consegue concluir a compra, que &#233; a opera&#231;&#227;o cr&#237;tica. O checkout continua funcionando, apenas com a capacidade reduzida de n&#227;o exibir o hist&#243;rico.</p><p style="text-align: justify;">Isso &#233; muito superior a derrubar toda a p&#225;gina de checkout e retornar um erro para o usu&#225;rio simplesmente porque um componente secund&#225;rio est&#225; indispon&#237;vel. A cobran&#231;a &#233; o que importa, o hist&#243;rico &#233; complementar.</p></div><h3>Graceful Backoff</h3><p style="text-align: justify;">Existe um ponto em que a degrada&#231;&#227;o n&#227;o &#233; mais suficiente, simplesmente n&#227;o h&#225; resultados dispon&#237;veis o bastante para que a resposta seja &#250;til. A requisi&#231;&#227;o precisa falhar. Mas em vez de apenas retornar um erro, ser&#225; que o seu servi&#231;o consegue realizar alguma a&#231;&#227;o alternativa que ainda entregue valor ao consumidor?</p><p style="text-align: justify;">Mudar o que o servi&#231;o faz de forma a oferecer algum valor, mesmo quando n&#227;o &#233; poss&#237;vel completar a requisi&#231;&#227;o original, &#233; um exemplo de Graceful Backoff.</p><p style="text-align: justify;">No servi&#231;o de pagamentos, imagine que o gateway principal de cobran&#231;a e o gateway secund&#225;rio est&#227;o ambos fora do ar. N&#227;o h&#225; como processar o pagamento. Em vez de simplesmente retornar um <code>503</code> e deixar o cliente sem resposta, o servi&#231;o poderia registrar a inten&#231;&#227;o de compra e responder com algo como &#8220;n&#227;o conseguimos processar seu pagamento agora, mas salvamos seu carrinho, voc&#234; receber&#225; um aviso assim que o pagamento puder ser conclu&#237;do&#8221;. O pedido n&#227;o foi finalizado, mas o cliente n&#227;o perdeu a sele&#231;&#227;o de produtos, e o servi&#231;o preservou a possibilidade de convers&#227;o futura.</p><h3>Falhe o Mais R&#225;pido Poss&#237;vel</h3><p style="text-align: justify;">E quando n&#227;o for poss&#237;vel continuar operando sem a resposta da depend&#234;ncia que falhou? Se n&#227;o existe uma funcionalidade reduzida ou um graceful backoff que fa&#231;a sentido? Sem aquela resposta, o servi&#231;o simplesmente n&#227;o consegue fazer nada &#250;til. Nesse caso, a &#250;nica op&#231;&#227;o &#233; falhar a requisi&#231;&#227;o, e quando isso acontece, &#233; fundamental falhar o mais r&#225;pido poss&#237;vel. N&#227;o continue executando outras etapas da requisi&#231;&#227;o original depois de saber que ela vai falhar.                     </p><p style="text-align: justify;">No servi&#231;o de pagamentos, se o servi&#231;o de antifraude est&#225; indispon&#237;vel e a pol&#237;tica da empresa exige valida&#231;&#227;o de fraude antes de qualquer cobran&#231;a, n&#227;o h&#225; como prosseguir. Nesse cen&#225;rio, n&#227;o faz sentido validar o cart&#227;o, reservar estoque ou gerar um ID de transa&#231;&#227;o, tudo isso ser&#225; descartado. O servi&#231;o deve retornar imediatamente um erro claro e liberar os recursos.</p><p style="text-align: justify;">Aqui voc&#234; pode realizar o m&#225;ximo de valida&#231;&#245;es poss&#237;veis logo no in&#237;cio da requisi&#231;&#227;o. Verifique campos obrigat&#243;rios, limites de valor, formato do cart&#227;o e permiss&#245;es do cliente antes de acionar qualquer depend&#234;ncia externa. Assim, quando o servi&#231;o avan&#231;ar para as etapas mais custosas, h&#225; uma boa chance de que a requisi&#231;&#227;o ser&#225; conclu&#237;da com sucesso, e as falhas evit&#225;veis j&#225; foram eliminadas antes de consumir recursos desnecess&#225;rios.  </p><p style="text-align: justify;">Agora, por que falhar cedo?</p><h4>Conservar Recursos</h4><p style="text-align: justify;">Se uma requisi&#231;&#227;o vai falhar, qualquer trabalho realizado antes de identificar essa falha &#233; trabalho desperdi&#231;ado. No servi&#231;o de pagamentos, imagine processar uma cobran&#231;a sem antes verificar se o cliente existe. O servi&#231;o consulta o gateway de antifraude, valida o cart&#227;o, reserva estoque, e s&#243; ent&#227;o descobre que o ID do cliente &#233; inv&#225;lido. Todas essas chamadas para depend&#234;ncias externas consumiram recursos &#224; toa, apenas para resultar em um erro.</p><h4>Responsividade                                                    </h4><p style="text-align: justify;">Quanto antes o servi&#231;o determinar que uma requisi&#231;&#227;o vai falhar, antes poder&#225; devolver essa informa&#231;&#227;o ao servi&#231;o consumidor. No servi&#231;o de pagamentos, se o valor da cobran&#231;a &#233; negativo, rejeitar imediatamente com um <code>400 Bad Request</code> permite que o consumidor corrija e reenvie a requisi&#231;&#227;o em milissegundos ao inv&#233;s de esperar segundos por um timeout de uma depend&#234;ncia que nem precisava ser acionada.</p><h4>Complexidade do erro</h4><p style="text-align: justify;">&#192;s vezes, permitir que uma requisi&#231;&#227;o que vai falhar avance pelo fluxo s&#243; ficar&#225; mais dif&#237;cil de debugar e entender onde est&#225; o problema. </p><p style="text-align: justify;">No servi&#231;o de pagamentos, considere uma cobran&#231;a com valor zero. &#201; poss&#237;vel detectar isso imediatamente e rejeitar a requisi&#231;&#227;o. Mas se o servi&#231;o seguir adiante e enviar essa cobran&#231;a ao gateway, o comportamento pode ser imprevis&#237;vel, o gateway pode retornar um erro gen&#233;rico, travar em um loop de retry interno, ou at&#233; registrar uma transa&#231;&#227;o fantasma que depois precisar&#225; ser conciliada manualmente. </p><p style="text-align: justify;">Uma falha simples se transforma em um problema operacional muito mais dif&#237;cil de resolver.</p><h2>Se liga a&#237; que &#233; hora da revis&#227;o!</h2><p style="text-align: justify;">Falhas em cascata n&#227;o come&#231;am com uma explos&#227;o. Elas come&#231;am com uma resposta lenta que ningu&#233;m notou, um timeout mal configurado, ou um servi&#231;o que retornou <code>200 OK</code> quando deveria ter retornado um erro. O estrago acontece de forma silenciosa, depend&#234;ncia por depend&#234;ncia, at&#233; que o sistema inteiro caia e a&#237; j&#225; &#233; tarde demais.</p><p style="text-align: justify;">A boa not&#237;cia &#233; que a maioria dessas falhas &#233; f&#225;cil de prevenir. Respostas previs&#237;veis, contratos bem definidos, circuit breakers, graceful degradation e a disciplina de falhar cedo s&#227;o padr&#245;es que existem h&#225; anos, o desafio &#233; aplic&#225;-las de forma consistente.</p><p style="text-align: justify;">Novamente, construir r&#225;pido &#233; &#243;timo. A AI est&#225; possibilitando isso todos os dias, mas construir r&#225;pido e de forma resiliente &#233; o que separa um prot&#243;tipo de um sistema production-ready. </p>]]></content:encoded></item><item><title><![CDATA[Graceful Shutdown - Como não perder milhares de Reais em 5 minutos de deploy]]></title><description><![CDATA[Um guia completo para encerrar aplica&#231;&#245;es de forma controlada]]></description><link>https://blog.padz.dev/p/graceful-shutdown-como-nao-perder</link><guid isPermaLink="false">https://blog.padz.dev/p/graceful-shutdown-como-nao-perder</guid><dc:creator><![CDATA[Bruno Padilha]]></dc:creator><pubDate>Tue, 13 Jan 2026 13:03:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!d7B8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d7B8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d7B8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 424w, https://substackcdn.com/image/fetch/$s_!d7B8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 848w, https://substackcdn.com/image/fetch/$s_!d7B8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!d7B8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d7B8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg" width="1456" height="911" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:911,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:691631,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/184042490?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!d7B8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 424w, https://substackcdn.com/image/fetch/$s_!d7B8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 848w, https://substackcdn.com/image/fetch/$s_!d7B8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!d7B8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2be8574-b8ec-4d10-9785-75ebbd2f637a_2832x1772.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Foto por <a href="https://unsplash.com/@sydsujuaan?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Syd Sujuaan</a> no <a href="https://unsplash.com/photos/closeup-photo-of-rippling-sea-water-08I-aPLola0?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure></div><p>Imagina o seguinte cen&#225;rio: voc&#234; trabalha em um e-commerce com alto volume de tr&#225;fego e logo no in&#237;cio do ano a diretoria comercial junto ao marketing decide realizar uma mega promo&#231;&#227;o de queima de estoque de produtos que n&#227;o venderam na Black Friday, com desconto agressivo e prazo curto.</p><p>Tudo no ar, campanhas rodando em redes sociais, tr&#225;fego subindo, todo mundo animado. At&#233; que percebem que um c&#225;lculo errado de pre&#231;o est&#225; sendo aplicado em parte do cat&#225;logo, afetando diretamente alguns dos produtos da promo&#231;&#227;o.</p><p>N&#227;o tem muito o que discutir, &#233; preciso corrigir. A &#250;nica sa&#237;da &#233; um novo deploy para sanar o problema.</p><p>Seu time faz a corre&#231;&#227;o, o CI passa, o deploy come&#231;a. Minutos depois, o time de atendimento dispara no Slack dizendo que v&#225;rios clientes n&#227;o conseguiram finalizar compras nos &#250;ltimos 5 minutos, exatamente o tempo que levou para o rollout da nova vers&#227;o. Carrinhos abandonados, pagamentos falhando, reclama&#231;&#245;es p&#250;blicas. Clim&#227;o.</p><p>Voc&#234; come&#231;a a investigar e percebe que diversas requisi&#231;&#245;es simplesmente n&#227;o foram conclu&#237;das durante o deploy. Algumas morreram no meio do caminho. Outras nunca receberam resposta.</p><p>O que aconteceu? Sua aplica&#231;&#227;o morreu no meio de transa&#231;&#245;es ativas. Pedidos sendo processados foram abortados. Pagamentos ficaram em estados inconsistentes. Workers processando emails de confirma&#231;&#227;o morreram deixando eventos &#243;rf&#227;os no Kafka.</p><p>E agora? Como evitar que isso aconte&#231;a de novo?</p><p>&#201; aqui que entra o Graceful Shutdown, uma forma de encerrar uma aplica&#231;&#227;o de maneira controlada, garantindo que requisi&#231;&#245;es em andamento sejam conclu&#237;das antes do processo morrer.</p><h2>O que &#233; Graceful Shutdown de verdade?</h2><p>Graceful Shutdown &#233; um contrato operacional entre sua aplica&#231;&#227;o e o ambiente onde ela roda. Para satisfazer esse contrato, voc&#234; precisa garantir tr&#234;s coisas:</p><ol><li><p>N&#227;o aceitar novas requests e workloads: Encerrar o recebimento de novas requisi&#231;&#245;es HTTP; Parar de consumir mensagens de filas (Kafka, RabbitMQ, SQS); Sem derrubar conex&#245;es j&#225; estabelecidas com banco de dados ou cache;</p></li><li><p>Completar todo processamento: Aguardar que todas as requisi&#231;&#245;es ativas sejam conclu&#237;das; Processar mensagens que j&#225; foram retiradas da fila; Se ultrapassar um tempo aceit&#225;vel, responder com erro previs&#237;vel, n&#227;o timeout gen&#233;rico.</p></li><li><p>Liberar recursos: Encerrar conex&#245;es com bancos de dados; Commitar offsets do Kafka; Liberar locks de arquivos; Finalizar qualquer comunica&#231;&#227;o ativa com sistemas externos.</p></li></ol><p>Neste artigo, vou mostrar como implementar isso em Go, mas o conceito vale para qualquer linguagem, runtime ou plataforma de orquestra&#231;&#227;o.</p><h1>Como processos sabem que devem morrer?</h1><p>Antes de nos aprofundarmos em Graceful Shutdown, &#233; importante entender como processos s&#227;o &#8220;avisados&#8221; de que precisam parar. Vamos voltar ao cen&#225;rio do e-commerce, quando voc&#234; fez o deploy, o que exatamente aconteceu do ponto de vista do processo rodando no container?</p><h2>Sinais </h2><p>Em sistemas Unix-like, processos s&#227;o notificados atrav&#233;s de sinais. Sinais s&#227;o interrup&#231;&#245;es enviadas pelo sistema operacional (ou por outro processo) para notificar que algo relevante aconteceu e uma a&#231;&#227;o precisa ser tomada.</p><p>Quando um sinal &#233; entregue, o fluxo normal de execu&#231;&#227;o do processo &#233; interrompido para que ele possa reagir a esse evento.</p><p>Por&#233;m, nem todo processo reage da mesma forma a um sinal, e nem todo sinal permite rea&#231;&#227;o.</p><p>Existem tr&#234;s comportamentos poss&#237;veis:</p><h3>Signal handler</h3><p>Um signal handler &#233; uma fun&#231;&#227;o registrada pela aplica&#231;&#227;o para lidar com um sinal espec&#237;fico. Quando o sinal &#233; recebido, o processo n&#227;o morre automaticamente. Em vez disso, o handler &#233; executado, permitindo que a aplica&#231;&#227;o:</p><ul><li><p>Pare de aceitar novas requisi&#231;&#245;es;</p></li><li><p>Aguarde requisi&#231;&#245;es em andamento;</p></li><li><p>Libere recursos;</p></li><li><p>Finalize de forma controlada.</p></li></ul><h3>A&#231;&#227;o padr&#227;o (default action)</h3><p>Se a aplica&#231;&#227;o n&#227;o define um handler, o sistema operacional executa a a&#231;&#227;o padr&#227;o associada ao sinal e dependendo do sinal, essa a&#231;&#227;o pode ser:</p><ul><li><p>Encerrar o processo imediatamente;</p></li><li><p>Ignorar o sinal;</p></li><li><p>Parar (suspender) o processo.</p></li></ul><h3>Unblockable signals (sinais que n&#227;o podem ser tratados)</h3><p>Alguns sinais n&#227;o podem ser interceptados ou ignorados, independentemente do que a aplica&#231;&#227;o fa&#231;a. Os mais conhecidos s&#227;o <code>SIGKILL </code>e o <code>SIGSTOP</code>. Quando um desses sinais &#233; enviado, o processo morre imediatamente, sem chance de cleanup, sem handler, sem tempo de reagir.</p><h3>E em ambientes conteinerizados?</h3><p>No Kubernetes, o processo normalmente recebe um <code>SIGTERM</code> antes de qualquer coisa mais agressiva. Esse &#233; como se fosse um &#250;ltimo aviso educado para a aplica&#231;&#227;o.</p><p>Se a aplica&#231;&#227;o n&#227;o trata <code>SIGTERM</code> ou demora mais do que o tempo configurado, o orquestrador envia um <code>SIGKILL</code> e a sua aplica&#231;&#227;o cai.</p><h2>Voltando ao cen&#225;rio do deploy com bug de pre&#231;o</h2><pre><code>15:29:58 - Deploy iniciado
15:30:00 - Kubernetes envia SIGTERM para Pod antigo
15:30:00 - Sua aplica&#231;&#227;o IGNORA o sinal (n&#227;o tem handler)
15:30:00 - Runtime do Go encerra processo imediatamente
15:30:00 - 47 requisi&#231;&#245;es HTTP ativas abortadas
15:30:00 - 12 mensagens Kafka meio processadas
15:30:00 - 3 workers gerando relat&#243;rios mortos
15:30:01 - Time de atendimento come&#231;a a receber reclama&#231;&#245;es</code></pre><h3>O erro comum</h3><p>Muitos times acham que &#8220;Graceful Shutdown &#233; coisa do Kubernetes&#8221; ou do load balancer, a real &#233; que n&#227;o &#233;.</p><p>O Graceful Shutdown come&#231;a dentro da aplica&#231;&#227;o, no momento em que ela decide o que fazer ao receber um sinal.</p><h1>Lidando com sinais em Go</h1><p>Quando uma aplica&#231;&#227;o Go inicia, antes mesmo da fun&#231;&#227;o<strong> </strong><code>main</code><strong> </strong>rodar, o runtime registra handlers para v&#225;rios sinais do sistema operacional. Esses handlers existem para garantir que o processo termine de forma previs&#237;vel.</p><p>Por&#233;m, para Graceful Shutdown, quase tudo &#233; ru&#237;do. Na pr&#225;tica, tr&#234;s sinais concentram 99% dos cen&#225;rios reais:</p><ul><li><p><code>SIGTERM</code>: Indica que o processo deve encerrar. &#201; o sinal enviado por orquestradores como Kubernetes durante deploys, scale down ou evictions. Ele pode e deve ser tratado pela aplica&#231;&#227;o;</p></li><li><p><code>SIGINT</code>: Normalmente enviado quando algu&#233;m pressiona <code>Ctrl+C</code> no terminal. O comportamento esperado &#233; encerrar de forma limpa, assim como no <code>SIGTERM</code>;</p></li><li><p><code>SIGHUP</code>: Historicamente &#233; um sinal utilizado para indicar fechamento de terminal. Hoje em dia, ele costuma ser usado para recarregar configs.</p></li></ul><p>Por padr&#227;o, ao receber qualquer um desses sinais, o runtime do Go encerra o processo imediatamente. Isso significa que:</p><ul><li><p>Requisi&#231;&#245;es em andamento s&#227;o abortadas;</p></li><li><p>Conex&#245;es s&#227;o fechadas sem aviso;</p></li><li><p>O sistema externo que chamou sua aplica&#231;&#227;o n&#227;o vai receber a resposta.</p></li></ul><p>Para mudar esse comportamento, &#233; necess&#225;rio interceptar os sinais usando o pacote <code>os/signal</code>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xsRp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xsRp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 424w, https://substackcdn.com/image/fetch/$s_!xsRp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 848w, https://substackcdn.com/image/fetch/$s_!xsRp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 1272w, https://substackcdn.com/image/fetch/$s_!xsRp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xsRp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png" width="590" height="712.758064516129" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1498,&quot;width&quot;:1240,&quot;resizeWidth&quot;:590,&quot;bytes&quot;:215407,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/184042490?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xsRp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 424w, https://substackcdn.com/image/fetch/$s_!xsRp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 848w, https://substackcdn.com/image/fetch/$s_!xsRp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 1272w, https://substackcdn.com/image/fetch/$s_!xsRp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca73810-42c1-4305-bcbe-7618d203aa5f_1240x1498.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Basicamente, <code>signal.NotifyContext</code> (dispon&#237;vel desde o Go 1.16) faz com que o runtime notifique os sinais para um contexto ao inv&#233;s de executar o comportamento padr&#227;o, permitindo que voc&#234; configure a melhor forma de prevenir que a aplica&#231;&#227;o termine de forma abrupta.</p><h2>Timeout n&#227;o &#233; detalhe</h2><p>Graceful Shutdown n&#227;o acontece no seu tempo, acontece no tempo que o ambiente permite.</p><p>Quando sua aplica&#231;&#227;o recebe um sinal de encerramento, existe um rel&#243;gio invis&#237;vel rodando. Se ele zerar antes do seu cleanup terminar, o sistema simplesmente mata o processo.</p><p>No Kubernetes, por exemplo, o comportamento padr&#227;o &#233; o seguinte:</p><ul><li><p>Ao iniciar um deploy, scale down ou eviction, o Pod recebe um <code>SIGTERM</code>;</p></li><li><p>A partir desse momento, come&#231;a a contar o valor que &#233; especificado no <code>terminationGracePeriodSeconds</code>, que por padr&#227;o s&#227;o 30 segundos - <a href="https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/">doc</a>;</p></li><li><p>Se o processo ainda estiver vivo ao final desse per&#237;odo, o Kubernetes envia um <code>SIGKILL</code>.</p></li></ul><p>E aqui n&#227;o tem negocia&#231;&#227;o, o <code>SIGKILL</code> n&#227;o pode ser interceptado, tratado ou ignorado. O processo morre imediatamente, no estado em que estiver. </p><p>Isso significa que toda a sua l&#243;gica de shutdown precisa caber dentro dessa janela:</p><ul><li><p>Concluindo requisi&#231;&#245;es em andamento;</p></li><li><p>Respondendo erros controlados se necess&#225;rio;</p></li><li><p>Liberando conex&#245;es;</p></li><li><p>Finalizar goroutines e workers.</p></li></ul><p>No cen&#225;rio do e-commerce, se voc&#234; tem:</p><ul><li><p>Requisi&#231;&#245;es HTTP de checkout que levam 5-8 segundos (valida&#231;&#227;o de estoque, pagamento, nota fiscal);</p></li><li><p>Workers processando emiss&#227;o de Notas Fiscais que levam 10-15 segundos;</p></li><li><p>Consumidor Kafka commitando offsets em batch a cada 30 segundos.</p></li></ul><p>Voc&#234; tem um baita de um problema. O shutdown padr&#227;o de 30s n&#227;o vai dar conta.</p><h2>Parando de receber requisi&#231;&#245;es: HTTP Server</h2><p>Vamos come&#231;ar pelo b&#225;sico, fazer o servidor HTTP parar de aceitar novas requisi&#231;&#245;es. </p><p>O pacote <code>net/http</code> possui o m&#233;todo <code>http.Server.Shutdown(ctx)</code> que implementa Graceful Shutdown nativamente. Ele para de aceitar novas conex&#245;es, aguarda as requisi&#231;&#245;es em andamento completarem (respeitando o contexto passado) e ent&#227;o fecha as conex&#245;es idle. Veja um exemplo <a href="https://github.com/brunopadz/signals-go/blob/main/http.go">aqui</a>.</p><p>Se voc&#234; usa <a href="https://gin-gonic.com/en/">Gin</a>, ele n&#227;o possui m&#233;todo pr&#243;prio, voc&#234; usa o <code>http.Server.Shutdown</code> diretamente, j&#225; que Gin &#233; apenas um wrapper em cima do <code>net/http</code>. Exemplo <a href="https://github.com/brunopadz/signals-go/blob/main/gin.go">aqui</a>.</p><p>J&#225; se voc&#234; usa o <a href="https://gofiber.io/">Fiber</a> (minha escolha pessoal), ele tem seu pr&#243;prio m&#233;todo, o <code>app.ShutdownWithContext(ctx)</code> porque usa o <a href="https://github.com/valyala/fasthttp">fasthttp</a> por baixo e n&#227;o o <code>net/http</code>. <a href="https://github.com/brunopadz/signals-go/blob/main/fiber.go">Exemplo</a>.</p><h3>Comportamento comum aos tr&#234;s</h3><p>Independte da implemente, framework, o comportamento &#233; o mesmo:</p><ul><li><p>Param de aceitar novas conex&#245;es imediatamente;</p></li><li><p>Aguardam requisi&#231;&#245;es ativas finalizarem (com timeout do contexto);</p></li><li><p>Fecham conex&#245;es idle;</p></li><li><p>Por&#233;m, n&#227;o garantem que requisi&#231;&#245;es v&#227;o completar se o timeout do contexto expirar.</p></li></ul><h3>O problema do Kubernetes</h3><p>J&#225; no Kubernetes, mesmo ap&#243;s o Pod ser marcado para termination, o kube-proxy pode demorar alguns segundos (~5-10s) para atualizar as regras de iptables e remover o Pod dos endpoints do Service. </p><p>Durante essa janela, voc&#234; ainda pode receber tr&#225;fego. O que acontece:</p><pre><code>15:30:00 - SIGTERM enviado 
15:30:00 - app.Shutdown() chamado imediatamente 
15:30:00 - Servidor para de aceitar conex&#245;es 
15:30:01 - Cliente tenta conectar &#8594; Connection refused 
15:30:02 - Cliente tenta conectar &#8594; Connection refused 
15:30:05 - kube-proxy finalmente atualiza iptables 
15:30:05 - Agora sim, tr&#225;fego para de chegar</code></pre><p>O resultado s&#227;o clientes recebendo erros 5xx.</p><p>Uma boa solu&#231;&#227;o &#233; implementar um delay antes de chamar o Shutdown:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d8B7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d8B7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 424w, https://substackcdn.com/image/fetch/$s_!d8B7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 848w, https://substackcdn.com/image/fetch/$s_!d8B7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 1272w, https://substackcdn.com/image/fetch/$s_!d8B7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d8B7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png" width="1240" height="864" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:864,&quot;width&quot;:1240,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:159251,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/184042490?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!d8B7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 424w, https://substackcdn.com/image/fetch/$s_!d8B7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 848w, https://substackcdn.com/image/fetch/$s_!d8B7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 1272w, https://substackcdn.com/image/fetch/$s_!d8B7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef82586c-e20b-45a6-97ab-8dec159ae9c0_1240x864.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>E agora o fluxo ficaria algo assim:</p><pre><code>15:30:00 - SIGTERM recebido
15:30:00 - Aplica&#231;&#227;o aguarda 10s (delay intencional)
15:30:05 - kube-proxy atualiza iptables
15:30:10 - app.Shutdown() chamado
15:30:10 - Servidor para de aceitar conex&#245;es (mas n&#227;o chega mais tr&#225;fego)
15:30:12 - Requisi&#231;&#245;es ativas completadas
15:30:12 - Servidor encerrado </code></pre><h2>O que voc&#234; esqueceu de desligar</h2><p>Voc&#234; implementou <code>http.Server.Shutdown</code>, testou localmente, fez deploy em produ&#231;&#227;o. Tudo funcionando. At&#233; que numa ter&#231;a-feira &#224;s 3 da manh&#227; voc&#234; recebe um alerta: mensagens duplicadas no Kafka, jobs incompletos no banco, relat&#243;rios corrompidos.</p><p>O que aconteceu? Seu servidor HTTP morreu corretamente com Graceful Shutdown, mas o resto da aplica&#231;&#227;o morreu no meio do caminho.</p><h3>O problema real</h3><p>Aplica&#231;&#245;es n&#227;o s&#227;o s&#243; servidores HTTP. Elas t&#234;m:</p><ul><li><p>Consumidores de fila processando eventos ass&#237;ncronos;</p></li><li><p>Workers em background gerando relat&#243;rios, enviando emails, processando uploads;</p></li><li><p>Jobs agendados fazendo limpeza, sincroniza&#231;&#227;o, c&#225;lculos peri&#243;dicos;</p></li><li><p>Conex&#245;es persistentes com bancos, caches, message brokers.</p></li></ul><p>Quando voc&#234; faz Graceful Shutdown apenas do servidor HTTP, esses componentes continuam rodando at&#233; o SIGKILL chegar (~30s depois no Kubernetes). O resultado:</p><pre><code><code>15:30:00 - SIGTERM recebido
15:30:00 - HTTP server para de aceitar requests
15:30:02 - HTTP server finaliza &#250;ltimas requisi&#231;&#245;es
15:30:02 - HTTP server encerrado 
15:30:02 - Kafka consumer ainda processando pedido #8472
           &#8627; Validando estoque, reservando produtos...
15:30:15 - Worker ainda gerando nota fiscal do pedido #8480
           &#8627; PDF 70% completo, gravando no S3...
15:30:20 - Job de sincroniza&#231;&#227;o com ERP ainda rodando
           &#8627; Atualizando 4.823 produtos de 10.000...
15:30:30 - SIGKILL &#8594; tudo morre abruptamente
           &#8627; Pedido #8472: estoque reservado mas n&#227;o commitado no Kafka
           &#8627; Nota fiscal #8480: PDF corrompido no S3
           &#8627; Sincroniza&#231;&#227;o ERP: estado inconsistente</code></code></pre><p>A sequ&#234;ncia de shutdown tamb&#233;m &#233; importante. Voc&#234; precisa respeitar as depend&#234;ncias entre componentes: </p><h3>Fase 1</h3><p>Primeiro voc&#234; impede que novos processamentos ocorram no sistema:</p><ol><li><p>HTTP Server para de aceitar requisi&#231;&#245;es;</p></li><li><p>Kafka Consumer para de consumir novos eventos;</p></li><li><p>Jobs agendados devem ser cancelados.</p></li></ol><p>A ideia de fazer nessa ordem &#233; porque o servidor HTTP pode enfileirar eventos no Kafka, e o Kafka pode disparar jobs. Se voc&#234; parar o Kafka antes do HTTP, requisi&#231;&#245;es v&#227;o falhar ao tentar publicar os eventos.</p><h3>Fase 2</h3><p>Aqui a ideia &#233; finalizar todo processamento que est&#225; em andamento:</p><ol><li><p>Requisi&#231;&#245;es HTTP ativas, por exemplo: checkout, pagamento;</p></li><li><p>Kafka Consumers: Finaliza processamento, commita offsets;</p></li><li><p>Workers: Completa gera&#231;&#227;o de Notas Fiscais, envio de e-mails;</p></li><li><p>Jobs: Termina sincroniza&#231;&#227;o com ERP.</p></li></ol><h3>Fase 3</h3><p>Por fim, voc&#234; a aplica&#231;&#227;o deve liberar conex&#245;es com recursos externos:</p><ol><li><p>Fecha conex&#245;es com o Kafka, tanto de producer quanto consumer;</p></li><li><p>Encerra conex&#227;o com o banco de dados;</p></li><li><p>Encerra conex&#227;o com o Redis, memcached ou qualquer outro sistema de cache;</p></li><li><p>Libera locks de arquivos.</p></li></ol><p>Essa ordem importa, por que se voc&#234; fechar a conex&#227;o com o banco de dados enquanto os workers ainda est&#227;o salvando Notas Fiscais, voc&#234; ver&#225; um connection closed do nada. Se fechar a conex&#227;o com o Kafka antes de commitar os offsets, vai ter que reprocessar mensagens.</p><p>Exemplo:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SMeF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SMeF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 424w, https://substackcdn.com/image/fetch/$s_!SMeF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 848w, https://substackcdn.com/image/fetch/$s_!SMeF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 1272w, https://substackcdn.com/image/fetch/$s_!SMeF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SMeF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png" width="1240" height="790" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:790,&quot;width&quot;:1240,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:159950,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/184042490?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SMeF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 424w, https://substackcdn.com/image/fetch/$s_!SMeF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 848w, https://substackcdn.com/image/fetch/$s_!SMeF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 1272w, https://substackcdn.com/image/fetch/$s_!SMeF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F389b5c11-4215-4975-8fea-81de0dbb208b_1240x790.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Goroutines tamb&#233;m precisam saber a hora de morrer</h2><p>Outro ponto ignorado com frequ&#234;ncia: goroutines n&#227;o morrem sozinhas.</p><p>Quando o processo recebe um <code>SIGTERM</code>:</p><ul><li><p>O runtime n&#227;o cancela goroutines automaticamente;</p></li><li><p>Loops infinitos continuam rodando;</p></li><li><p>Workers bloqueados continuam bloqueados.</p></li></ul><p>Se voc&#234; n&#227;o tem um mecanismo claro de cancelamento (normalmente via <code>context.Context</code>), voc&#234; est&#225; acreditando que o processo vai morrer r&#225;pido o suficiente, ou o orquestrador vai mandar <code>SIGKILL</code>.</p><p>Nenhuma das duas op&#231;&#245;es &#233; uma boa estrat&#233;gia.</p><p>Uma boa aqui &#233; utilizar context-aware goroutine, <a href="https://github.com/brunopadz/signals-go/blob/main/goroutines_1.go">exemplo</a>. Agora caso voc&#234; tem v&#225;rias goroutines, use <code>sync.WaitGroup</code> para aguardar todas finalizarem, <a href="https://github.com/brunopadz/signals-go/blob/main/goroutines_2.go">exemplo</a>.</p><p>Toda goroutine de longa dura&#231;&#227;o deveria responder a cancelamento. Se ela n&#227;o sabe quando parar, ela &#233; provavelmente &#233; um leak.</p><h2>Shutdown precisa ser previs&#237;vel, n&#227;o best effort</h2><p>Muita gente implementa shutdown como algo &#8220;best effort&#8221;, tenta fechar tudo e torce para dar tempo e isso &#233; fr&#225;gil.</p><p>O shutdown precisa ter:</p><ul><li><p>Ordem clara, o que encerra antes do qu&#234;;</p></li><li><p>Limites de tempo expl&#237;citos;</p><ul><li><p>Lembra das fases que citei acima?</p></li></ul></li><li><p>Fallback bem definido. O que acontece se algo n&#227;o for encerrado conforme esperado?</p></li></ul><p>Esses tempos precisam ser mensurados e testados. Uma dica aqui &#233; adicionar uma gordura. Voltando ao nosso cen&#225;rio:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!o48I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!o48I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 424w, https://substackcdn.com/image/fetch/$s_!o48I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 848w, https://substackcdn.com/image/fetch/$s_!o48I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 1272w, https://substackcdn.com/image/fetch/$s_!o48I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!o48I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png" width="673" height="498.6513859275053" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e0ea64a3-6060-4851-b254-d8879b79f796_938x695.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:695,&quot;width&quot;:938,&quot;resizeWidth&quot;:673,&quot;bytes&quot;:158978,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/184042490?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!o48I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 424w, https://substackcdn.com/image/fetch/$s_!o48I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 848w, https://substackcdn.com/image/fetch/$s_!o48I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 1272w, https://substackcdn.com/image/fetch/$s_!o48I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe0ea64a3-6060-4851-b254-d8879b79f796_938x695.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Vamos relembrar que o <code>terminationGracePeriodSeconds</code> por padr&#227;o no Kubernetes s&#227;o 30 segundos, mas a soma das nossas fases d&#225; ~35s. Isso &#233; intencional, voc&#234; quer que todas fases termine antes do <code>SIGKILL</code>.</p><p>Voc&#234; pode muito bem configurar o lifecycle do seu Deployment/Pod atrav&#233;s do par&#226;metro <code>terminationGracePeriodSeconds</code> e utilizar o <code>preStop</code> hook. </p><h2>Observe o shutdown como um evento cr&#237;tico</h2><p>Outro erro recorrente, o shutdown n&#227;o &#233; observado.</p><p>Em produ&#231;&#227;o, voc&#234; deveria conseguir responder:</p><ul><li><p>Quanto tempo o shutdown levou?</p></li><li><p>Q que demorou mais?</p></li><li><p>Quantas requisi&#231;&#245;es foram abortadas?</p></li><li><p>Houve timeout?</p></li></ul><p>Sem logs claros e m&#233;tricas, o shutdown vira um buraco negro. Quando algo d&#225; errado, ningu&#233;m sabe o real motivo.</p><p>Talvez esse seja o grande ponto de reflex&#227;o do meu post, Graceful Shutdown &#233; um evento operacional importante, n&#227;o um detalhe de implementa&#231;&#227;o.</p><h3>Dicas para mensurar</h3><ul><li><p>Atrav&#233;s m&#233;tricas para mensurar o tempo de dura&#231;&#227;o do shutdown;;</p></li><li><p>Atrav&#233;s de logs contendo dura&#231;&#227;o, quantas requests estavam ativas, quantos jobs estavam pendentes;</p></li><li><p>Crie uma dashboard para monitorar esses tempos, com dura&#231;&#227;o do shutdown, quantos shutdowns foram bem sucedidos, a dura&#231;&#227;o por fase e quantas requests foram abortadas;</p></li><li><p>Alerte apenas em casos cr&#237;ticos. Quando o shutdown est&#225; pr&#243;ximo dos 30s ou do valor que voc&#234; definir do <code>terminationGracePeriodSeconds</code>.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4Lda!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4Lda!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 424w, https://substackcdn.com/image/fetch/$s_!4Lda!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 848w, https://substackcdn.com/image/fetch/$s_!4Lda!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 1272w, https://substackcdn.com/image/fetch/$s_!4Lda!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4Lda!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png" width="630" height="401.3709677419355" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:790,&quot;width&quot;:1240,&quot;resizeWidth&quot;:630,&quot;bytes&quot;:125370,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.padz.dev/i/184042490?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4Lda!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 424w, https://substackcdn.com/image/fetch/$s_!4Lda!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 848w, https://substackcdn.com/image/fetch/$s_!4Lda!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 1272w, https://substackcdn.com/image/fetch/$s_!4Lda!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93f0fe0f-31e1-441d-ae5c-80a33dc2935f_1240x790.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Exemplo de m&#233;tricas</figcaption></figure></div><p></p><h3>N&#227;o teste s&#243; quando d&#225; problema</h3><p>Shutdown precisa ser testado:</p><ul><li><p>Localmente durante desenvolvimento;</p></li><li><p>Em staging antes de subir pra produ&#231;&#227;o;</p></li><li><p>Sob carga com tr&#225;fego real;</p></li><li><p>Com lat&#234;ncia que possa simular depend&#234;ncias lentas;</p></li><li><p>Com depend&#234;ncias como banco de dados e Kafka falhando.</p></li></ul><p>Quanto antes voc&#234; falhar, mais barato &#233; corrigir.</p><h1>Conclus&#227;o</h1><p>Graceful Shutdown n&#227;o &#233; uma feature opcional nem um detalhe de infraestrutura.<br>Ele &#233; parte do contrato da aplica&#231;&#227;o com o ambiente onde ela roda.</p><p>Se voc&#234; ignora:</p><ul><li><p>Sinais do sistema operacional;</p></li><li><p>Limites de tempo impostos pelo orquestrador;</p></li><li><p>Requisi&#231;&#245;es em andamento;</p></li><li><p>Goroutines e workers;</p></li></ul><p>O sistema vai continuar funcionando, at&#233; o dia em que o deploy custar dinheiro, reputa&#231;&#227;o ou ambos.</p><h2>Pr&#243;ximos passos</h2><p>Se voc&#234; ainda n&#227;o tem Graceful Shutdown:</p><ol><li><p>Comece pelo b&#225;sico interceptando <code>SIGTERM</code> e <code>SIGINT</code>;</p></li><li><p>Implemente shutdown do servidor HTTP;</p></li><li><p>Identifique todos os componentes concorrentes (Kafka, workers, jobs);</p></li><li><p>Implemente shutdown coordenado respeitando depend&#234;ncias;</p></li><li><p>Adicione logs e m&#233;tricas;</p></li><li><p>Teste localmente com <code>Ctrl+C</code>;</p></li><li><p>Teste em staging sob carga;</p></li><li><p>Fa&#231;a rollout gradual em produ&#231;&#227;o;</p></li><li><p>Monitore e ajuste timeouts baseado em dados reais.</p></li></ol><p>Se voc&#234; j&#225; tem Graceful Shutdown:</p><ol><li><p>Revise a ordem, ela respeita depend&#234;ncias?;</p></li><li><p>Me&#231;a os timeouts;</p></li><li><p>Adicione observabilidade;</p></li><li><p>Teste sob condi&#231;&#245;es adversas;</p></li><li><p>Configure alertas;</p></li><li><p>Documente.</p></li></ol><div><hr></div><p>Fiquem a vontade para comentar suas solu&#231;&#245;es, como voc&#234;s implementam ou se possuem d&#250;vidas sobre o tema.</p><p>At&#233; mais!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.padz.dev/p/graceful-shutdown-como-nao-perder?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Compartilhar&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.padz.dev/p/graceful-shutdown-como-nao-perder?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Compartilhar</span></a></p>]]></content:encoded></item></channel></rss>