<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marcos Belorio</title>
    <description>The latest articles on DEV Community by Marcos Belorio (@marcosbelorio).</description>
    <link>https://dev.to/marcosbelorio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F565184%2Fb914cdad-ff6c-4b25-b27b-509ca57b1917.jpeg</url>
      <title>DEV Community: Marcos Belorio</title>
      <link>https://dev.to/marcosbelorio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marcosbelorio"/>
    <language>en</language>
    <item>
      <title>Melhorando a observabilidade da sua aplicação - Logs</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Tue, 18 Mar 2025 14:40:06 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/melhorando-a-observabilidade-da-sua-aplicacao-parte-1-logs-jm2</link>
      <guid>https://dev.to/marcosbelorio/melhorando-a-observabilidade-da-sua-aplicacao-parte-1-logs-jm2</guid>
      <description>&lt;p&gt;Quando falamos de sistemas distribuídos e arquiteturas de microsserviços, a observabilidade é fundamental para o sucesso operacional. Diferente do simples monitoramento tradicional, a observabilidade nos permite não apenas identificar que algo está errado, mas entender por que está acontecendo.&lt;/p&gt;

&lt;p&gt;Neste artigo, o primeiro dessa série que pretendo escrever sobre observabilidade, veremos algumas dicas de como melhorar os logs de uma aplicação para entender de maneira mais eficiente e clara o comportamento do seu sistema em produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evite gerar logs excessivos sem filtragem adequada
&lt;/h2&gt;

&lt;p&gt;Deixar sua aplicação gerar um volume excessivo de logs dificulta a equipe a encontrar dados relevantes no meio de tanta informação, além de poder comprometer o custo, considerando que muitos serviços de observabilidade cobram pela quantidade de logs que são ingeridos e armazenados.&lt;/p&gt;

&lt;p&gt;Algumas dicas para ajudar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Não crie logs irrelevantes. Seja crítico e reflita se aquele log trará algum benefício para uma análise futura da aplicação.&lt;/li&gt;
&lt;li&gt;Evite gerar logs dentro de estruturas de loops na aplicação.&lt;/li&gt;
&lt;li&gt;Filtre logs debug e trace em produção.&lt;/li&gt;
&lt;li&gt;Filtre logs de bibliotecas e SDKs com informações irrelevantes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obs: Bibliotecas de logs já possuem essa funcionalidade de filtro. Por exemplo, em .NET você pode utilizar a biblioteca Serilog para configurar esses filtros.&lt;/p&gt;

&lt;h2&gt;
  
  
  Centralize os logs
&lt;/h2&gt;

&lt;p&gt;Se você trabalha com sistemas distribuídos e/ou arquiteturas de microsserviços, centralizar todos os logs desses serviços em um único lugar para consulta e análise é essencial. Sem isso, a sustentação desses serviços será muito difícil.&lt;/p&gt;

&lt;p&gt;Centralizar os logs ajudará a realizar consultas mais rápidas por não precisar alternar entre diferentes interfaces para visualizar os logs, assim como analisar e correlacionar diferentes serviços de maneira fácil.&lt;/p&gt;

&lt;p&gt;Vale lembrar que não estamos falando somente de logs dos serviços que criamos, mas também de logs de serviços que você utiliza de provedores cloud, por exemplo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Padronize o formato dos logs
&lt;/h2&gt;

&lt;p&gt;Logs bem estruturados são mais fáceis de ler, filtrar e agrupar. Por isso, a maioria das aplicações utiliza o formato JSON para formatar os logs. Evite misturar diferentes formatos como JSON, texto simples e XML, principalmente se você precisa visualizar logs de diferentes aplicações/serviços.&lt;/p&gt;

&lt;p&gt;Depois de adotado um formato padrão para o log (preferencialmente JSON), uma segunda definição importante é estabelecer um template padrão. Diferentes serviços gerando logs em diferentes templates dificultarão a realização de buscas em uma ferramenta centralizada. Por exemplo, em um serviço a propriedade se chama "message" e em outro serviço se chama "mensagem".&lt;/p&gt;

&lt;p&gt;Outro ponto que geralmente recebe pouca atenção, mas que frequentemente cria dificuldades ao analisar os logs, é a formatação de datetime ou timestamp e fuso horário. Padronize para que todas as aplicações utilizem a mesma formatação e fuso horário para garantir uma análise consistente (você irá me agradecer no futuro, acredite hehehe).&lt;/p&gt;

&lt;h2&gt;
  
  
  Forneça contexto
&lt;/h2&gt;

&lt;p&gt;Sempre ao criar um log, forneça o máximo de informações relevantes para ser possível identificar padrões de comportamento na aplicação. Evite mensagens genéricas como "Erro no sistema" ou "cliente cadastrado com sucesso". Existem vários tipos de informações que podem contribuir para um log mais completo, as principais são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Informações sobre o ambiente&lt;/strong&gt;: Dados de host, container, IP, configuração (dev/hom/prod), etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Informações sobre a aplicação/serviço&lt;/strong&gt;: nome do serviço, versão de deploy, URL requisitada, nome da classe, nome do método, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identificadores de correlação&lt;/strong&gt;: trace ID, request ID, correlation ID, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Informações de contexto&lt;/strong&gt;: Informações adicionais que fazem sentido para aquele log específico, como parâmetros de entrada, parâmetros de saída, qual ID foi gerado, qual usuário realizou aquela ação, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Em caso de erro&lt;/strong&gt;: Qual foi o erro, stack trace do erro (fornecerá os métodos e linhas por onde o erro percorreu), etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Como fornecer contexto da maneira correta
&lt;/h3&gt;

&lt;p&gt;A maioria das informações exemplificadas acima será configurada para que a aplicação já forneça automaticamente para os logs, exceto as informações de contexto, que são dados que você fornecerá de forma específica para cada log. Tome o cuidado para não fornecer essas informações como string, pois isso dificultará filtros e agrupamentos nas ferramentas de observabilidade. O correto é fornecer esses dados como metadados do log, veja o exemplo abaixo em C#:&lt;/p&gt;

&lt;p&gt;Forma incorreta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;$"Transação #&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; processada: status=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transactionStatus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, tipo=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transactionType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output gerado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transação #45892 processada: status=FINALIZADA, tipo=PAGAMENTO"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forma correta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"Transação #{transactionId} processada: status={transactionStatus}, tipo={transactionType}."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;transactionStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="n"&gt;transactionType&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output gerado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transação #45892 processada: status=FINALIZADA, tipo=PAGAMENTO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"transactionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45892&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"transactionStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FINALIZADA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"transactionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PAGAMENTO"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Remova dados sensíveis
&lt;/h2&gt;

&lt;p&gt;Criar logs com dados sensíveis pode resultar em problemas jurídicos ou de segurança para sua aplicação. Não forneça dados que possam identificar uma pessoa como CPF, nome completo, email e afins. Dados como tokens e senhas também podem expor riscos de segurança.&lt;/p&gt;

&lt;p&gt;Quando um dado sensível precisa realmente estar em um log para trazer contexto e sentido para ele, você pode optar pelo ofuscamento parcial da informação, como por exemplo, fornecer apenas os 5 primeiros números do CPF e ocultar o restante. Existem bibliotecas que podem ajudar com esse ofuscamento, e também as principais ferramentas de observabilidade permitem criar padrões de ofuscamento, geralmente mediante um custo adicional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilize o nível de log correto
&lt;/h2&gt;

&lt;p&gt;Logs não servem apenas para capturar erros; uma estratégia de logging robusta faz uso de todos ou quase todos os diferentes níveis de log. Embora os nomes de cada nível possam variar um pouco entre as linguagens de programação e ferramentas de observabilidade, geralmente são oferecidos seis níveis de log. Para este artigo, utilizarei os nomes dos níveis de log da Microsoft.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Nível&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Critical&lt;/td&gt;
&lt;td&gt;Logs que descrevem um erro catastrófico irrecuperável na aplicação que impede que ela continue funcionando, exigindo atenção imediata.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error&lt;/td&gt;
&lt;td&gt;Logs que destacam quando o fluxo de execução atual é interrompido devido a um erro inesperado. Deve indicar um erro na atividade atual, não um erro em toda a aplicação.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warning&lt;/td&gt;
&lt;td&gt;Indica situações inesperadas ou potencialmente problemáticas mas que não impedem o funcionamento normal. Serve como alerta para possíveis problemas futuros.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Information&lt;/td&gt;
&lt;td&gt;Captura eventos operacionais normais e marcos importantes do fluxo da aplicação, útil para rastrear o funcionamento geral do sistema.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug&lt;/td&gt;
&lt;td&gt;Fornece informações detalhadas úteis para diagnóstico de problemas durante o desenvolvimento ou investigação de problemas; inclui valores de variáveis e fluxo de execução. Não possuem valor a longo prazo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trace&lt;/td&gt;
&lt;td&gt;Registra o nível mais granular de informações, incluindo entrada/saída de métodos e detalhes de processamento interno; usado principalmente durante debugging intensivo. São desabilitadas por padrão e nunca devem ser habilitadas em ambiente de produção.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Configure um período de retenção de logs
&lt;/h2&gt;

&lt;p&gt;Logs são caros para armazenar devido ao alto volume de dados. Configure um período de retenção adequado para o orçamento destinado à observabilidade.&lt;br&gt;
Se sua aplicação precisa de um período maior de armazenamento de logs, considere transferir esses dados após um determinado período para um armazenamento mais econômico. Em algumas ferramentas de observabilidade, como o Datadog, isso é fácil de configurar.&lt;/p&gt;

&lt;p&gt;Sobre retenção de logs, já participei de discussões onde foi defendido que o período de retenção deveria ser extenso (na casa de anos) pois os logs serviam como auditoria da aplicação. Acredito ser um equívoco utilizar os logs como auditoria, pois os dois possuem finalidades distintas (pode até virar tema de outro artigo hehe). &lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Por último, mas não menos importante, a aplicação não deve sofrer bloqueio da thread principal para operações de log. Utilize processamentos assíncronos e buffering de logs para melhorar a performance da aplicação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Implementar boas práticas de logging é importante para construir uma estratégia de observabilidade eficiente. Com logs bem estruturados, padronizados e contextualizados, sua equipe estará melhor equipada para diagnosticar problemas rapidamente e entender o comportamento real do sistema em produção.&lt;/p&gt;

&lt;p&gt;Se você possui alguma dica adicional, ou discorda de algum ponto, por favor, deixe um comentário. Será legal trocar experiências sobre o tema.&lt;/p&gt;

</description>
      <category>observability</category>
      <category>braziliandevs</category>
      <category>logs</category>
    </item>
    <item>
      <title>Cold Start no AWS Lambda: Entendendo seu comportamento e impacto</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Wed, 26 Feb 2025 16:13:36 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/cold-start-no-aws-lambda-entendendo-seu-comportamento-e-impacto-5gjl</link>
      <guid>https://dev.to/marcosbelorio/cold-start-no-aws-lambda-entendendo-seu-comportamento-e-impacto-5gjl</guid>
      <description>&lt;p&gt;Quem já trabalhou com o AWS Lambda já se deparou com o "temido" cold start hehehe, presente em praticamente toda discussão sobre o serviço e frequentemente citado como uma das principais preocupações ao utilizá-lo. A ideia desse artigo é tentar trazer um pouco mais de clareza sobre esse comportamento da Lambda e se de fato ele impacta negativamente o uso do serviço.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é um cold start?
&lt;/h2&gt;

&lt;p&gt;O cold start refere-se ao tempo que uma função AWS Lambda leva para ficar pronta para executar o código implementado, é o seu tempo de inicialização no ambiente de execução. Isso ocorre quando ela é executada pela primeira vez ou após ficar ociosa por um período de tempo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hbds4wcysrz865t33o8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hbds4wcysrz865t33o8.png" alt="Inicialização de uma Lambda" width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podemos ver na imagem acima, o cold start inclui o tempo de download do código da função e o tempo de inicialização do ambiente de execução.&lt;/p&gt;

&lt;p&gt;Uma vez que a Lambda foi inicializada, invocações posteriores não sofrerão o cold start e utilizarão da mesma instância, a menos que, devido às demandas de tráfego, aumente o número de execuções concorrentes, resultando em novas invocações e novos cold starts. Para ajudar na visualização desse comportamento, veja a imagem abaixo:&lt;/p&gt;

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

&lt;p&gt;Para processar execuções concorrentes, foi necessário a inicialização de novas instâncias, causando novos cold starts, porém algumas execuções (execução 6, 7, 8, 10) utilizaram de instâncias já inicializadas e por isso não tiveram o tempo de cold start somados ao tempo total de execução.&lt;/p&gt;

&lt;h2&gt;
  
  
  Impactos do cold start
&lt;/h2&gt;

&lt;p&gt;O cold start pode adicionar desde alguns milissegundos até alguns segundos no tempo total de execução de uma Lambda, dependendo do tamanho da Lambda e alguns outros fatores, como por exemplo, o uso de VPC. &lt;/p&gt;

&lt;p&gt;Outro dado importante é a taxa em que o cold start ocorre perante o total de execuções da Lambda. Isso pode variar muito dependendo do cenário de uso. Lambdas que são muito requisitadas e possuem um padrão de requisição com poucos picos &lt;strong&gt;tendem&lt;/strong&gt; a ter uma taxa muito baixa de cold start, abaixo de 1%. Porém, Lambdas com um padrão de requisição com muitos picos ou Lambdas com pouca requisição &lt;strong&gt;tendem&lt;/strong&gt; a ter taxas maiores de cold start. É muito importante acompanhar essa taxa através de ferramentas de observabilidade. Obs.: A própria AWS menciona que o valor geralmente é abaixo de 1% - &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html#cold-start-latency" rel="noopener noreferrer"&gt;Documentação AWS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;E é aqui que a história começa a ficar interessante. Frequentemente participo de discussões sobre Lambdas onde o cold start recebe atenção desproporcional, em muitos casos, vejo equipes descartando prematuramente o uso de Lambdas apenas por causa desse fator.&lt;/p&gt;

&lt;p&gt;No entanto, como sempre dizemos na arquitetura de software: tudo depende do contexto (a clássica frase da arquitetura, hahaha). Existem cenários onde esse tempo adicional é aceitável, assim como há situações onde esse atraso torna-se inviável.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cenários onde o cold start não é um problema
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cenário mais simples - Quando os cold starts são tão rápidos que não representam um problema
&lt;/h3&gt;

&lt;p&gt;Isso geralmente ocorre com funções que utilizam runtimes como C++, Go e Rust e o código da Lambda é enxuto, facilitando a etapa de download. No entanto, você deve seguir as melhores práticas e otimizações em cada runtime para manter um cold start de baixo impacto.&lt;/p&gt;

&lt;p&gt;Para conhecer melhor o benchmark de cold start por runtime, confira este &lt;a href="https://maxday.github.io/lambda-perf/" rel="noopener noreferrer"&gt;Link&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Execução assíncrona
&lt;/h3&gt;

&lt;p&gt;Outro caso simples é quando sua função é executada de forma assíncrona, seja por SQS, SNS, EventBridge, DynamoDB stream, etc. Nesses casos, um segundo adicional &lt;strong&gt;geralmente&lt;/strong&gt; é aceitável e não representa um problema crítico.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fluxos não críticos
&lt;/h3&gt;

&lt;p&gt;Um tempo adicional de latência de 0,5-1 segundo importa em fluxos não críticos para 1% dos clientes? Provavelmente não, especialmente se for um fluxo interno entre serviços, sem exposição direta ao cliente. Geralmente SLOs de fluxos não críticos observam o percentil p95 ou p97, tolerando o cold start quando a taxa de cold starts se mantém em torno de 1%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cenários com impacto maior - Onde realmente é um problema
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Quando o desempenho é essencial
&lt;/h3&gt;

&lt;p&gt;Os cold starts prejudicam mais quando lidamos com fluxos voltados para o cliente onde o desempenho é crítico, mesmo para aqueles 1% dos clientes. Por exemplo, se você tem microsserviços dedicados à pagamento online que precisam operar com alta concorrência e concluir a execução em menos de 200 ms, 1% de um tempo adicional de 0,5-1 segundo pode ser inaceitável.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quando a taxa de cold start é alta
&lt;/h3&gt;

&lt;p&gt;Conforme vimos anteriormente, a taxa de cold start pode aumentar em cenários com muitos picos de requisição, cenários com poucas requisições ou ainda cenários com grandes variações, tornando o comportamento da Lambda imprevisível. Para esses casos sua função pode ter mais cold starts do que o usual, impactando mais do que 1% do total de requisições.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estratégias para mitigar o cold start
&lt;/h2&gt;

&lt;p&gt;Existem estratégias para tentar mitigar o cold start. Entre elas as principais são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configurar Provisioned Concurrency para sua Lambda (porém vai acarretar em um aumento significativo no custo da sua Lambda, que é uma das principais vantagens do serviço).&lt;/li&gt;
&lt;li&gt;Aquecer sua função implementando mecanismos próprios onde executa a sua função de tempos em tempos de maneira forçada (Este método é menos eficaz para funções com muitas execuções concorrentes, pois sua execução forçada atingiria apenas uma das Lambdas já instanciadas).&lt;/li&gt;
&lt;li&gt;Desenvolvendo funções Lambda em linguagens com menor tempo de cold start (C++, Rust ou Go).&lt;/li&gt;
&lt;li&gt;Ajustando a memória da função para otimizar a inicialização.&lt;/li&gt;
&lt;li&gt;Otimizando dependências e tamanho do pacote (existem muitos artigos na internet que exploram melhor essas otimizações).&lt;/li&gt;
&lt;li&gt;Evitando VPCs sempre que possível! Configurar VPC na sua função requer que a Lambda crie ENIs (elastic network interface) para a VPC alvo, o que facilmente adiciona alguns segundos ao seu cold start.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Os cold starts podem desencorajar as pessoas de usar Serverless, e entendo esse ponto de vista, mas conforme vimos, existem casos e casos, não dá para generalizarmos em relação a esse comportamento. Ao usar o serviço AWS Lambda, é importante monitorar a taxa de cold start através de ferramentas de observabilidade para decisões mais embasadas.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>lambda</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Integrando o Amazon SQS com o AWS Lambda - Entendendo os principais aspectos dessa integração</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Tue, 18 Feb 2025 17:49:52 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/integrando-o-amazon-sqs-com-o-aws-lambda-entendendo-os-principais-aspectos-dessa-integracao-a67</link>
      <guid>https://dev.to/marcosbelorio/integrando-o-amazon-sqs-com-o-aws-lambda-entendendo-os-principais-aspectos-dessa-integracao-a67</guid>
      <description>&lt;p&gt;Neste artigo, a ideia é explorar todos os aspectos que envolvem essa que é uma das principais integrações no mundo serverless: uma Lambda consumindo mensagens do serviço SQS. Apesar de simples de criar, essa integração possui aspectos importantes (alguns desconhecidos pelos desenvolvedores) que impactam diretamente na confiabilidade da sua solução.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conceitos Fundamentais
&lt;/h2&gt;

&lt;p&gt;O Amazon SQS (Simple Queue Service) integrado ao AWS Lambda implementa um modelo de processamento baseado em polling, através de um mecanismo chamado event source mapping para criar um fluxo de processamento. O event source mapping é responsável por realizar uma chamada GET na API do SQS, agrupar os resultados em lotes e invocar de forma &lt;strong&gt;síncrona&lt;/strong&gt; a Lambda. Conforme podemos ver na imagem abaixo:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Mecanismo de Processamento
&lt;/h2&gt;

&lt;p&gt;A Lambda implementa o seguinte fluxo de processamento:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Polling das Mensagens&lt;/strong&gt;&lt;br&gt;
Como vimos, a Lambda realiza consultas periódicas à fila SQS e as mensagens são recuperadas em lotes. Cada lote gera uma única invocação da função Lambda.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ciclo de Visibilidade&lt;/strong&gt;&lt;br&gt;
A partir daqui entra um aspecto importante da integração, o ciclo de visibilidade das mensagens. As mensagens permanecem na fila durante o processamento da Lambda, porém de forma oculta de acordo com o &lt;strong&gt;visibility timeout&lt;/strong&gt; configurado na fila. Quando definimos um visibility timeout de 30 segundos, por exemplo, as mensagens que estão sendo processadas pela Lambda permanecerão invisíveis por este período, evitando assim que outros consumidores tentem processá-las simultaneamente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gerenciamento de Conclusão&lt;/strong&gt;&lt;br&gt;
Se o processamento for bem sucedido, a Lambda remove automaticamente as mensagens da fila. Caso a Lambda tenha uma falha no processamento, as mensagens retornam à fila após a expiração do visibility timeout.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configurações de Processamento em Lote
&lt;/h2&gt;

&lt;p&gt;O trigger SQS para a Lambda oferece configurações específicas para otimização do processamento:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tamanho do Lote&lt;/strong&gt;: Por padrão, agrupa 10 mensagens em uma única execução, mas pode ser aumentado até 10 mil mensagens para filas standard e 10 para filas FIFO.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Janela de Lote (Batch Window)&lt;/strong&gt;: Permite acumular mensagens por até 5 minutos antes de invocar o processamento da Lambda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quando um desses dois critérios é alcançado, dispara a execução da Lambda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Garantias de Processamento
&lt;/h2&gt;

&lt;p&gt;O mecanismo de event source mapping garante processamento "at least once", que significa que uma mensagem será processada pelo menos uma vez, podendo ocorrer processamentos duplicados. Para gerenciar esta característica, é importante a Lambda possuir mecanismo de idempotência.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mecanismos de Tratamento de Erros
&lt;/h2&gt;

&lt;p&gt;A Lambda implementa automaticamente um mecanismo de tratamento de erros que reduz gradualmente a escalabilidade (Lambdas executando em paralelo) durante o consumo de mensagens da fila SQS, prevenindo assim que erros ocorram em larga escala na sua aplicação. &lt;/p&gt;

&lt;p&gt;Em casos de throttling (quando a Lambda retorna erro 429 too many requests), a Lambda tenta reprocessar a &lt;strong&gt;mesma&lt;/strong&gt; mensagem até que o visibility timeout na fila expire. Após esse período, caso o processamento não tenha sido bem sucedido, a mensagem é descartada. 😱😱😱&lt;/p&gt;

&lt;h2&gt;
  
  
  Respostas Parciais de Lote
&lt;/h2&gt;

&lt;p&gt;Por padrão, quando sua função Lambda encontra um erro durante o processamento de um lote, todas as mensagens daquele lote voltam a ficar visíveis na fila, incluindo as que foram processadas com sucesso. Isso pode resultar em dois problemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se a sua Lambda não tratar idempotência, você pode gerar dados duplicados.&lt;/li&gt;
&lt;li&gt;Mesmo se a Lambda tratar idempotência, haverá um reprocessamento desnecessário de mensagens que já foram processadas com sucesso anteriormente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para resolver esse problema podemos implementar as respostas parciais de lote, onde a Lambda executa com sucesso, porém parcial. Na prática, a Lambda remove da fila as mensagens que foram processadas com sucesso e as que foram processadas com erro permanecem na fila para serem reprocessadas.&lt;/p&gt;

&lt;p&gt;Para implementar o sucesso parcial é necessário alterar para &lt;code&gt;true&lt;/code&gt; o valor da propriedade &lt;code&gt;Report batch item failures&lt;/code&gt; no trigger SQS da Lambda e também alterar o retorno da Lambda informando os ids de mensagens que foram processadas com erro, igual este exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"batchItemFailures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"itemIdentifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id2"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"itemIdentifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id4"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obs.: Para algumas linguagens existem bibliotecas da AWS que implementam essa classe de retorno para facilitar o desenvolvimento.&lt;/p&gt;

&lt;p&gt;Pontos importantes sobre respostas parciais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anteriormente foi mencionado o mecanismo de tratamento de erro da Lambda que evita que erros ocorram em larga escala na sua aplicação, pois bem, com o &lt;code&gt;Report batch item failures&lt;/code&gt; ativado, a Lambda não utiliza mais esse mecanismo visto que as execuções serão sempre com sucesso (mesmo que parcial).&lt;/li&gt;
&lt;li&gt;Se sua Lambda lançar uma exceção não tratada, o lote inteiro é considerado como falha completa.&lt;/li&gt;
&lt;li&gt;Para filas FIFO, sua Lambda deve interromper o processamento após a primeira falha e retornar na resposta todas as mensagens que falharam ou não foram processadas, para preservar a ordenação das mensagens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Entendendo como o event source mapping escala as Lambdas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Filas Standard (Padrão)
&lt;/h3&gt;

&lt;p&gt;Ao iniciar o consumo de uma fila SQS standard, o event source mapping instância 5 Lambdas em paralelo, cada uma consumindo um lote de mensagens, se a fila continua com mensagens disponíveis, a Lambda continua escalando até 300 novas instâncias por minuto. O número máximo de lotes sendo processados simultaneamente é de 1000.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filas FIFO
&lt;/h3&gt;

&lt;p&gt;Nas filas FIFO, a Lambda processa as mensagens na ordem em que as recebe. Ao enviar uma mensagem para uma fila FIFO, você especifica um &lt;code&gt;MessageGroupId&lt;/code&gt;. O Amazon SQS garante que as mensagens do mesmo grupo sejam entregues a Lambda em ordem. Quando o event source mapping agrupa as mensagens em lotes, cada lote pode conter mensagens de diferentes grupos, mas sempre mantendo a ordem das mensagens de mesmo &lt;code&gt;MessageGroupId&lt;/code&gt;. Se sua função retornar um erro, todas as tentativas de reprocessamento das mensagens afetadas são realizadas antes que a Lambda receba mensagens adicionais do mesmo grupo, por isso erros em filas FIFO podem comprometer consideravelmente o escalonamento das Lambdas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuração da Concorrência Máxima
&lt;/h2&gt;

&lt;p&gt;Existem dois motivos que podem fazer você considerar controlar o quanto a Lambda pode escalar ao consumir uma fila SQS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Esgotar o limite de instâncias de Lambda executando em paralelo na região, podendo afetar outras Lambdas que também estão executando na sua conta AWS. Isso porque por padrão uma conta AWS possui o limite de 1000 instâncias de Lambda sendo executadas simultaneamente por região (esse limite é aplicado sobre todas as Lambdas da região, e não para cada uma).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sua Lambda pode requisitar alguma API, banco ou qualquer outro serviço que talvez não suporte altos picos de utilização.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Para isso a trigger SQS da Lambda possui a propriedade &lt;code&gt;Maximum concurrency&lt;/code&gt; onde você pode limitar o teto de escalonamento da Lambda.&lt;/p&gt;

&lt;p&gt;Alguns pontos importantes sobre essa configuração:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Maximum concurrency&lt;/code&gt; e &lt;code&gt;Reserve concurrency&lt;/code&gt; são configurações distintas.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Maximum concurrency&lt;/code&gt; não deve ser superior à &lt;code&gt;Reserve concurrency&lt;/code&gt; da Lambda.&lt;/li&gt;
&lt;li&gt;Caso a Lambda tenha múltiplos triggers SQS, a configuração de &lt;code&gt;Reserve concurrency&lt;/code&gt; deve ser maior ou igual à soma do &lt;code&gt;Maximum concurrency&lt;/code&gt; de todas as triggers.&lt;/li&gt;
&lt;li&gt;Caso algum desses pontos acima não seja respeitado, a execução da Lambda pode resultar em throttling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em filas FIFO, as execuções simultâneas são limitadas pelo menor valor entre:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O número de IDs de grupo de mensagens (&lt;code&gt;messageGroupId&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;A configuração de concorrência máxima (&lt;code&gt;Maximum concurrency&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por exemplo, com seis IDs de grupo de mensagens e concorrência máxima configurada para 10, sua função terá no máximo seis execuções simultâneas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações Finais
&lt;/h2&gt;

&lt;p&gt;Entender os aspectos dessa integração é fundamental para implementar uma Lambda robusta, garantindo um processamento confiável das mensagens e um sono tranquilo nas suas noites hehehehe.&lt;/p&gt;

&lt;p&gt;Se você estiver começando a usar o serviço Amazon SQS, recomendo a leitura deste artigo sobre &lt;a href="https://dev.to/marcosbelorio/erros-comuns-ao-usar-o-aws-sqs-2hmg"&gt;os erros mais comuns ao utilizar o SQS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Todos os pontos abordados nesse artigo estão contidos na documentação oficial da AWS que você pode encontrar nos links de referência logo abaixo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html#sqs-polling-behavior" rel="noopener noreferrer"&gt;Using Lambda with Amazon SQS&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/services-sqs-scaling.html" rel="noopener noreferrer"&gt;Configuring scaling behavior for SQS event source mappings&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/services-sqs-errorhandling.html" rel="noopener noreferrer"&gt;Handling errors for an SQS event source in Lambda&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>braziliandevs</category>
      <category>serverless</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Construindo Integrações Serverless Sem Código na AWS</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Tue, 11 Feb 2025 14:47:47 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/construindo-integracoes-serverless-sem-codigo-na-aws-3oha</link>
      <guid>https://dev.to/marcosbelorio/construindo-integracoes-serverless-sem-codigo-na-aws-3oha</guid>
      <description>&lt;p&gt;Olá, pessoal! Nesse artigo eu pretendo mostrar uma forma interessante de se trabalhar com integrações serverless na AWS. Vamos modificar uma integração tradicionalmente utilizada na AWS utilizando Lambda para uma integração sem código.&lt;/p&gt;

&lt;h2&gt;
  
  
  O Cenário Inicial: A Arquitetura Clássica
&lt;/h2&gt;

&lt;p&gt;Quando iniciamos no mundo serverless na AWS fazemos uma arquitetura típica usando Lambda, como por exemplo o fluxo abaixo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uma requisição chega no API Gateway&lt;/li&gt;
&lt;li&gt;O API Gateway aciona uma função Lambda&lt;/li&gt;
&lt;li&gt;A Lambda processa e envia para uma fila SQS&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Parece familiar, não é? É aquela arquitetura que vemos em praticamente todos os tutoriais serverless por aí.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Descoberta: Integrações Nativas
&lt;/h2&gt;

&lt;p&gt;Mas aí veio aquele momento "aha!" que todo desenvolvedor adora. Durante uma palestra no AWS Summit São Paulo 2023 que eu participei, foi apresentado como o API Gateway da AWS pode se integrar com outros serviços diretamente sem a necessidade de processamento computacional, como por exemplo, uma Lambda. Isso significa que podemos fazer nossa API se comunicar diretamente com o SQS, sem precisar de código!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Vantagens e Desvantagens Dessa Solução
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Vantagens
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicidade e Menos Código&lt;/strong&gt;: Reduz a quantidade de serviços e a manutenção de código, já que não existe código hehehe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Baixa Latência&lt;/strong&gt;: Como a integração é direta, a latência da requisição é menor em comparação com uma requisição API → Lambda → SQS. (Não vai mais precisar se preocupar com o cold start da Lambda).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custo&lt;/strong&gt;: Sem custos de processamento computacional, você paga apenas pelo API Gateway e pelo SQS. (Aqui existe um disclaimer, o API Gateway deve ser do tipo API REST para essa integração direta com o SQS poder ocorrer, esse tipo de API Gateway é mais caro porém provê outros recursos adicionais. Se os demais recursos não fizerem sentido para a sua solução, usar a combinação API Gateway tipo API HTTP → Lambda → SQS possa ficar mais barato hehehe).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Desvantagens
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sem Processamento ou Validação&lt;/strong&gt;: Não é possível validar, processar, modificar ou enriquecer os dados antes de enviá-los.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limitação no tamanho do payload&lt;/strong&gt;: O SQS suporta mensagens de até 256 kb.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Como Configurar
&lt;/h2&gt;

&lt;p&gt;Se você ficou interessado pela solução e quer testar ela, este vídeo da própria AWS ensina como criar e configurar um api gateway com SQS no console da cloud.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Eaza-yyPvMY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações Finais: Quando Usar?
&lt;/h2&gt;

&lt;p&gt;Eu particularmente gosto de utilizar essa solução em cenários onde a API deve retornar o status code 202 (Accepted), ou seja, quando a requisição é recebida com sucesso, mas o processamento será feito de forma assíncrona. E você? enxerga algum outro cenário onde essa solução se aplica bem?&lt;/p&gt;

&lt;p&gt;Ficou com alguma dúvida? Quer compartilhar suas experiências com integrações serverless? Deixe nos comentários - adoraria saber sua opinião!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>braziliandevs</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Erros comuns ao usar o Amazon SQS</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Mon, 12 Aug 2024 13:48:03 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/erros-comuns-ao-usar-o-aws-sqs-2hmg</link>
      <guid>https://dev.to/marcosbelorio/erros-comuns-ao-usar-o-aws-sqs-2hmg</guid>
      <description>&lt;p&gt;O Amazon Simple Queue Service (SQS) é um serviço de mensageria totalmente gerenciado e serverless, muito popular por ser simples, altamente escalável e robusto. A proposta desse artigo é trazer alguns erros comuns que devemos nos atentar ao utilizar o serviço.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurar o visibility timeout muito baixo
&lt;/h2&gt;

&lt;p&gt;O visibility timeout determina por quanto tempo uma mensagem permanece indisponível após ser consumida. Se o consumidor não deletar a mensagem antes do término desse período, a mensagem retorna à fila para ser processada novamente.&lt;/p&gt;

&lt;p&gt;Um erro comum é configurar o visibility timeout com um valor que não permita tempo suficiente para o consumidor processar a mensagem. Isso pode resultar em problemas como o processamento duplicado da mesma mensagem, já que o consumidor pode concluir o processamento, mas não conseguir deletar a mensagem antes que ela volte para a fila.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;A AWS recomenda configurar o visibility timeout para ser seis vezes maior que o tempo estimado de processamento da mensagem. Isso ajuda a cobrir cenários de exceção, como eventuais lentidões no processamento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurar o retention period muito baixo
&lt;/h2&gt;

&lt;p&gt;O retention period é usado para determinar o tempo de vida de uma mensagem na fila, uma vez expirado esse tempo, a mensagem é apagada, mesmo não tendo sido consumida.&lt;/p&gt;

&lt;p&gt;Configurar o retention period de forma errada pode causar perda de mensagens na sua aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;Defina um valor generoso para o retention period, lembrando que a AWS &lt;strong&gt;não&lt;/strong&gt; cobra pelo armazenamento das mensagens no SQS. Além disso, é recomendável configurar o retention period máximo de 14 dias para filas DLQ (Dead-Letter Queues). Isso dá ao time de suporte tempo suficiente para identificar e resolver problemas relacionados a essas mensagens, permitindo o reprocessamento adequado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Esperar que as mensagens sejam consumidas na mesma ordem que foram enviadas
&lt;/h2&gt;

&lt;p&gt;O serviço SQS possui dois tipos de filas, o tipo standard e o tipo FIFO, o  tipo standard possui um throughput maior mas não garante a ordem das mensagens, somente o tipo FIFO.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;Se você precisa garantir a ordem do consumo das mensagens, então você deve utilizar a fila do tipo FIFO. Quando você envia uma mensagem para uma fila FIFO, você precisa fornecer um MessageGroupId, esse atributo garante a ordenação entre as mensagens de mesmo id. Lembrando que a fila FIFO não garante ordenação entre mensagens que possuem MessageGroupId diferentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enviar/Consumir mensagens individualmente
&lt;/h2&gt;

&lt;p&gt;O envio ou consumo de mensagens de forma individual pode impactar tanto a performance quanto o custo da aplicação, visto que a AWS cobra pela quantidade de requisições ao serviço do SQS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;A API do SQS permite o envio e o consumo de mensagens em batch, reduzindo o número de requisições ao serviço e, consequentemente, diminuindo os custos. Do ponto de vista de performance, realizar menos requisições com mais dados em cada uma delas tende a ser mais eficiente, pois reduz o número de viagens de ida e volta na rede.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enviar mensagens em batch sem conhecer os limites da action SendMessageBatchCommand
&lt;/h2&gt;

&lt;p&gt;Quando começamos a enviar mensagens em batch pro serviço do SQS, é importante considerar os limites da action &lt;strong&gt;SendMessageBatchCommand&lt;/strong&gt;. Esta action limita o batch a 10 mensagens e o tamanho total da requisição a 256KB, note que o limite de tamanho se aplica à requisição total, não a cada mensagem individualmente. Se uma requisição exceder um desses limites, o batch inteiro de mensagens é recusado, gerando erro na sua aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;Implemente uma lógica na sua aplicação ou utilize alguma lib que garanta o envio de até 10 mensagens e até 256kb por requisição.&lt;/p&gt;

&lt;h2&gt;
  
  
  Não tratar o sucesso parcial da action SendMessageBatchCommand
&lt;/h2&gt;

&lt;p&gt;Outro ponto que traz um pouco mais de complexidade ao usar o envio de mensagens em batch é o fato de que a requisição pode retornar um sucesso parcial. Isso significa que, dentro de uma única requisição, algumas mensagens podem ser enviadas com sucesso, enquanto outras podem falhar. Se esse cenário não for tratado na aplicação, pode resultar em perda de mensagens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;Ao usar a action &lt;strong&gt;SendMessageBatchCommand&lt;/strong&gt;, sua aplicação deve sempre verificar a resposta recebida. Se houver mensagens que não foram enviadas com sucesso, esse cenário deve ser tratado de maneira apropriada, como, por exemplo, tentando reenviar as mensagens falhas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lançar erros durante o consumo de mensagens em batch
&lt;/h2&gt;

&lt;p&gt;Mais um cenário comum que pode resultar em perda de mensagens ou processamento duplicado é a falta de tratamento durante o consumo de mensagens em batch. Normalmente, o consumo de mensagens em batch é realizado dentro de um loop na aplicação, onde cada mensagem é processada individualmente. Como cada processamento pode lançar erros, é necessário que a aplicação esteja preparada para lidar com essas exceções, para não afetar o lote inteiro.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;Em filas do tipo Standard onde a ordenação das mensagens não é relevante, se o processamento de uma mensagem resultar em erro, a aplicação deve permitir que as demais mensagens continuem sendo processadas. As mensagens não processadas devem ser devolvidas à fila para tentativas futuras de processamento. No entanto, para filas do tipo FIFO, onde a ordem das mensagens é importante, se uma mensagem falhar no processamento, a aplicação deve interromper o processamento imediatamente. Todas as mensagens não processadas devem ser devolvidas à fila para tentativas futuras de processamento, ou o lote inteiro pode ser devolvido caso a aplicação esteja preparada para lidar com o consumo duplicado de mensagens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Não tratar duplicidade de mensagens
&lt;/h2&gt;

&lt;p&gt;Por último, aplicações que utilizam mensageria devem estar preparados para um possível cenário de mensagens duplicadas, podendo causar inconsistência de dados.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solução
&lt;/h3&gt;

&lt;p&gt;Aplicar estratégias de idempotência durante o consumo de mensagens, seja diretamente na fila ou no momento da persistência dos dados. Aqui no meu blog eu escrevi como tratar &lt;a href="https://dev.to/marcosbelorio/idempotencia-em-filas-do-servico-aws-sqs-c31"&gt;Idempotência em filas do serviço AWS SQS&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html" rel="noopener noreferrer"&gt;SendMessageBatchCommand&lt;/a&gt;&lt;br&gt;
&lt;a href="https://repost.aws/questions/QUKEwhVpOKT3y6lxstPZL8Eg/what-happens-if-sqs-messages-partially-fail-in-sendmessagebatch" rel="noopener noreferrer"&gt;What happens if SQS messages partially fail in SendMessageBatch?&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>aws</category>
      <category>sqs</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Idempotência em filas do serviço AWS SQS</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Mon, 12 Jun 2023 21:22:46 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/idempotencia-em-filas-do-servico-aws-sqs-c31</link>
      <guid>https://dev.to/marcosbelorio/idempotencia-em-filas-do-servico-aws-sqs-c31</guid>
      <description>&lt;h2&gt;
  
  
  Problema
&lt;/h2&gt;

&lt;p&gt;Quando trabalhamos com aplicações que consomem mensagens de uma fila, um cenário que pode ocorrer é a fila possuir mensagens duplicadas em um fluxo funcional onde isso não poderia acontecer, causando uma inconsistência de dados em nossa aplicação. Esse problema pode ocorrer geralmente por dois motivos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Houve um problema de rede que impediu que o publicador da mensagem recebesse o status da requisição feita ao SQS, fazendo com que seja requisitado novamente.&lt;/li&gt;
&lt;li&gt;Por falta de validações prévias ou algum bug, funcionalmente o publicador acabou enviando a mesma mensagem para a fila.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solução
&lt;/h2&gt;

&lt;p&gt;Existem algumas formas de se resolver esse problema, uma delas é utilizando filas do tipo FIFO no serviço AWS SQS. As filas FIFO possuem uma propriedade chamada MessageDeduplicationId. Se uma mensagem for enviada com um MessageDeduplicationId específico, todas as mensagens enviadas com o mesmo MessageDeduplicationId serão aceitas pela fila, porém NÃO serão entregues durante o intervalo de 5 minutos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Formas de trabalhar com a propriedade MessageDeduplicationId
&lt;/h2&gt;

&lt;p&gt;Existem duas formas de se trabalhar com essa propriedade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A primeira é deixando a cargo do próprio SQS gerar o identificador ativando o "Content-based deduplication" nas configurações do SQS. Ao ativar essa configuração, é gerado um identificador único baseado no conteúdo do corpo da mensagem (não se aplica aos atributos da mensagem). &lt;/li&gt;
&lt;li&gt;A segunda forma de se trabalhar com o MessageDeduplicationId é passando manualmente um valor ao publicar uma mensagem na fila.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cenários recomendados para trabalhar manualmente com o MessageDeduplicationId
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;O publicador adiciona alguma informação no corpo da mensagem que sempre faz com que o conteúdo seja diferente.&lt;/li&gt;
&lt;li&gt;Mensagens com informações nos atributos que também deveriam ser levados em consideração para determinar se a mensagem é duplicada.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>braziliandevs</category>
      <category>aws</category>
      <category>sqs</category>
    </item>
    <item>
      <title>Executando Tasks em paralelo em aplicações .Net com o SemaphoreSlim</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Fri, 11 Mar 2022 12:54:56 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/executando-tasks-em-paralelo-em-aplicacoes-net-com-o-semaphoreslim-4e9n</link>
      <guid>https://dev.to/marcosbelorio/executando-tasks-em-paralelo-em-aplicacoes-net-com-o-semaphoreslim-4e9n</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Neste artigo vamos entender como executar tasks de forma paralela, visualizar possíveis problemas que poderemos causar em nossas aplicações e aprender a utilizar a classe SemaphoreSlim para nos ajudar a gerenciar a execução das tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cenário
&lt;/h2&gt;

&lt;p&gt;Imagine uma aplicação onde será necessário de tempos em tempos processar uma massa de dados relativamente grande (entre 1 mil à 10 mil registros) e para cada registro processado, enviá-lo em uma requisição http. Para essa massa de dados poder ser executada em um tempo aceitável será necessário efetuar processamentos em paralelo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplificando o cenário
&lt;/h2&gt;

&lt;p&gt;Vamos criar um trecho de código simples onde iremos simular o processamento de 10 mil registros de forma paralela:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;        
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Início da execução"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;ProcessarMassaDeDados&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Tempo: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fff&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessarMassaDeDados&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;listOfTasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;listOfTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ProcessarRegistro&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listOfTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessarRegistro&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_httpClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpClientFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://httpstat.us/200?sleep=1000"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como podemos ver no código acima, primeiro criamos uma lista de tasks e adicionamos a task &lt;code&gt;ProcessarRegistro&lt;/code&gt; 10 mil vezes dentro dessa lista, após isso executamos todas elas em paralelo através do comando &lt;code&gt;Task.WaitAll&lt;/code&gt;, esse comando aguarda a conclusão de todas as tasks para poder seguir. Dentro do método &lt;code&gt;ProcessarRegistro&lt;/code&gt; estamos fazendo uma requisição http que demora um segundo para ser executado.&lt;/p&gt;

&lt;p&gt;Rodando esse trecho de código temos o seguinte resultado no meu computador:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Início da execução
Tempo: 1:37.821
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se não executássemos essas tasks em paralelo, iria levar pelo menos 10 mil segundos (166 minutos) para executar tudo, já que cada requisição dura um segundo.&lt;/p&gt;

&lt;p&gt;Olhando esses números o código acima parece nos atender bem, porém esse código só executou bem porque estamos testando em um ambiente local, sem concorrência significativa pelos recursos do sistema. Em um ambiente de produção, onde o sistema pode estar processando centenas de outras requisições simultaneamente, a execução desse código pode não ser tão eficiente. Problemas como esgotamento de recursos (estouro de memória, limite de rede, sobrecarga no banco de dados, etc) pode causar lentidões e até mesmo quebrar a aplicação. Portanto, é crucial considerar esses fatores e implementar mecanismos de controle para evitar a sobrecarga do sistema ao processar tarefas em paralelo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conhecendo a classe SemaphoreSlim
&lt;/h2&gt;

&lt;p&gt;O .Net possui uma classe chamada &lt;code&gt;SemaphoreSlim&lt;/code&gt; que limita o número de tarefas que podem ser executadas simultaneamente.&lt;/p&gt;

&lt;p&gt;Vamos modificar o nosso código e adicionar essa classe para gerenciar as execuções em paralelo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;        
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Início da execução"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;ProcessarMassaDeDadosComSemaforo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Tempo: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fff&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessarMassaDeDadosComSemaforo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;semaphoreSlim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SemaphoreSlim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;listOfTasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;listOfTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ProcessarRegistro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;semaphoreSlim&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listOfTasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessarRegistro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SemaphoreSlim&lt;/span&gt; &lt;span class="n"&gt;semaphoreSlim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;semaphoreSlim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_httpClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpClientFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://httpstat.us/200?sleep=1000"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;semaphoreSlim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como podemos ver, instanciamos a classe &lt;code&gt;SemaphoreSlim&lt;/code&gt; e no seu construtor passamos respectivamente o número inicial de solicitações que podem ser executadas simultaneamente e o número máximo de solicitações que podem ser executadas simultaneamente. &lt;/p&gt;

&lt;p&gt;Isso significa que após 100 tasks estarem sendo executadas em paralelo, a próxima só será executada quando uma dessas 100 terminarem, limitando sempre a no máximo 100 tasks em paralelo.&lt;br&gt;
Obs: No código acima foi usado a quantidade de 100 execuções em paralelo somente como forma de exemplo, o ideal é você calibrar esse número de acordo com o seu cenário e ambiente. &lt;/p&gt;

&lt;p&gt;Dentro do método &lt;code&gt;ProcessarRegistro&lt;/code&gt; usamos o método &lt;code&gt;semaphoreSlim.WaitAsync()&lt;/code&gt; e &lt;code&gt;semaphoreSlim.Release()&lt;/code&gt;, eles que são os responsáveis respectivamente por fazer a execução aguardar e para liberar uma posição no semáforo. &lt;/p&gt;

&lt;p&gt;Rodando o código com as modificações temos o seguinte resultado no meu computador:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Início da execução
Tempo: 2:23.149
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos perceber que o processamento demora um pouco mais porém os recursos do ambiente são utilizados de maneira controlada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Quando criamos uma aplicação devemos sempre considerar que o ambiente em execução possui recursos limitados. A classe SemaphoreSlim pode ser uma boa solução para utilizar esses recursos de maneira controlada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-6.0" rel="noopener noreferrer"&gt;SemaphoreSlim Class - Microsoft Documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mustafatulun.com/using-semaphoreslim-to-make-parallel-http-requests-in-net-core/" rel="noopener noreferrer"&gt;Using SemaphoreSlim to Make Parallel HTTP Requests in .NET Core&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.c-sharpcorner.com/article/understanding-semaphore-in-net-core/" rel="noopener noreferrer"&gt;Understanding Semaphore in .NET Core&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>braziliandevs</category>
      <category>performance</category>
    </item>
    <item>
      <title>Criando dados fake para testes em .Net</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Wed, 12 May 2021 11:24:29 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/criando-dados-fake-para-teste-em-net-46l6</link>
      <guid>https://dev.to/marcosbelorio/criando-dados-fake-para-teste-em-net-46l6</guid>
      <description>&lt;p&gt;Olá, hoje vou apresentar uma biblioteca muito interessante capaz de gerar dados aleatórios muito precisos na nossa língua portuguesa (e outras línguas também) chamada &lt;strong&gt;Bogus&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problema a ser solucionado
&lt;/h2&gt;

&lt;p&gt;Frequentemente nos vemos diante de um teste ou criação de uma POC (proof of concept) onde necessitamos de uma massa de dados para validar nosso código, esses dados necessitam ser o mais parecido possível com o que esperamos para não deixarmos passar nenhum detalhe em nossas validações. Muitas vezes optamos por criar esses dados na mão, mas dependendo da quantidade necessária levamos muito tempo criando, as vezes até duplicando dados.&lt;/p&gt;

&lt;p&gt;Nesse contexto a biblioteca Bogus nos auxilia muito, ela é capaz de gerar uma massa de dados do tamanho que você necessita, de forma rápida sem repetir nenhum registro, com suporte a diferentes línguas e muitas opções de dados para que o teste fique o mais real possível.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstração
&lt;/h2&gt;

&lt;p&gt;Para demonstrar o uso da biblioteca, iremos criar um projeto console em .Net e adicionar a biblioteca através do gerenciador de pacotes nuget ou da execução do comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Bogus&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos também criar nossa classe &lt;code&gt;Pessoa&lt;/code&gt; (mais clássico impossível hahahaha), que será utilizada para gerar nossa massa de dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Nome&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;DataNascimento&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Telefone&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto, vamos agora começar a usar a biblioteca para gerar alguns dados. Dentro da classe &lt;code&gt;Program&lt;/code&gt; da nossa aplicação console iremos configurar para ser gerado um objeto Pessoa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Pessoa&lt;/span&gt; &lt;span class="n"&gt;pessoa&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Pessoa&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"pt_BR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataNascimento&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Past&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Telefone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Phone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PhoneNumberFormat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SerializeObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pessoa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Indented&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você já utilizou a biblioteca &lt;code&gt;FluentValidation&lt;/code&gt; deve estar reconhecendo a forma de configurar, é praticamente igual.&lt;/p&gt;

&lt;p&gt;Olhando o código podemos ver que estamos instanciando a classe &lt;code&gt;Faker&lt;/code&gt; passando Pessoa como tipo genérico e setando a língua para português do Brasil, isso ajuda muito a termos dados mais precisos.&lt;/p&gt;

&lt;p&gt;A partir dai criamos uma regra para cada propriedade da classe Pessoa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setando para a propriedade &lt;code&gt;Id&lt;/code&gt; um valor aleatório inteiro sendo o valor mínimo 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setando para a propriedade &lt;code&gt;Nome&lt;/code&gt; um nome completo aleatório. &lt;/p&gt;

&lt;p&gt;Veja no exemplo abaixo que a biblioteca é tão legal que podemos até especificar se queremos um nome do sexo masculino ou feminino.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bogus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataSets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Male&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setando para a propriedade &lt;code&gt;Email&lt;/code&gt; um email aleatório baseado no nome gerado anteriormente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataNascimento&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Past&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setando para a propriedade &lt;code&gt;DataNascimento&lt;/code&gt; uma data baseada nos últimos 50 anos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Telefone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Phone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PhoneNumberFormat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setando para a propriedade &lt;code&gt;Telefone&lt;/code&gt; um número já formatado no padrão utilizado aqui no Brasil.&lt;/p&gt;

&lt;p&gt;Rodando a aplicação teremos no console o resultado:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc0lvk3d3yy9kpfni3w8.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc0lvk3d3yy9kpfni3w8.PNG" alt="Alt Text" width="659" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podemos ver nos exemplos acima são muitas opções de customização para os dados fazendo com que o resultado seja muito próximo de um dado real.&lt;/p&gt;
&lt;h2&gt;
  
  
  Criando uma grande quantidade de dados
&lt;/h2&gt;

&lt;p&gt;Olhando novamente o exemplo anterior, quem faz de fato o objeto ser criado é o método &lt;code&gt;Generate()&lt;/code&gt;, sendo assim se você precisar de 500 registros, basta você setar &lt;code&gt;Generate(500)&lt;/code&gt; que ele irá gerar 500 registros sendo nenhum deles repetido, segue um exemplo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Pessoa&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pessoaLista&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Faker&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Pessoa&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"pt_BR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataNascimento&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Between&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"01/01/1990"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"01/01/2000"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Telefone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Phone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PhoneNumberFormat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Projeto de exemplo
&lt;/h2&gt;

&lt;p&gt;Caso tenha ficado ainda alguma dúvida no código, você pode ver o exemplo que eu criei nesse repositório do &lt;a href="https://github.com/marcosbelorio/fake-data-example" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se gostou utilize os botões do lado esquerdo para que eu possa saber. Caso tenha alguma dúvida, sugestão ou crítica, deixe um comentário logo abaixo.&lt;/p&gt;

&lt;p&gt;Muito obrigado!&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>braziliandevs</category>
      <category>testing</category>
    </item>
    <item>
      <title>Design Pattern - Strategy</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Wed, 28 Apr 2021 11:36:38 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/design-pattern-strategy-111n</link>
      <guid>https://dev.to/marcosbelorio/design-pattern-strategy-111n</guid>
      <description>&lt;p&gt;Vamos falar hoje de um pattern bem interessante quando trabalhamos com programação orientada a objetos, que pode ser aplicado em muitos casos do nosso dia a dia. Durante esse artigo vamos conhecer a definição do pattern, ver um exemplo de código que frequentemente nos deparamos no dia a dia e como podemos melhorá-lo aplicando o pattern.&lt;/p&gt;

&lt;p&gt;Os exemplos desse artigo serão em C# porém o pattern é facilmente aplicado em outras linguagens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definição
&lt;/h2&gt;

&lt;p&gt;Segundo Erich Gamma em seu livro sobre Design Patterns, a definição para o pattern strategy é:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Definir uma família de algoritmos, encapsular cada uma delas e torná-las intercambiáveis. Strategy permite que o algoritmo varie independentemente dos clientes que o utilizam.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Implementando um exemplo para pagamentos
&lt;/h2&gt;

&lt;p&gt;No nosso exemplo iremos criar um código para efetuar pagamento, seja ele por cartão de crédito, débito e outras modalidades. Para isso então vamos criar suas interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPagamentoCartaoCreditoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPagamentoCartaoDebitoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Criamos uma interface para cada forma de pagamento que possui declarado o método EfetuarPagamento.&lt;/p&gt;

&lt;p&gt;Vamos agora implementar as classes concretas das interfaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagamentoCartaoCreditoService&lt;/span&gt; 
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPagamentoCartaoCreditoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;$"Pagamento efetuado com o cartão de crédito no valor de R$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagamentoCartaoDebitoService&lt;/span&gt; 
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPagamentoCartaoDebitoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;$"Pagamento efetuado com o cartão de débito no valor de R$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E por fim vamos implementar nossa regra de pagamento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagamentoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IPagamentoCartaoCreditoService&lt;/span&gt; &lt;span class="n"&gt;_cartaoCreditoService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IPagamentoCartaoDebitoService&lt;/span&gt; &lt;span class="n"&gt;_cartaoDebitoService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PagamentoService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IPagamentoCartaoCreditoService&lt;/span&gt; &lt;span class="n"&gt;cartaoCreditoService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;IPagamentoCartaoDebitoService&lt;/span&gt; &lt;span class="n"&gt;cartaoDebitoService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_cartaoCreditoService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cartaoCreditoService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_cartaoDebitoService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cartaoDebitoService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CartaoCredito&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_cartaoCreditoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CartaoDebito&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_cartaoDebitoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Forma de pagamento não encontrada."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementamos um método para efetuar o pagamento e dependendo do valor passado pelo enum ele efetua o pagamento por cartão de crédito ou por cartão de débito. Acredito que você já tenha visto um código similar a esse, note que não tem nada de errado nesse código, mas agora vamos ver o que precisamos para implementar uma nova forma de pagamento.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implementar a nova forma de pagamento (interface e classe concreta)&lt;/li&gt;
&lt;li&gt;Modificar o construtor da classe PagamentoService passando a interface da nova forma de pagamento.&lt;/li&gt;
&lt;li&gt;Criar uma nova condição if para poder ser utilizado essa nova forma de pagamento.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Se atualizarmos esse código com dez novas formas de pagamento (o que não é difícil hoje em dia com tantas opções de pagamento hehehe) teremos um código cada vez maior, complexo e aberto constantemente a modificações (o que vai contra a letra 'O' dos princípios do SOLID).&lt;/p&gt;

&lt;p&gt;Então vamos aplicar algumas melhorias nesse código com o nosso pattern strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementando o pattern strategy
&lt;/h2&gt;

&lt;p&gt;Vamos começar criando apenas uma interface de pagamento de forma genérica.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPagamentoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que agora definimos o enum dentro da interface também. As classes concretas são implementadas à partir desta interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagamentoCartaoCreditoService&lt;/span&gt; 
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPagamentoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt; 
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CartaoCredito&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;$"Pagamento efetuado com o cartão de crédito no valor de R$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagamentoCartaoDebitoService&lt;/span&gt; 
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPagamentoService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt; 
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CartaoDebito&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;$"Pagamento efetuado com o cartão de débito no valor de R$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora vem a parte mais interessante que é a implementação do pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagamentoStrategyService&lt;/span&gt; 
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPagamentoStrategyService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPagamentoService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PagamentoStrategyService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPagamentoService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_services&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FormaPagamentoEnum&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EfetuarPagamento&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; 
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formaPagamento&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como temos duas classes que implementam a mesma interface &lt;code&gt;IPagamentoService&lt;/code&gt;, recebemos no construtor um IEnumerable contendo as duas implementações. No método de efetuar pagamento criamos uma expressão lambda filtrando qual implementação da interface &lt;code&gt;IPagamentoService&lt;/code&gt; iremos utilizar à partir do valor do enum.&lt;/p&gt;

&lt;p&gt;Muito simples não? Você não vai mais precisar de vários &lt;code&gt;if else&lt;/code&gt;, a classe estará pronta para receber quantas formas de pagamento forem necessárias sem precisar modificá-la. Toda vez que precisarmos implementar uma nova forma de pagamento o único passo será:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implementar a nova forma de pagamento (classe concreta utilizando a interface &lt;code&gt;IPagamentoService&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Projeto de exemplo
&lt;/h2&gt;

&lt;p&gt;Caso tenha ficado ainda alguma dúvida no código, você pode ver o exemplo que eu criei nesse &lt;a href="https://github.com/marcosbelorio/strategy-pattern-example" rel="noopener noreferrer"&gt;repositório do Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se gostou utilize os botões do lado esquerdo para que eu possa saber. Caso tenha alguma dúvida, sugestão ou crítica, deixe um comentário logo abaixo.&lt;/p&gt;

&lt;p&gt;Muito obrigado!&lt;/p&gt;

&lt;p&gt;Referências:&lt;br&gt;
&lt;a href="https://dev.to/kylegalbraith/what-you-need-to-know-about-the-helpful-strategy-pattern-34pm"&gt;What You Need To Know About The Helpful Strategy Pattern&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/WestDiscGolf/StrategyPatternExample" rel="noopener noreferrer"&gt;WestDiscGolf/StrategyPatternExample&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>braziliandevs</category>
      <category>pattern</category>
    </item>
    <item>
      <title>Resiliência em aplicações .Net com Polly</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Mon, 12 Apr 2021 15:41:52 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/resiliencia-em-aplicacoes-net-com-polly-40f2</link>
      <guid>https://dev.to/marcosbelorio/resiliencia-em-aplicacoes-net-com-polly-40f2</guid>
      <description>&lt;p&gt;Neste artigo vou abordar o uso da lib Polly para criarmos políticas de retry e circuit breaker em requisições http dentro de nossa aplicação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problema a ser solucionado
&lt;/h2&gt;

&lt;p&gt;Frequentemente precisamos lidar com requisições http dentro de nossas aplicações para consumir dados fornecidos por aplicações externas, as famosas requisições para apis, nesse contexto a lib Polly ajuda a criar comportamentos através da criação de políticas que tornam a nossa aplicação mais resiliente a possíveis falhas dessas requisições.&lt;/p&gt;

&lt;h2&gt;
  
  
  Política de retry
&lt;/h2&gt;

&lt;p&gt;Essa política serve para lidarmos principalmente com indisponibilidades momentâneas, vamos imaginar que realizamos uma requisição a uma api e por algum motivo ela está sendo muito requisitada e está apresentando lentidões para responder, nesse cenário estamos propícios a talvez receber um erro 408 de timeout da api, mas esse cenário pode ser momentâneo, talvez tentando mais uma vez ou depois de algum tempo, pode ser que a api esteja respondendo normalmente. Nesse cenário a política de retry se encaixa muito bem, podemos definir uma quantidade de tentativas em um espaço de tempo para que seja possível obter um retorno de sucesso da requisição.&lt;/p&gt;

&lt;h2&gt;
  
  
  Política de circuit breaker
&lt;/h2&gt;

&lt;p&gt;Você já deve ter utilizado algum aplicativo que estava apresentando lentidões para carregar os dados e você efetuou o comando de atualizar os dados (geralmente é o movimento de arrastar para baixo) e o aplicativo respondeu instantaneamente que não foi possível atualizar. Provavelmente o aplicativo estava com a política de circuit breaker ativada. Essa política auxilia em evitar tentativas desnecessárias, para que não seja sobrecarregado ainda mais uma aplicação já sobrecarregada. O desenvolvedor define uma quantidade limite de erros em sequência para ativar o circuit breaker, uma vez ativado, ele fica com o circuito aberto e não realiza novas requisições até que o circuito seja fechado novamente, esse tempo em que o circuito fica aberto é também configurado na política. &lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstração
&lt;/h2&gt;

&lt;p&gt;O exemplo que eu irei mostrar a seguir também está publicado no &lt;a href="https://github.com/marcosbelorio/polly-example" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Vamos criar um novo projeto web api e criar uma controller com um endpoint para podermos realizar os nossos testes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;HttpClientPollyExample.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HttpBinController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IHttpBinService&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HttpBinController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IHttpBinService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{code:int}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromRoute&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos agora criar a classe service e sua interface que está sendo passada via injeção de dependência no construtor da controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;HttpClientPollyExample.Interfaces&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IHttpBinService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;HttpClientPollyExample.Services&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HttpBinService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IHttpBinService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;_httpClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HttpBinService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_httpClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_httpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"http://httpbin.org/status/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como podemos ver no código da classe service, estamos fazendo uma requisição http para a api &lt;strong&gt;httpbin&lt;/strong&gt; (uma ótima api disponível para realizar testes) e passando o parâmetro code na rota, esse endpoint irá forçar o status code do retorno conforme o code que passarmos na rota, exemplo, se passarmos o valor 200 o endpoint irá retornar status code 200, se passarmos 500, irá retornar status code 500. Isso irá nos ajudar a simular os casos de uso das políticas do polly.&lt;/p&gt;

&lt;p&gt;Agora vem a parte mais importante, iremos configurar o Polly em nossa aplicação. Primeiro vamos adicionar os pacotes necessários.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Polly&lt;/span&gt;
&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Polly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;
&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Polly&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos agora criar as duas configurações das políticas de retry e circuit breaker. Por ser apenas uma demo eu adicionei na Startup.cs pois será lá que iremos utilizá-las.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IAsyncPolicy&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetRetryPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;retryCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpPolicyExtensions&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleTransientHttpError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitAndRetryAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retryCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retryAttempt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retryAttempt&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IAsyncPolicy&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetCircuitBreakerPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;exceptionsAllowedBeforeBreaking&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;durationOfBreakInSeconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpPolicyExtensions&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleTransientHttpError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CircuitBreakerAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exceptionsAllowedBeforeBreaking&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;durationOfBreakInSeconds&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos analisar as configurações, as duas políticas foram setadas com o handler &lt;code&gt;HandleTransientHttpError()&lt;/code&gt;, se lermos a descrição dele vamos ver que a configuração irá valer para os seguintes erros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Falhas de rede (System.Net.Http.HttpRequestException)&lt;/li&gt;
&lt;li&gt;HTTP 5XX status codes (server errors)&lt;/li&gt;
&lt;li&gt;HTTP 408 status code (request timeout)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Na política de retry passamos a quantidade de tentativas que serão realizadas e o intervalo de tempo entre elas, para isso setamos o valor &lt;code&gt;TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))&lt;/code&gt; que irá dobrar o tempo entre cada tentativa começando por 2 segundos.&lt;/p&gt;

&lt;p&gt;Na política de circuit breaker passamos a quantidade de exceções em sequência que serão aceitas antes de ativar o circuit breaker e o tempo que o circuito ficará aberto caso ele tenha sido ativado.&lt;/p&gt;

&lt;p&gt;Por último vamos aplicar as duas políticas a nossa service que criamos utilizando AddHttpClient() e a extensão AddPolicyHandler().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHttpClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IHttpBinService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HttpBinService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicyHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GetRetryPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retryCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicyHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GetCircuitBreakerPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exceptionsAllowedBeforeBreaking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;durationOfBreakInSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setamos para a política de retry 3 tentativas e para a política de circuit breaker 5 erros em sequência para ativá-lo e 30 segundos para o circuito fechar após aberto, vamos testar agora.&lt;/p&gt;

&lt;p&gt;Execute a aplicação e chame o endpoint passando o valor 500 para o parâmetro code &lt;code&gt;[GET]http://localhost:5000/httpbin/500&lt;/code&gt; e veja o resultado no console.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8otv5hl4smm24z3u96x.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8otv5hl4smm24z3u96x.PNG" alt="Alt Text" width="639" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O endpoint da api httpbin está retornando erro status code 500 e por isso foi tentado mais três vezes, conforme destacado na print, com isso conseguimos testar nossa política de retry.&lt;/p&gt;

&lt;p&gt;Agora execute mais uma vez o endpoint passando o code 500 e veja o resultado novamente no console.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3n8r10vs50joh5bx4j9q.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3n8r10vs50joh5bx4j9q.PNG" alt="Alt Text" width="800" height="119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como já tínhamos recebidos 4 erros em sequência no teste anterior, executamos a quinta requisição com erro e o circuit breaker foi ativado retornando uma exceção para a sexta chamada. Você pode tratar a exceção &lt;code&gt;Polly.CircuitBreaker.BrokenCircuitException&lt;/code&gt; para ter um comportamento mais amigável na aplicação.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>polly</category>
      <category>dotnetcore</category>
    </item>
    <item>
      <title>Conhecendo o Azure Functions</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Thu, 01 Apr 2021 19:52:32 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/conhecendo-o-azure-functions-2756</link>
      <guid>https://dev.to/marcosbelorio/conhecendo-o-azure-functions-2756</guid>
      <description>&lt;p&gt;Nesse artigo vamos conhecer o Azure Functions, o serviço de computação em nuvem &lt;strong&gt;serverless&lt;/strong&gt; da Azure. Além de explicar o que é o Azure Functions, vamos ver suas vantagens e desvantagens, suas diferentes formas de executar e exemplos de como implementar. Mais artigos sobre o assunto serão postados em breve por possuir bastante recursos para explorarmos.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é Azure Functions?
&lt;/h2&gt;

&lt;p&gt;Azure Functions é um serviço computacional capaz de executar pedaços de código sem a necessidade de construir uma infraestrutura para isso, por isso é chamado de &lt;strong&gt;serverless&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As Azure Functions são disparadas/executadas a partir de um evento, os principais eventos utilizados são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Request&lt;/strong&gt; - Executado quando requisitado via http (igual uma api).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timer&lt;/strong&gt; - Executado de tempos em tempos ou em uma data específica.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Bus&lt;/strong&gt; - Executado quando uma nova mensagem chega na fila ou tópico. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Existem outros eventos que podem disparar uma Azure Function e a cada atualização é adicionado novos triggers, você pode checar todos os triggers disponíveis &lt;a href="https://docs.microsoft.com/pt-br/azure/azure-functions/functions-triggers-bindings?tabs=csharp#supported-bindings" rel="noopener noreferrer"&gt;clicando aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vantagens e desvantagens
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Principais vantagens ao utilizar Azure Functions:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sem infraestrutura para dar manutenção&lt;/strong&gt; - Por possuir a infraestrutura totalmente abstraída dentro do serviço, não é necessário se preocupar em administrar ou dar manutenção na infraestrutura, tudo isso é feito pela Azure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Não é cobrado quando não executado&lt;/strong&gt; - No plano de consumo as funções são cobradas por execuções realizadas, então mesmo o serviço estando disponível 24 horas por dia, você não é cobrado pela disponibilidade do serviço, diferente de uma VM ou o App Service. Isto não se aplica no plano "App Service Plan".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalável automaticamente&lt;/strong&gt; - o serviço auto gerencia as execuções das funções e sempre garante disponibilidade escalando automaticamente recursos caso necessário, tudo isso invisível para nós.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redução da complexidade do sistema&lt;/strong&gt; - Com uma plataforma serverless podemos escrever e executar trechos de código sem se preocupar com complexidades de implantação como sistema operacional, hardware ou servidores. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Principais desvantagens:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ficar preso ao fornecedor&lt;/strong&gt; - Desenvolver uma aplicação utilizando Azure Functions acaba te prendendo ao fornecedor, neste caso a Azure, isso pode dificultar uma possível mudança de plataforma.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dificuldade em debugar&lt;/strong&gt; - É possível debugar as Azure Functions, mas nem sempre é uma tarefa simples recriar o cenário desejado, principalmente quando o número de funções é muito grande.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bindings de entrada e saída
&lt;/h2&gt;

&lt;p&gt;Uma das facilidades em utilizar o Azure Functions são os bindings de entrada e saída. Você pode criar uma função onde ela se comunica com recursos externos de uma forma automática e transparente, sem você se preocupar em codificar para isso. Os bindings podem te ajudar tanto a receber um dado de algum recurso como também enviar um dado para algum recurso.&lt;/p&gt;

&lt;p&gt;Vamos ver o exemplo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;HttpTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"content/settings.json"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos ver que usamos um &lt;strong&gt;HttpTrigger&lt;/strong&gt; que além de ser nossa trigger que irá disparar a função ela também recebe os dados da requisição http na variável request, e do lado temos um binding do tipo &lt;strong&gt;Blob&lt;/strong&gt; onde recebe na variável json o conteúdo do arquivo settings.json que está armazenado em um serviço de Blob Storage na Azure. Você pode checar todas as possibilidades de binding &lt;a href="https://docs.microsoft.com/pt-br/azure/azure-functions/functions-triggers-bindings?tabs=csharp#supported-bindings" rel="noopener noreferrer"&gt;clicando aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Vamos fazer um exemplo para vermos na prática o uso de trigger e os bindings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstração
&lt;/h2&gt;

&lt;p&gt;O Azure Functions permite que você escreva seu código em diversas linguagens como C#, Javascript e Python, esse exemplo será usando C#. Para o nosso exemplo iremos utilizar o Azure Storage Table, um banco NoSQL bem simples e barato da Azure.&lt;/p&gt;

&lt;p&gt;Então vamos começar logando no portal da Azure (&lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;https://portal.azure.com/&lt;/a&gt;) e vamos criar uma nova &lt;strong&gt;storage account&lt;/strong&gt; para conseguirmos utilizar o banco Azure Storage Table.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mnr2vzs1w53arop0xm3.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mnr2vzs1w53arop0xm3.PNG" alt="Criando uma nova storage account" width="800" height="895"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após o portal terminar de criar o recurso, vamos entrar na storage account e clicar em &lt;strong&gt;access keys&lt;/strong&gt; no menu lateral e copiar a connectionstring do recurso (pode ser qualquer uma das duas).&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgeyq1n8not33b5y490cm.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgeyq1n8not33b5y490cm.PNG" alt="Acessando access keys" width="266" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora vamos pro Visual Studio e criar um novo projeto escolhendo Azure Functions.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3frq99ox7lx9kvo8y31.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3frq99ox7lx9kvo8y31.PNG" alt="Novo projeto azure functions" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos criar uma nova função utilizando a trigger Http trigger.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22uuf4cx0puj7qzwh0go.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22uuf4cx0puj7qzwh0go.PNG" alt="Escolhendo uma function http trigger" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Projeto criado, vamos adicionar o pacote nuget via Visual Studio ou comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Azure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebJobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Storage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com este pacote conseguiremos usar a nossa storage account na Azure.&lt;/p&gt;

&lt;p&gt;Próximo passo é setarmos a connectionstring da storage account, para isso edite o arquivo local.settings.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"AzureWebJobsStorage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;sua-connectionstring&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"FUNCTIONS_WORKER_RUNTIME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dotnet"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto, agora o projeto está preparado para fazermos nossa Azure Function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Azure.WebJobs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;AzureFunctionsExemplo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FunctionUsuarioSalvar&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UsuarioSalvar"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Usuario"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Usuario&lt;/span&gt; &lt;span class="nf"&gt;UsuarioSalvar&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;HttpTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="kt"&gt;dynamic&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Usuario&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;RowKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;Login&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Login&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Usuario&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;PartitionKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;RowKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Login&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;    
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto, com apenas esse código fizemos uma function que recebe dados à partir de uma requisição http e salva o mesmo em um banco NoSql, não precisa ser feito mais nada. Apesar de ser só um exemplo de demonstração, podemos ver como é muito simples trabalharmos com as Azure Functions. Vamos analisar o código:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[FunctionName("UsuarioSalvar")]&lt;/code&gt; - Com esse annotation declaramos o nome da função que será usado pelo Azure.&lt;br&gt;
&lt;code&gt;[return: Table("Usuario")]&lt;/code&gt; - Esse annotation é um binding de saída de dados, estamos utilizando o binding do Azure Storage Table e dizendo que iremos salvar na tabela Usuario.&lt;br&gt;
&lt;code&gt;public Usuario UsuarioSalvar([HttpTrigger("POST")] dynamic request)&lt;/code&gt; - Note que aqui estamos retornando a classe Usuario o que irá ser feito o binding de saída e também temos declarado a nossa trigger HttpTrigger com o verbo POST recebendo um objeto dynamic.&lt;br&gt;
E por fim retornarmos o objeto Usuario contendo o Login que foi passado via requisição http e as duas propriedades obrigatórias do Azure Storage Table que são o PartitionKey e o RowKey. A PartitionKey serve para criarmos separações entre os documentos presentes na tabela e o RowKey é um identificador único para cada documento.&lt;/p&gt;

&lt;p&gt;Execute a aplicação e veja que no console foi disponibilizado um endpoint devido termos usado uma function http trigger, agora é só utilizar o endpoint que iremos ver a requisição sendo salva no banco. No caso aqui eu uso o aplicativo Postman para fazer a chamada do endpoint e o aplicativo Microsoft Azure Storage Explorer para visualizar os dados no banco.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkprd8fsqwp9j8rt63wm.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkprd8fsqwp9j8rt63wm.PNG" alt="Dado persistido no banco" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sua function agora está pronta para ser publicada na Azure. Após terminar os testes não se esqueça de excluir o Resource Group utilizado no portal da Azure.&lt;/p&gt;

&lt;p&gt;Referência:&lt;br&gt;
&lt;a href="https://www.techrepublic.com/article/serverless-computing-pros-and-cons-5-benefits-and-3-drawbacks/" rel="noopener noreferrer"&gt;Serverless computing pros and cons: 5 benefits and 3 drawbacks&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>azure</category>
      <category>azurefunctions</category>
    </item>
    <item>
      <title>Cancelando Tasks assíncronas em C#</title>
      <dc:creator>Marcos Belorio</dc:creator>
      <pubDate>Fri, 12 Mar 2021 13:33:37 +0000</pubDate>
      <link>https://dev.to/marcosbelorio/cancelando-tasks-assincronas-em-c-12ba</link>
      <guid>https://dev.to/marcosbelorio/cancelando-tasks-assincronas-em-c-12ba</guid>
      <description>&lt;p&gt;Uma das boas práticas ao trabalhar com Tasks assíncronas em C# é utilizar o &lt;strong&gt;CancellationToken&lt;/strong&gt;, possibilitando que a execução pare quando solicitada.&lt;/p&gt;

&lt;p&gt;Se você ainda não está familiarizado com o uso de Tasks Assíncronas e as palavras chaves async e await, recomendo ler este outro post antes:&lt;br&gt;
&lt;a href="https://dev.to/marcosbelorio/trabalhando-com-tasks-assincronas-em-c-pjp"&gt;Trabalhando com Tasks assíncronas em C#&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Executando requisições sem a possibilidade de cancelamento
&lt;/h2&gt;

&lt;p&gt;Vamos criar um exemplo mostrando como é a execução de uma requisição sem a possibilidade de cancelamento, para isso iremos criar o seguinte endpoint em uma aplicação web api:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Iniciando"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//simulando um processamento de 10 segundos&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Finalizando após 10 segundos"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Finalizado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executando no navegador esse endpoint e aguardando o retorno com a mensagem "Finalizado", podemos ver o console da aplicação desse jeito:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Iniciando
Finalizando após 10 segundos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora execute novamente no navegador o endpoint, mas antes da requisição terminar aperte f5 (atualizar) duas vezes, o console irá ficar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Iniciando
Iniciando
Iniciando
Finalizando após 10 segundos
Finalizando após 10 segundos
Finalizando após 10 segundos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Concluímos que mesmo atualizando a página no navegador, todas as requisições foram totalmente processadas, mesmo as que não tiveram tempo de retornar no navegador o response por ter sido atualizado antes. Esse comportamento pode ser esperado caso a requisição efetue alguma persistência em banco por exemplo, mas também pode ser um desperdício de processamento caso a requisição não mude nenhum estado da aplicação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usando o CancellationToken
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CancellationToken&lt;/strong&gt; é um objeto leve capaz de notificar caso a requisição tenha sido cancelada. Passar um CancellationToken como parâmetro para um método que retorne uma Task é uma boa prática, dando a possibilidade para o chamador do método desistir do resultado.&lt;/p&gt;

&lt;p&gt;Vamos refazer o exemplo acima utilizando o CancellationToken:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Iniciando"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//simulando um processamento de 10 segundos&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Finalizando após 10 segundos"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Finalizado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note que foi passado um CancellationToken como parâmetro para o método Task.Delay(). Agora execute novamente no navegador o endpoint, e atualize a página antes da requisição terminar, o console irá ficar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Iniciando
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.Threading.Tasks.TaskCanceledException: A task was canceled.    
//toda stack do erro
Iniciando
Finalizando após 10 segundos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diferente do outro exemplo onde a primeira requisição foi totalmente processada, dessa vez ela retornou uma exceção avisando que a Task foi cancelada e não chegou a ser totalmente processada.&lt;/p&gt;

&lt;p&gt;Caso seja necessário você pode tratar essa exceção, como por exemplo retornar um erro amigável, através das exceptions &lt;strong&gt;TaskCanceledException&lt;/strong&gt; ou &lt;strong&gt;OperationCanceledException&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manipulando CancellationToken em seu código
&lt;/h2&gt;

&lt;p&gt;Ao criar um método que retorne uma Task, você pode verificar o CancellationToken para impedir que a execução do código continue. Podemos fazer assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ThrowIfCancellationRequested&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//Algum comportamento aqui&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo acima o método retorna uma exceção caso a requisição tenha sido cancelada. &lt;br&gt;
Você também pode criar seu próprio comportamento quando a requisição for cancelada, ao invés de retornar uma exceção, veja o exemplo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsCancellationRequested&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//Algum comportamento aqui&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outra forma de se trabalhar com o CancellationToken é definir um timeout para ele ser cancelado, ou seja, se a execução passar do tempo definido no token, o token será cancelado. Vamos ver um exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Iniciando"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//Criando um CancellationTokenSource com timeout de 5 segundos&lt;/span&gt;
    &lt;span class="n"&gt;CancellationTokenSource&lt;/span&gt; &lt;span class="n"&gt;cts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;//simulando um processamento de 10 segundos&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Finalizando após 10 segundos"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Finalizado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos ver que criamos um CancellationToken onde será automaticamente cancelado após 5 segundos, como nosso código simula um processamento de 10 segundos, o método será cancelado antes de ser totalmente executado.&lt;/p&gt;

&lt;p&gt;Por último, caso você precise utilizar um método que obrigue você passar um CancellationToken mas por algum motivo você espera que aquele código &lt;strong&gt;sempre&lt;/strong&gt; seja executado independente se a requisição foi cancelada ou não, passe o token dessa forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;DoSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma você está passando um token vazio, então ele não terá nenhum comportamento.&lt;/p&gt;

&lt;p&gt;Referências:&lt;br&gt;
&lt;a href="https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/" rel="noopener noreferrer"&gt;Using CancellationTokens in ASP.NET Core MVC controllers&lt;/a&gt;&lt;br&gt;
&lt;a href="https://johnthiriet.com/cancel-asynchronous-operation-in-csharp/" rel="noopener noreferrer"&gt;Cancel asynchronous operations in C#&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>task</category>
    </item>
  </channel>
</rss>
