<?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: Mateus Vinícius</title>
    <description>The latest articles on DEV Community by Mateus Vinícius (@antiduhring).</description>
    <link>https://dev.to/antiduhring</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%2F865368%2F0f005741-9b8d-452b-9552-70904ba2eccd.jpeg</url>
      <title>DEV Community: Mateus Vinícius</title>
      <link>https://dev.to/antiduhring</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/antiduhring"/>
    <language>en</language>
    <item>
      <title>Ponteiros, stack e heap em Go</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Sun, 03 Mar 2024 21:20:56 +0000</pubDate>
      <link>https://dev.to/antiduhring/ponteiros-stack-e-heap-em-go-46fl</link>
      <guid>https://dev.to/antiduhring/ponteiros-stack-e-heap-em-go-46fl</guid>
      <description>&lt;h2&gt;
  
  
  Pointers
&lt;/h2&gt;

&lt;p&gt;Ponteiros são variáveis cujo valor é um endereço na memória, e esse endereço pode conter qualquer tipo de valor - uma string, um int, uma struct e etc.&lt;/p&gt;

&lt;p&gt;A sintaxe básica de ponteiros em Go é relativamente simples, mas iremos entrar nos detalhes ao decorrer do texto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// declarando uma variável do tipo int&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; 

&lt;span class="c"&gt;// exibindo na tela o endereço na memória da variável "foo"&lt;/span&gt;
&lt;span class="c"&gt;// O resultado será algo como: 0xc000110010&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="c"&gt;// declarando uma variável do tipo ponteiro&lt;/span&gt;
&lt;span class="c"&gt;// cujo endereço apontado é um variável do tipo int.&lt;/span&gt;
&lt;span class="c"&gt;// estamos apontando para o endereço da variável foo&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;

&lt;span class="c"&gt;// exibindo na tela o valor da variável "bar", que é um endereço na memória. &lt;/span&gt;
&lt;span class="c"&gt;// o resultado será o mesmo do Println anterior&lt;/span&gt;
&lt;span class="c"&gt;// já que ambos apontam para o mesmo endereço na memória&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="c"&gt;// exibindo na tela o valor original contido no endereço&lt;/span&gt;
&lt;span class="c"&gt;// Resultado: 3&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Primeiro é importante diferenciar os diferentes usos do operador *, também conhecido como &lt;em&gt;star operator&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Star operator&lt;/em&gt; num tipo é chamado de &lt;em&gt;pointer type&lt;/em&gt;, e indica que aquela variável é o ponteiro para algo - como int, string etc -, esse algo é chamado de base. Por exemplo, o código abaixo indica que a variável baz é um pointer type de base string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Matt"&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já se o uso do &lt;em&gt;star operator&lt;/em&gt; seguido de uma variável é uma forma de obter o valor original do endereço na memória que o ponteiro está salvando. Chamamos isso de &lt;em&gt;dereferencing&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Matt"&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Resultado: "Matt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apesar da sintaxe simples, o uso apropriado de ponteiros no Go pode se tornar complexo devido ao fato de não ser sempre claro qual será o comportamento do compilador na alocação de memória. Basicamente um ponteiro pode ser salvo na stack ou  no heap, e a escolha de um ou outro é muitas vezes implícita.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;p&gt;Stack - ou pilha - é uma estrutura de dado que salva cada bloco de código que é executado numa goroutine, de forma isolada e ordenada, e cada bloco é chamado de frame. Exemplo, no código abaixo temos uma função &lt;em&gt;main&lt;/em&gt;, que chama uma função &lt;em&gt;greetings&lt;/em&gt;, que chama a função &lt;em&gt;fmt.Println&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Matt"&lt;/span&gt;
    &lt;span class="n"&gt;greetings&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Executando o código, esse seria o comportamento da stack:&lt;br&gt;
&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zchfpnp3v09fhciysxhg.png"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzchfpnp3v09fhciysxhg.png" alt="Stack" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após a execução do frame terminar, a stack automaticamente se limpa sozinha, jogando fora toda a memória alocada em cada frame e finalizando nosso programa.&lt;br&gt;
&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rantyl6y8rn9m960sm4x.png"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frantyl6y8rn9m960sm4x.png" alt="Stack" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Normalmente frames não podem acessar endereços na memória de fora dele, então se um ponteiro for criado num frame e apenas acessado nesse frame, aquela memória normalmente será alocada dentro da stack, no próprio frame, e será zerada no momento em que esse frame terminar a sua execução e for removido da stack. O mesmo vale caso o ponteiro seja criado num frame e passado pra baixo na execução dos frames filhos, por exemplo no código abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Matt"&lt;/span&gt;
    &lt;span class="n"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&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;A função &lt;em&gt;greetings&lt;/em&gt; recebe um ponteiro que aponta para o endereço na memória da variável &lt;em&gt;name&lt;/em&gt;, e essa variável está salva dentro do frame &lt;em&gt;main&lt;/em&gt;, que não será removido da stack até a função &lt;em&gt;greetings&lt;/em&gt; e &lt;em&gt;fmt.Println&lt;/em&gt; terminarem sua execução, então é seguro manter a variável salva lá.&lt;br&gt;
&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09czskrt7dmai5918mev.png"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09czskrt7dmai5918mev.png" alt="Stack" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Importante mencionar que, caso a variável passada não seja um ponteiro e sim uma string, por exemplo, o valor é copiado ao passar de um frame para o outro, pois, como dito anteriormente, frames normalmente não podem acessar memória de fora do seu próprio bloco de execução.&lt;/p&gt;

&lt;p&gt;Dado o comportamento de &lt;em&gt;self cleaning&lt;/em&gt;, ou seja, de remover da stack o frame assim que ele finaliza sua execução, a stack não precisa de ajuda do &lt;em&gt;garbage collector&lt;/em&gt;, o que melhora a performance do código.&lt;/p&gt;
&lt;h2&gt;
  
  
  Heap
&lt;/h2&gt;

&lt;p&gt;Mas existem situações em que não seria seguro manter a memória salva no próprio frame, pois ele pode ser acessado de fora mesmo após o frame ser removido da stack, o que causaria a perda do seu valor, retornando apenas &lt;em&gt;nil&lt;/em&gt;. Por exemplo, no trecho abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;createName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;greetings&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&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;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Matt"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&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;A função &lt;em&gt;createName&lt;/em&gt; cria o ponteiro que aponta para a variável name, mas ao finalizar sua execução a função greetings ainda precisa acessar esse valor. O comportamento da stack, nesse caso, seria esse:&lt;br&gt;
&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kddxt8as3ns5o8i18ylx.png"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkddxt8as3ns5o8i18ylx.png" alt="Stack" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas se o frame da função &lt;em&gt;createName&lt;/em&gt; foi removido da stack após sua execução, o que significa que toda a memória foi zerada, como a função &lt;em&gt;greetings&lt;/em&gt; ainda assim conseguiu acessá-lo? A resposta é que, nesse caso, a memória não foi alocada dentro do frame na stack, mas sim num lugar de fora, chamado &lt;em&gt;heap&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;O heap é o local que guarda essas memórias alocadas que precisam ser compartilhadas entre frames e até entre stacks, sem que sejam apagadas após a execução do frame que as criou. &lt;/p&gt;

&lt;p&gt;Dado esse comportamento pode parecer muito tentador usar apenas memória alocada no heap, mas, como não há o comportamento de self cleaning, o heap precisa de ajuda do garbage collector do Go, e isso têm um custo computacional, criando cada vez mais latência no programa.&lt;/p&gt;

&lt;p&gt;Mas nem sempre a alocação em memória do Go é tão previsível assim, por isso destaquei o "normalmente" ao descrever os comportamentos de alocação na stack e no heap, mas isso será melhor explorado num momento futuro. Por ora basta entender que cada tipo de alocação tem suas vantagens e desvantagens, e que usar ponteiros, apesar de parecer simples, pode trazer certa complexidade e custos por trás.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>memoryallocation</category>
      <category>go</category>
    </item>
    <item>
      <title>Channels por baixo dos panos</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Sat, 25 Nov 2023 19:31:20 +0000</pubDate>
      <link>https://dev.to/antiduhring/channels-por-baixo-dos-panos-5ddh</link>
      <guid>https://dev.to/antiduhring/channels-por-baixo-dos-panos-5ddh</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Channels&lt;/em&gt; são canais de comunicação e sincronização entre goroutines&lt;/strong&gt;. A comunicação é feita através do envio de dados entre &lt;em&gt;goroutines&lt;/em&gt; e a sincronização é feita pausando e retomando o processamento de uma &lt;em&gt;goroutine&lt;/em&gt; quando necessário.&lt;/p&gt;

&lt;p&gt;Podemos criar uma nova &lt;em&gt;channel&lt;/em&gt;, com o seguinte código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Task&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O tipo &lt;code&gt;chan Task&lt;/code&gt; significa que estamos &lt;strong&gt;criando uma channel que envia e recebe um dado de tipo &lt;em&gt;Task&lt;/em&gt;&lt;/strong&gt;, enquanto &lt;strong&gt;o parâmetro &lt;code&gt;3&lt;/code&gt; representa a quantidade de dados que a channel pode guardar ao mesmo tempo&lt;/strong&gt; na sua fila, iremos explorar o que isso significa muito em breve.&lt;/p&gt;

&lt;p&gt;Por debaixo dos panos &lt;strong&gt;o valor da variável &lt;code&gt;ch&lt;/code&gt; passa a ser um ponteiro para uma estrutura de dados chamada &lt;code&gt;hchan&lt;/code&gt;&lt;/strong&gt;, que é nada mais do que uma &lt;em&gt;struct&lt;/em&gt; com 4 propriedades principais: buffer, sendx, recvx e lock. Cada propriedade possui um papel fundamental no funcionamento das channels.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;&lt;em&gt;buffer&lt;/em&gt; é uma fila que guarda cópias dos dados enviados para a &lt;em&gt;channel&lt;/em&gt;&lt;/strong&gt;. Quando uma &lt;em&gt;goroutine&lt;/em&gt; envia um dado para uma &lt;em&gt;channel&lt;/em&gt;, o &lt;em&gt;buffer&lt;/em&gt; armazena e mantém um cópia desse dado - chamamos esse processo de &lt;strong&gt;&lt;em&gt;enqueue&lt;/em&gt;&lt;/strong&gt; - e, quando uma &lt;em&gt;goroutine&lt;/em&gt; recebe esse dado, ele é removido do &lt;em&gt;buffer&lt;/em&gt; e uma cópia fica com a &lt;em&gt;goroutine&lt;/em&gt; que o consome - esse processo chamamos de &lt;strong&gt;&lt;em&gt;dequeue&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Sendx&lt;/em&gt; representa o índice do dado sendo enviado para a fila&lt;/strong&gt;. No nosso exemplo acima de uma fila com 3 elementos, se uma &lt;em&gt;goroutine&lt;/em&gt; envia o primeiro dado para a &lt;em&gt;channel&lt;/em&gt; o &lt;em&gt;sendx&lt;/em&gt; passa a ser 1, se envia mais outro o &lt;em&gt;sendx&lt;/em&gt; passa a ser 2, se envia mais outro o &lt;em&gt;sendx&lt;/em&gt; passa a ser...0. Essa é a definição de uma fila circular, pois o último elemento se conecta ao primeiro. O valor do &lt;em&gt;sendx&lt;/em&gt; seria zero porque o próximo elemento depois do terceiro é o primeiro, portanto se a fila está cheia - já possui 3 elementos - e eventualmente o primeiro elemento da fila for removido, quando uma &lt;em&gt;goroutine&lt;/em&gt; enviar para a &lt;em&gt;channel&lt;/em&gt; um novo dado, ele ficará guardado no índice 1 - e ai o valor do &lt;em&gt;sendx&lt;/em&gt; volta a ser 1 - e assim sucessivamente, de forma circular.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Recvx&lt;/em&gt; funciona da mesma forma que a propriedade &lt;em&gt;sendx&lt;/em&gt;&lt;/strong&gt;, mas é referente ao índice do dado sendo recebido por uma &lt;em&gt;goroutine&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Lock&lt;/em&gt; consiste em um &lt;em&gt;&lt;a href="https://go.dev/tour/concurrency/9"&gt;mutex&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;, que é um tipo primitivo de dado usado para evitar &lt;em&gt;race condition&lt;/em&gt; - ou seja, evitar que diferentes threads manipulem o mesmo dado compartilhado, no caso a &lt;em&gt;channel&lt;/em&gt;, de foma simultânea, causando comportamentos inesperados ou corrupção de dados. Se duas &lt;em&gt;goroutines&lt;/em&gt; tentarem fazem operações simultâneas na mesma &lt;em&gt;channel&lt;/em&gt; apenas uma conseguirá o &lt;em&gt;lock&lt;/em&gt;, e a outra deverá aguardar o &lt;em&gt;unlock&lt;/em&gt; da primeira para realizar sua própria operação. &lt;/p&gt;

&lt;p&gt;Podemos visualizar o fluxo de funcionamento de uma &lt;em&gt;channel&lt;/em&gt; enquanto fila circular com o diagram criado por &lt;a href="https://medium.com/@akankshadokania"&gt;@akankshadokania&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JGbllD1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hdw7umbusuyxx46ijl8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JGbllD1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hdw7umbusuyxx46ijl8v.png" alt="Diagrama mostrando o funcionamento de uma channel" width="786" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um ponto importante que pode ser levantado é: Já que a fila circular possui um tamanho fixo de quantidade de elementos que podem ser salvos ao mesmo tempo, o que acontece se uma goroutine enviar mais um dado para a channel que já está cheia? &lt;/p&gt;

&lt;p&gt;Usando nossa &lt;em&gt;channel&lt;/em&gt; de 3 elementos como exemplo, imaginando que ele já possui 3 &lt;em&gt;Tasks&lt;/em&gt; no &lt;em&gt;buffer&lt;/em&gt;, o &lt;em&gt;sendx&lt;/em&gt; e &lt;em&gt;recvx&lt;/em&gt; seriam ambos 0 e o &lt;em&gt;runtime&lt;/em&gt; do Go, sabendo que o índice 0 do &lt;em&gt;buffer&lt;/em&gt; ainda está ocupado, &lt;strong&gt;bloquearia a execução da &lt;em&gt;goroutine&lt;/em&gt; que tentou enviar o dado para a &lt;em&gt;channel&lt;/em&gt;&lt;/strong&gt; e apenas desbloquearia quando o &lt;em&gt;recvx&lt;/em&gt; passasse a ser 1, ou seja, quando o primeiro elemento fosse removido da fila, assim permitindo o envio do dado para a &lt;em&gt;channel&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Portanto &lt;em&gt;channels&lt;/em&gt; são uma ferramenta poderosa por possuir essas características interessantes: &lt;strong&gt;São &lt;em&gt;goroutine-safe&lt;/em&gt;&lt;/strong&gt;, ou seja, possuem a capacidade de lidar com múltiplas &lt;em&gt;goroutines&lt;/em&gt; sem levar a problemas de &lt;em&gt;race condition&lt;/em&gt;; &lt;strong&gt;Possuem capacidade de salvar dados&lt;/strong&gt;, como vimos no ponto sobre a propriedade &lt;em&gt;buffer&lt;/em&gt;; Possui semântica &lt;strong&gt;&lt;em&gt;FIFO - First In First Out -&lt;/em&gt;,&lt;/strong&gt; ou seja, a fila do &lt;em&gt;buffer&lt;/em&gt; recebe e envia os dados em ordem; &lt;strong&gt;Podem enviar dados&lt;/strong&gt; entre &lt;em&gt;goroutines&lt;/em&gt; e &lt;strong&gt;podem bloquear/desbloquear&lt;/strong&gt; a execução de &lt;em&gt;goroutines&lt;/em&gt;, dependendo da situação.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>go</category>
      <category>computerscience</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Goroutines por baixo dos panos</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Sat, 11 Nov 2023 21:54:33 +0000</pubDate>
      <link>https://dev.to/antiduhring/goroutines-por-baixo-dos-panos-2ld1</link>
      <guid>https://dev.to/antiduhring/goroutines-por-baixo-dos-panos-2ld1</guid>
      <description>&lt;p&gt;&lt;em&gt;Goroutine&lt;/em&gt; é a implementa do Go de uma &lt;a href="https://en.wikipedia.org/wiki/Coroutine"&gt;&lt;em&gt;corrotina&lt;/em&gt;&lt;/a&gt;, que é uma solução que existe em diversas linguagens de programação e tem como objetivo &lt;strong&gt;criar concorrência gerenciando a execução de funções, de forma que cada função seja executada por uma thread&lt;/strong&gt; do sistema operacional.&lt;/p&gt;

&lt;p&gt;A primeira vista, esse conceito pode parecer similar a uma &lt;a href="https://en.wikipedia.org/wiki/Thread_pool"&gt;&lt;em&gt;thread pool&lt;/em&gt;&lt;/a&gt;, que é um &lt;em&gt;design pattern&lt;/em&gt; que consiste em múltiplas threads do sistema operacional e uma fila de processamento, e funciona basicamente da seguinte forma: o nosso programa envia para a fila execuções que devem ser processadas e deixa as threads do sistema operacional atuarem como &lt;em&gt;consumers&lt;/em&gt;, puxando esses itens da fila e os processando de forma concorrente. &lt;strong&gt;Pense numa thread pool como um &lt;em&gt;load balancer&lt;/em&gt; de threads&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Entretanto, &lt;em&gt;Goroutines&lt;/em&gt; são diferentes de uma thread pool, e os motivos ficarão claros ao longo do texto, mas podemos adicionar que, por exemplo, cada &lt;em&gt;goroutine&lt;/em&gt; não corresponde necessariamente a uma thread real do sistema operacional - inclusive duas &lt;em&gt;goroutines&lt;/em&gt; podem eventualmente ser processadas na mesma thread -, e não há um caminho direto entre o que precisa ser processado e está na fila e as threads que irão processar, todo esse percurso é mediado pela estratégia do &lt;em&gt;runtime&lt;/em&gt; do Go.&lt;/p&gt;

&lt;p&gt;Ao executarmos um programa que cria várias &lt;em&gt;goroutines&lt;/em&gt;, &lt;strong&gt;o &lt;em&gt;runtime&lt;/em&gt; do Go, através do seu &lt;a href="https://osmh.dev/posts/goroutines-under-the-hood"&gt;&lt;em&gt;scheduler&lt;/em&gt;&lt;/a&gt;, precisa gerenciar quando e em qual thread essas &lt;em&gt;goroutines&lt;/em&gt; vão ser processadas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imaginemos que, na nossa execução, temos 2 threads do sistema operacional, o &lt;em&gt;scheduler&lt;/em&gt; do Go então vai redirecionar nossas &lt;em&gt;goroutines&lt;/em&gt; para serem processadas em uma dessas threads. Num cenário de 4 &lt;em&gt;goroutines&lt;/em&gt; para serem processadas pelas 2 threads, o &lt;em&gt;scheduler&lt;/em&gt; redireciona a &lt;em&gt;goroutine&lt;/em&gt; A e B para ser processada pela thread 1, e a &lt;em&gt;goroutine&lt;/em&gt; C e D para ser processada pela thread 2.&lt;/p&gt;

&lt;p&gt;E ao contrário de uma thread pool o &lt;em&gt;scheduler&lt;/em&gt; do Go não é  passivo, ele pode decidir &lt;strong&gt;pausar a execução de uma função numa thread, caso haja um bloqueio, por exemplo, e redirecionar essa execução para outa thread&lt;/strong&gt;, enquanto as threads de uma pool apenas consomem e executam todo pedaço de programa chega na fila. Existe muito mais estratégia e coordenação em tempo de execução numa &lt;em&gt;goroutine&lt;/em&gt; do que existe numa thread pool crua.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Goroutine&lt;/em&gt; é uma ferramenta poderosíssima do Go porque &lt;strong&gt;permite a implementação de concorrência de forma rápida e leve&lt;/strong&gt;, porque conta com um &lt;em&gt;scheduler&lt;/em&gt; que gerencia, como um maestro, em qual thread e quando um pedaço do programa será executado, e pelo fato de cada &lt;em&gt;goroutine&lt;/em&gt; criada não necessariamente corresponder a criação de uma nova thread do sistema operacional, o que as torna muito menos custosa e mais fáceis de serem criadas, já que existem numa camada de permissão bem acima das threads do kernel.&lt;/p&gt;

</description>
      <category>go</category>
      <category>computerscience</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Não use funções puras com Go</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Sun, 22 Oct 2023 15:44:03 +0000</pubDate>
      <link>https://dev.to/antiduhring/nao-use-funcoes-puras-com-go-36j7</link>
      <guid>https://dev.to/antiduhring/nao-use-funcoes-puras-com-go-36j7</guid>
      <description>&lt;p&gt;Um mantra muito comum no mundo do desenvolvimento é que funções puras são sempre melhores, mas isso nem sempre é verdade, pelo menos não no ecossistema do Go, e esse é um padrão amplamente adotado pela comunidade.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é uma função pura?
&lt;/h2&gt;

&lt;p&gt;Uma função pura é aquela que segue princípios de determinismo e imutabilidade. Ela retorna o mesmo resultado para o mesmo conjunto de argumentos de entrada, sem depender de variáveis externas, tornando o comportamento previsível e fácil de entender. Além disso, não modifica o estado de variáveis ou objetos fora de seu escopo, que é o chamado &lt;em&gt;side effect&lt;/em&gt;, mas sim cria e retorna um novo valor com base em seus argumentos, evitando efeitos colaterais indesejados. &lt;/p&gt;

&lt;h2&gt;
  
  
  Qual o padrão usado no lugar das funções puras?
&lt;/h2&gt;

&lt;p&gt;Go te permite acessar ponteiros diretamente, assim como linguagens &lt;em&gt;low-level&lt;/em&gt; como C e C++, e se tornou um padrão da comunidade dar preferência a funções que recebem como argumento um &lt;em&gt;ponteiro&lt;/em&gt; (isto é, o endereço na memória) para algum valor, como uma &lt;em&gt;struct&lt;/em&gt;, e manipular esse valor diretamente dentro da função.&lt;/p&gt;

&lt;p&gt;Um exemplo desse padrão pode ser visto no &lt;a href="https://github.com/go-gorm/gorm"&gt;GORM&lt;/a&gt;, lib de ORM muito popular.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"gorm.io/gorm"&lt;/span&gt;
  &lt;span class="s"&gt;"gorm.io/driver/sqlite"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;
  &lt;span class="n"&gt;Code&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sqlite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.db"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to connect database"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Migrate the schema&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AutoMigrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

  &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"D42"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c"&gt;// Create&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Read&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;product&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="c"&gt;// find product with integer primary key&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"code = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"D42"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// find product with code D42&lt;/span&gt;

  &lt;span class="c"&gt;// Update - update product's price to 200&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Price"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c"&gt;// Update - update multiple fields&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"F42"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c"&gt;// non-zero fields&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Updates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&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="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;&lt;span class="s"&gt;"Price"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"F42"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c"&gt;// Delete - delete product&lt;/span&gt;
  &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;product&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A variável &lt;em&gt;product&lt;/em&gt; é uma struct cujo ponteiro é passado como argumento nas funções de update, create e etc, dessa forma, o retorno da operação já é preenchido dentro desse variável. No caso do create, por exemplo, a variável &lt;em&gt;product&lt;/em&gt; passaria a ter todas as propriedades do registro que foi criado (ex: um uuid gerado automaticamente pelo banco de dados). No caso do update, o valor da struct é modificado para corresponde aos novos valores da operação de atualização.&lt;/p&gt;

&lt;p&gt;O padrão do ecossistema do Go é reaproveitar variáveis declaradas no mesmo escopo, por isso a preferência no uso de ponteiros.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qual a vantagem de usar funções impuras em Go?
&lt;/h2&gt;

&lt;p&gt;Em suma, performance. Uma função pura retorna uma nova struct contendo as propriedades do registro de cada uma das operações, então o create criaria uma nova struct contendo os dados criados, o update criaria uma nova struct contendo os dados modificados e assim sucessivamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetUserBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&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;sendError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"missing id parameter"&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="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getUser&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;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sendError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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="n"&gt;sendSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"balance"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wallet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Balance&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;client&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wallet"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id = ?"&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&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 getUser é uma função pura que, dado um id e um client do banco, retorna sempre uma nova cópia da struct &lt;code&gt;schema.User{}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Se cada operações gera uma cópia de uma struct então nos encontramos em um cenário onde, durante um dado processamento, vão haver diversas cópias da mesma struct salvas na memória, mesmo que só precisemos de uma delas ao final da operação. Isso é um desperdício de memória e vai diretamente contra os objetivos do Go em ser uma linguagem performática, otimizada e com baixo consumo de RAM.&lt;/p&gt;

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

&lt;p&gt;Funções puras são extremamente úteis num cenário de paradigma funcional, elas são fáceis de testar e seu comportamento é previsível, mas toda solução possui &lt;em&gt;tradeoffs&lt;/em&gt; e, nesse caso, é sacrificado o consumo de memória. No ecossistema do Go, onde o baixo consumo de RAM é padrão, funções puras fazem pouco sentido e desperdiçam o potencial da linguagem que nos fornece tantas ferramentas para lidar com ponteiros.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>go</category>
      <category>functional</category>
    </item>
    <item>
      <title>Quando menos é mais - Escalando uma API em Golang</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Mon, 09 Oct 2023 20:25:26 +0000</pubDate>
      <link>https://dev.to/antiduhring/quando-menos-e-mais-escalando-uma-api-em-golang-3ph3</link>
      <guid>https://dev.to/antiduhring/quando-menos-e-mais-escalando-uma-api-em-golang-3ph3</guid>
      <description>&lt;p&gt;Resolvi fazer a minha implementação da &lt;a href="https://github.com/anti-duhring/rinha-de-backend-2023-q3"&gt;rinha de backend&lt;/a&gt; essa semana, e a experiência que tive foi bastante interessante e até contra-intuitiva em alguns pontos, nesse artigo pretendo listar exatamente as técnicas que aprendi para escalar minha aplicação. &lt;/p&gt;

&lt;p&gt;Fazendo um resumo breve, a Rinha de Backend foi uma competição criada pelo &lt;a class="mentioned-user" href="https://dev.to/zanfranceschi"&gt;@zanfranceschi&lt;/a&gt; onde cada participante sobe um serviço, com um limite máximo de 3GB de RAM e 1.5 CPUs, contendo no mínimo 4 elementos: 2 instâncias de uma API feita em qualquer linguagem, 1 nginx para baleancear a carga entre as APIs e um banco para persistência de dados em disco. Esse serviço precisa aguentar um teste de estresse com Gattling, cujo código do teste foi feito pelo próprio &lt;a class="mentioned-user" href="https://dev.to/zanfranceschi"&gt;@zanfranceschi&lt;/a&gt; em Scala.&lt;/p&gt;

&lt;p&gt;No final minha implementação conseguiu aguentar o teste de estresse de 58 mil requisições em 3min, dando a média de quase 281 requisições por segundo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QSW0LkJg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/do287o6oyer2jvhqd9ns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QSW0LkJg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/do287o6oyer2jvhqd9ns.png" alt="Gattling" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pra entender os requisitos da implementação basta acessar &lt;a href="https://github.com/zanfranceschi/rinha-de-backend-2023-q3"&gt;o repositório da Rinha&lt;/a&gt;.&lt;br&gt;
Para ver minha implementação basta acessar o &lt;a href="https://github.com/anti-duhring/goingcrazy"&gt;meu repositório&lt;/a&gt;. No meu caso, implementei a API em Golang e usei o banco postgres para persistência em disco.&lt;/p&gt;

&lt;p&gt;Aprendi muitas coisas importantes sobre escalabilidade com esse desafio, e aqui vou pontuar as que mais fizeram diferença no resultado final da performance da minha aplicação:&lt;/p&gt;

&lt;h2&gt;
  
  
  Índice em campo único
&lt;/h2&gt;

&lt;p&gt;Um dos pontos do stress test é fazer uma massiva busca por termos.&lt;br&gt;
Dado um termo, a API deverá retornar os 50 primeiros resultados de registros no banco (que são as pessoas), cujo termo esteja presente no campo "apelido", "nome" ou em algumas das "stacks", que representa um array de strings.&lt;/p&gt;

&lt;p&gt;Para facilitar a consulta, criei um campo no banco chamado de "search_index", esse campo, do tipo varchar, une todos os outros campos num único texto, assim a pesquisa pode ser direcionada unicamente para este campo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--orb78UON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/un8l6pdnrcbnmq534z3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--orb78UON--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/un8l6pdnrcbnmq534z3r.png" alt="Search index union field" width="454" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Além disso, adicionei um índice do tipo GiST nesse campo, o que aumentou drasticamente a performance das consultas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Channels e goroutines para processamento concorrente
&lt;/h2&gt;

&lt;p&gt;Channels são canais de comunicação entre threads no Golang, e isso é útil para delegar a tarefa de inserir no banco de dados para uma thread diferente daquela que está lidando com a requisição do Gattling, assim podemos responder à requisição mais rapidamente.&lt;/p&gt;

&lt;p&gt;Fiz com que a rota para criação de uma pessoa não inserisse no banco diretamente, mas sim enviasse para um channel, onde do outro lado há um worker recebendo esses dados numa goroutine. O worker recebe a pessoa da channel e insere num slice e, quando o slice atingir 1000 pessoas, o worker faz um batch insert no banco de dados.&lt;/p&gt;

&lt;p&gt;Num projeto em produção, onde eu deveria me preocupar com consistência dos dados, substituiria a channel por um sistema de filas como kafka ou rabbitMQ, ou até mesmo filas do Redis, para que os dados não fiquem em memória, mas não era necessidade para o desafio, então optei por sacrificar a consistência por ganho de performance.&lt;/p&gt;

&lt;p&gt;A vantagem foi que a inserção é feita em apenas uma operação, usando apenas uma conexão com o banco, e gerenciado por um worker que está rodando numa thread diferente da requisição dos usuários.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache
&lt;/h2&gt;

&lt;p&gt;Utilizei Redis para criar gerenciamento do cache de cada pessoa. Ao acessar a rota de criar pessoa a API, antes de enviar o recurso para o channel, salva o ID e o apelido no cache.&lt;/p&gt;

&lt;p&gt;Esse cache otimizou a consulta, já que o endpoint de consultar pessoa poderia buscar os dados direto no cache com o ID, mas também otimizou a criação, já que existe uma constraint que impede a pessoa de ser registrada caso o apelido já esteja em uso por outra pessoa. Então antes de enviar para o channel a API faz uma busca por apelido no cache, e, caso já esteja em uso, retorna imediatamente uma mensagem de erro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitação de conexão do nginx e postgres
&lt;/h2&gt;

&lt;p&gt;Essa foi a parte mais interessante, e esse é o tópico que dá nome ao artigo...&lt;br&gt;
A ganho mais significativo de performance que a minha implementação teve foi, sem dúvidas, quando DIMINUI DRASTICAMENTE a quantidade de conexões máximas, tanto do nginx quanto do postgres.&lt;/p&gt;

&lt;p&gt;Minha configuração inicial do nginx permitia até 2048 conexões simultâneas na minha instância, e a do postgres permitia até 300 conexões no máximo. O problema é que, dado um cenário de recursos limitados - 3GB de RAM e 1.5 CPUs -, o maior gargalo está no fluxo de entrada de novas requisições.&lt;/p&gt;

&lt;p&gt;Cada conexão com o postgres é um fork de um processo, e isso custa CPU, portanto, num cenário de escassez, a solução mais eficiente é limitar o número máximo de requisições simultâneas, assim o banco consegue gerenciar de forma mais eficiente as conexões existentes. Diminuí o número máximo de conexões de 300 pra 30, e com cada API tendo um pool máximo de 15, e isso já diminuiu o uso de CPU do postgres de 100% no pico para, no máximo, 50%. Foi uma mudança considerável.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GSEE7FEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo3yknhhv7vkzkzxrwzn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GSEE7FEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo3yknhhv7vkzkzxrwzn.png" alt="Postgres compose" width="682" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quanto ao nginx, diminuí o número de worker connections para 256, a ideia é que, como as requests virão de qualquer forma, o mais importante é controlar o fluxo de entrada para que conexões não sejam feitas em quantidades maiores do que o postgres e redis são capazes de lidar. Isso aumenta o tempo de espera do cliente para a conexão ser estabelecida, mas o mesmo tempo impede um overhelm da nossa aplicação e diminui o consumo de recursos de forma concorrente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gHbid7VD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ayzakvc1aimq67p71fup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gHbid7VD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ayzakvc1aimq67p71fup.png" alt="Nginx config" width="439" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No fim, a maior lição aprendida é que, no quesito escalabilidade, as vezes menos é mais. Simplificar a aplicação, abrir mão de processamentos desnecessários e limitar as conexões para garantir que a CPU dará conta do fluxo de entrada pode fazer mais diferença do que otimização com algoritmos, refatoração do código ou buscar o framework/linguagem perfeita.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>go</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Usando postgres como message broker</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Sun, 13 Aug 2023 19:23:52 +0000</pubDate>
      <link>https://dev.to/antiduhring/usando-postgres-como-message-broker-com-node-1lpi</link>
      <guid>https://dev.to/antiduhring/usando-postgres-como-message-broker-com-node-1lpi</guid>
      <description>&lt;p&gt;Em muitos cenários de desenvolvimento, a necessidade de um &lt;em&gt;message broker&lt;/em&gt; é inegável. No entanto, adotar soluções como &lt;strong&gt;Kafka&lt;/strong&gt; ou &lt;strong&gt;RabbitMQ&lt;/strong&gt; nem sempre é a opção mais viável ou desejável. Neste tutorial, vamos explorar uma abordagem alternativa e interessante: transformar uma tabela comum do &lt;strong&gt;Postgres&lt;/strong&gt; em um &lt;em&gt;message broker&lt;/em&gt; robusto, garantindo a integridade e consistência das mensagens processadas.&lt;/p&gt;

&lt;p&gt;O que é um &lt;em&gt;message broker&lt;/em&gt;? Trata-se de um sistema que gerencia e armazena uma fila de mensagens, sendo crucial para a comunicação assíncrona entre diferentes partes de um sistema. No nosso caso, o objetivo é criar um sistema onde diferentes sistemas e threads possam consumir mensagens da fila, assegurando que cada mensagem seja processada apenas uma vez, evitando corrupções ou duplicações indesejadas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparando o Terreno
&lt;/h2&gt;

&lt;p&gt;A ideia central é simples: um &lt;em&gt;producer&lt;/em&gt; envia ordens de pagamento para uma tabela que atua como fila, com status inicial "&lt;em&gt;PENDING&lt;/em&gt;". Em seguida, três clusters de uma aplicação Node executam cron jobs a cada 1 minuto, desempenhando o papel de &lt;em&gt;consumers&lt;/em&gt;. Cada job verifica as ordens de pagamento pendentes na tabela, processa o pagamento e atualiza o status para "&lt;em&gt;COMPLETED&lt;/em&gt;". O desafio é garantir que uma ordem seja processada apenas uma vez, mesmo com múltiplos consumidores operando simultaneamente.&lt;/p&gt;

&lt;p&gt;O objetivo deste artigo não é ensinar como criar uma aplicação com Node do zero, mas apenas mostrar como utilizar o &lt;strong&gt;Postgres&lt;/strong&gt; como &lt;em&gt;message broker&lt;/em&gt; numa API feita como Node, por isso iremos pular alguns passos de setup básico.&lt;/p&gt;

&lt;p&gt;Também, para fins didáticos, usaremos &lt;a href="https://docs.nestjs.com/" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt; como framework para a API, &lt;a href="https://github.com/Unitech/pm2" rel="noopener noreferrer"&gt;pm2&lt;/a&gt; para o gerenciamento dos clusters da aplicação e &lt;a href="https://docs.nestjs.com/recipes/prisma#set-up-prisma" rel="noopener noreferrer"&gt;prisma&lt;/a&gt; para modelagem e como camada de comunicação com nosso banco de dados.&lt;/p&gt;

&lt;p&gt;Você pode obter o projeto-base no repositório &lt;a href="https://github.com/anti-duhring/postgres-queue-broker" rel="noopener noreferrer"&gt;anti-duhring/postgres-queue-broker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Primeiro de tudo é necessário iniciar um novo projeto Nest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nest new postgres-queue-broker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após isso, iremos instalar os pacotes &lt;code&gt;pm2&lt;/code&gt;, &lt;code&gt;@nestjs/schedule&lt;/code&gt; para gerenciamento dos cron jobs e o &lt;code&gt;@prisma/client&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i pm2 @nestjs/schedule @prisma/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse será o schema da nossa tabela &lt;strong&gt;Order&lt;/strong&gt;, que conterá as ordens de pagamentos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Order {
  id        String    @id             @default(uuid())
  message   String
  status    String
  createdAt DateTime  @default(now()) @map("created_at")
  updatedAt DateTime  @updatedAt      @map("updated_at")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após isso, iremos criar um módulo para ser o nosso &lt;em&gt;Producer&lt;/em&gt;, ele será responsável por criar uma nova ordem de pagamentos e enviar para a nossa tabela &lt;strong&gt;Order&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nest g resource order
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;order.service.ts&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../prisma/prisma.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;orderStatus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../common/orderStatus.enum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PENDING&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;order&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;h2&gt;
  
  
  Trabalhando com Locks Inteligentes
&lt;/h2&gt;

&lt;p&gt;Para alcançar esse objetivo, iremos explorar as funcionalidades do &lt;strong&gt;Postgres&lt;/strong&gt;: as cláusulas &lt;a href="https://www.postgresql.org/docs/9.0/sql-select.html#SQL-FOR-UPDATE-SHARE" rel="noopener noreferrer"&gt;&lt;code&gt;FOR UPDATE&lt;/code&gt;&lt;/a&gt; e &lt;a href="https://www.postgresql.org/docs/current/sql-select.html" rel="noopener noreferrer"&gt;&lt;code&gt;SKIP LOCKED&lt;/code&gt;&lt;/a&gt;. O &lt;code&gt;FOR UPDATE&lt;/code&gt; bloqueia as linhas retornadas por uma consulta, garantindo que nenhuma outra transação possa modificá-las até que a transação atual seja concluída. Por sua vez, o &lt;code&gt;SKIP LOCKED&lt;/code&gt; permite que uma consulta ignore linhas que estejam bloqueadas, possibilitando o salto sobre linhas já bloqueadas por outros consumidores.&lt;/p&gt;

&lt;p&gt;Sabendo isto, iremos criar o módulo do nosso &lt;em&gt;consumer&lt;/em&gt;, que consistirá num &lt;em&gt;cron job&lt;/em&gt;_ que roda a cada 1min, obtendo as ordens de pagamento pendentes, processando e atualizando seu status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nest g resource consumer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;consumer.service.ts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../prisma/prisma.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;orderStatus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../common/orderStatus.enum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Cron&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/schedule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsumerService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PrismaService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getPendingOrders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pendingOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$queryRaw&lt;/span&gt;&lt;span class="s2"&gt;`
                select o.*
                from "Order" o 
                where o.status = 'PENDING'
                order by o.created_at asc 
                for update skip locked
        `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pendingOrders&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&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="nd"&gt;Cron&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0 * * * * *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;processOrders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pendingOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPendingOrders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;pendingOrders&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COMPLETED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Order &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; has been processed`&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;Esta consulta permite que cada &lt;em&gt;job consumer&lt;/em&gt; obtenha uma ordem de pagamento pendente e a bloqueie, impedindo que outros &lt;em&gt;jobs&lt;/em&gt; acessem a mesma ordem simultaneamente. Uma vez que a ordem é processada e o status é atualizado, ela é liberada para futuros consumidores.&lt;/p&gt;

&lt;p&gt;Importante mencionar que, num cenário real, é necessário ter cautela com a quantidade de itens carregados, por isso um &lt;code&gt;LIMIT&lt;/code&gt; para limitar a quantidade de itens obtidos por cada &lt;em&gt;job&lt;/em&gt; pode evitar gargalos e erros de &lt;em&gt;out of memory&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rodando nossa aplicação
&lt;/h2&gt;

&lt;p&gt;Por fim, basta realizar a build da aplicação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E executar os 3 clusters com o pm2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pm2 start dist/main.js -i 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É possível monitorar os logs dos clusters com seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pm2 logs main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma podemos ver que cada ordem de pagamento é processada por apenas um cluster:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fs3ar6pahiwmvdxa7lkl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fs3ar6pahiwmvdxa7lkl3.png" alt="Log mostrando que cada ordem de pagamento foi processada por um cluster diferente"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;O uso do &lt;strong&gt;Postgres&lt;/strong&gt; como um &lt;em&gt;message broker&lt;/em&gt; alternativo pode ser uma solução valiosa em cenários onde a complexidade do &lt;strong&gt;Kafka&lt;/strong&gt; ou do &lt;strong&gt;RabbitMQ&lt;/strong&gt; não é justificada. Aproveitar as funcionalidades nativas do &lt;strong&gt;Postgres&lt;/strong&gt;, como &lt;code&gt;FOR UPDATE&lt;/code&gt; e &lt;code&gt;SKIP LOCKED&lt;/code&gt;, possibilita a criação de um sistema robusto que garante a integridade e consistência das mensagens processadas.&lt;/p&gt;

&lt;p&gt;Ao explorar essa abordagem, você poderá aprimorar a comunicação assíncrona em seus sistemas, evitando problemas de duplicação e corrupção de mensagens. Dessa forma, o &lt;strong&gt;Postgres&lt;/strong&gt; se mostra não apenas como um excelente banco de dados, mas também como um aliado poderoso na construção de soluções de integração confiáveis. Experimente essa abordagem em seus projetos e desfrute dos benefícios de um &lt;em&gt;message broker&lt;/em&gt; sólido e eficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Para saber mais
&lt;/h2&gt;

&lt;p&gt;Esse artigo foi fortemente inspirado pela palestra do &lt;strong&gt;Rafael Ponte&lt;/strong&gt; no canal da &lt;strong&gt;ZUP&lt;/strong&gt;, fica aqui a recomendação para entender a implementação com mais detalhes:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=FF6Am0N6eq4&amp;amp;t=3275s" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=FF6Am0N6eq4&amp;amp;t=3275s&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>node</category>
      <category>mensageria</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Usando mensageria com Amazon SQS + Node</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Thu, 11 May 2023 13:22:42 +0000</pubDate>
      <link>https://dev.to/antiduhring/usando-mensageria-com-amazon-sqs-node-4n8b</link>
      <guid>https://dev.to/antiduhring/usando-mensageria-com-amazon-sqs-node-4n8b</guid>
      <description>&lt;h2&gt;
  
  
  O que é um serviço de mensageria
&lt;/h2&gt;

&lt;p&gt;O serviço de mensageria é uma forma de trocar informações entre diferentes partes de uma aplicação ou sistema de forma organizada e eficiente. Ele ajuda a separar as partes da aplicação e facilita a sua manutenção e desenvolvimento.&lt;/p&gt;

&lt;p&gt;Imaginando uma aplicação de e-commerce em que o serviço de compra de produtos fica separado do serviço que processa o pagamento e efetivamente realiza a transação entre as contas bancárias, a forma mais segura e efetiva de realizar a comunicação entre eles é via mensageria.&lt;/p&gt;

&lt;p&gt;Com mensageria, o serviço de compra de produtos vai enviar uma mensagem para uma fila com as informações de transação, enquanto o serviço de pagamento vai buscar as mensagens nesta fila e realizar as transações. Dessa forma é possível garantir que, mesmo que o serviço de compra de produtos caia, ou esteja passando por uma demanda gigantesca que possa comprometer o processamento de novas requisições, os pagamentos ainda assim serão processados de forma correta. Isso também garante que, mesmo havendo milhares de pagamentos na fila para serem processados, o usuário não precisará aguardar a transação ser realizada, já que uma vez enviado o pagamento para fila, é garantido que ele será consumido pelo serviço de processamento do pagamento, independemente do tempo que demore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Objetivo neste tutorial
&lt;/h2&gt;

&lt;p&gt;Neste tutorial iremos criar um exemplo básico de um serviço de e-commerce (&lt;strong&gt;producer&lt;/strong&gt;) que se comunica com um serviço de pagamento (&lt;strong&gt;consumer&lt;/strong&gt;), e toda a comunicação será feita via mensageria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Como o objetivo é entender o funcionamento de um serviço de mensageria utilizando Amazon SQS, não iremos nos aprofundar tanto na criação dos serviços de e-commerce e pagamento. Em vez disso, vamos nos concentrar na comunicação entre os dois usando como base um projeto hospedado no repositório: &lt;a href="https://github.com/anti-duhring/amazon-sqs-tutorial"&gt;https://github.com/anti-duhring/amazon-sqs-tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Abra o terminal e digite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/anti-duhring/amazon-sqs-tutorial.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após isso, instale as dependências da aplicação com o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Executando a aplicação
&lt;/h2&gt;

&lt;p&gt;Iremos executar ambos os serviços: &lt;code&gt;producer&lt;/code&gt; e &lt;code&gt;consumer&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Vá até o root da pasta local do repositório que você acabou de clonar e abra dois terminais.&lt;/p&gt;

&lt;p&gt;Em um deles, digite o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run start:producer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No outro, digite o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run start:consumer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Entendendo o funcionamento
&lt;/h2&gt;

&lt;p&gt;A aplicação consiste em dois serviços: &lt;code&gt;producer&lt;/code&gt; e &lt;code&gt;consumer&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Producer&lt;/code&gt;: Uma simulação de um &lt;strong&gt;e-commerce&lt;/strong&gt;, que possui uma rota &lt;code&gt;/request-transfer&lt;/code&gt;, cujo objetivo é enviar ao serviço de pagamento (&lt;strong&gt;consumer&lt;/strong&gt;) uma requisição com o número da conta que fará o pagamento, o número da conta que receberá o pagamento e a quantia de dinheiro a ser transferido.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Consumer&lt;/code&gt;: Um exemplo de um &lt;strong&gt;serviço de pagamento&lt;/strong&gt; que recebe as informações por meio da rota &lt;code&gt;/process-transfer&lt;/code&gt; e realiza a transação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por ora a comunicação entre os dois serviços está sendo feita de forma direta, ou seja, dentro da própria rota &lt;code&gt;/request-transfer&lt;/code&gt; o &lt;strong&gt;producer&lt;/strong&gt; recebe as informações do pagamento e já dispara uma requisição para a rota &lt;code&gt;/process-transfer&lt;/code&gt; do &lt;strong&gt;consumer&lt;/strong&gt;, que realiza a transação.&lt;/p&gt;

&lt;p&gt;Agora, vamos adaptar o projeto para que o &lt;strong&gt;producer&lt;/strong&gt; não precise mais se comunicar diretamente com o &lt;strong&gt;consumer&lt;/strong&gt;. Em vez disso, o &lt;strong&gt;producer&lt;/strong&gt; será responsável apenas por enviar os pedidos de transação para uma fila, e o &lt;strong&gt;consumer&lt;/strong&gt; será responsável apenas por buscar esses pedidos constantemente e processá-los.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando nossa fila principal
&lt;/h2&gt;

&lt;p&gt;Vá até o serviço &lt;code&gt;Amazon SQS&lt;/code&gt; no seu console da &lt;a href="https://aws.amazon.com/pt/free/"&gt;&lt;strong&gt;AWS&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aVTuTizQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pi236kqow0g3h5yyo0bh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aVTuTizQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pi236kqow0g3h5yyo0bh.png" alt="Pesquisando por SQS na barra de pesquisa do console da AWS" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após acessar a página do &lt;code&gt;Amazon SQS&lt;/code&gt;, clique no botão &lt;strong&gt;"Create queue"&lt;/strong&gt; (criar fila).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--od3MnPa6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydngdanl0u1ut9j1ci39.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--od3MnPa6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydngdanl0u1ut9j1ci39.png" alt='Clicando no botão "Create queue" na página do Amazon SQS da AWS' width="592" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro da página de criação da fila você verá uma série de opções para configuração. Entre elas, destaco aqui o &lt;code&gt;type&lt;/code&gt; (tipo) da fila:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ineoZh_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6c15naaoi4s83w74gfa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ineoZh_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6c15naaoi4s83w74gfa.png" alt="Escolhendo o tipo da fila dentro da página de criação da fila" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O tipo da fila, pode ser &lt;strong&gt;standard&lt;/strong&gt;(comum) ou &lt;strong&gt;FIFO&lt;/strong&gt; (First In First Out). Filas comuns não possuem ordem nas mensagens, enquanto as &lt;strong&gt;FIFO&lt;/strong&gt; ordena a fila em forma de pilha, onde a primeira mensagem que foi criada será a primeira a ser encontrada ao buscar mensagens dessa fila.&lt;/p&gt;

&lt;p&gt;Para os propósitos deste tutorial, vamos usar as seguintes configurações que já são atribuídas por padrão pelo próprio &lt;strong&gt;SQS&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YygYZ-JW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/52ccfejm5nfaquzg58o1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YygYZ-JW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/52ccfejm5nfaquzg58o1.png" alt="Configurações da fila do Amazon SQS" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique no link &lt;code&gt;Info&lt;/code&gt; ao lado da configuração para entender melhor o que cada propriedade representa.&lt;/p&gt;

&lt;p&gt;Após ter criado a fila copie o URL gerado no final.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando o &lt;em&gt;service&lt;/em&gt; de comunicação com o Amazon SQS
&lt;/h2&gt;

&lt;p&gt;Para facilitar a comunicação da nossa aplicação com o &lt;code&gt;Amazon SQS&lt;/code&gt;, vamos criar um &lt;strong&gt;service&lt;/strong&gt;, dentro da pasta &lt;code&gt;src/service&lt;/code&gt;, que terá três funções principais: enviar uma mensagem para a fila, recuperar mensagens da fila e deletar mensagens da fila.&lt;/p&gt;

&lt;p&gt;Esse &lt;strong&gt;service&lt;/strong&gt; será útil para desacoplar o &lt;em&gt;SQS&lt;/em&gt; da nossa aplicação, permitindo que ele seja facilmente adaptado para funcionar com outros serviços de fila também.&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando a classe &lt;em&gt;SqsService&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Vamos começar com uma classe com apenas dois atributos, ambos privados, &lt;code&gt;client&lt;/code&gt; e &lt;code&gt;queueUrl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SqsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&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;A ideia é que &lt;code&gt;client&lt;/code&gt; seja uma instância do &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/classes/sqsclient.html"&gt;&lt;code&gt;SQSClient&lt;/code&gt;&lt;/a&gt; do pacote &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/index.html"&gt;&lt;code&gt;@aws-sdk/client-sqs&lt;/code&gt;&lt;/a&gt;, que serve pra estabelecer uma conexão com a nossa fila. Enquanto que &lt;code&gt;queueUrl&lt;/code&gt; será o URL da fila copiado anteriormente, que deverá ser passado via &lt;em&gt;constructor&lt;/em&gt;, assim vamos poder usar o &lt;em&gt;service&lt;/em&gt; para outras filas, se for preciso.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adicionando o client do SQS no &lt;em&gt;constructor&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Agora precisamos adicionar o &lt;code&gt;SQSClient&lt;/code&gt; no &lt;em&gt;constructor&lt;/em&gt;, e atribuí-lo como valor da propriedade &lt;code&gt;client&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SQSClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-sqs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SqsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_REGION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;accessKeyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;secretAccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_ACESS_KEY&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que, para estabelecer uma conexão, o &lt;code&gt;client&lt;/code&gt; requere algumas informações, que são parte da interface &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/interfaces/sqsclientconfig.html"&gt;&lt;code&gt;SQSClientConfig&lt;/code&gt;&lt;/a&gt;: &lt;code&gt;region&lt;/code&gt;, &lt;code&gt;accessKeyId&lt;/code&gt; e &lt;code&gt;secretAccessKey&lt;/code&gt;. Essas informações são referentes a sua conta da &lt;strong&gt;AWS&lt;/strong&gt; e não devem ser compartilhadas, por isso iremos usar um arquivo &lt;strong&gt;.env&lt;/strong&gt; pra criar variáveis de ambiente. &lt;/p&gt;

&lt;p&gt;Basta criar um arquivo &lt;code&gt;.env&lt;/code&gt; no root do projeto com as seguintes variáveis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;AWS_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;REGIÃO &lt;span class="o"&gt;(&lt;/span&gt;ex: us-east-1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ID DO USUÁRIO
&lt;span class="nv"&gt;AWS_ACESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;CHAVE DE ACESSO
&lt;span class="nv"&gt;AWS_MAIN_QUEUE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;URL DA SUA FILA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adicionando método para enviar mensagens para fila
&lt;/h3&gt;

&lt;p&gt;Agora precisamos criar um método que irá enviar uma mensagem para a nossa fila usando o &lt;code&gt;client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O método terá como parâmetro um objeto com duas propriedades: &lt;code&gt;body&lt;/code&gt; e &lt;code&gt;attributes&lt;/code&gt;. O &lt;code&gt;body&lt;/code&gt; será o texto que ficará no corpo da mensagem, enquanto &lt;code&gt;attributes&lt;/code&gt; é um valor opcional que fornece mais informações sobre a mensagem.&lt;/p&gt;

&lt;p&gt;Aqui está um exemplo do objeto, mas você pode entender melhor suas propriedades na &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/classes/sendmessagecommand.html"&gt;documentação oficial&lt;/a&gt; da AWS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MENSAGEM QUE IRÁ NO CORPO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VALOR_OPCIONAL1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;StringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;VALOR DO ATRIBUTO&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nosso método de enviar mensagem será assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SQSClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-sqs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SqsService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SQSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_REGION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;accessKeyId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;secretAccessKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_ACESS_KEY&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendMessageCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SendMessageCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;MessageAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;DelaySeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendMessageCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nx"&gt;err&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;Agora podemos enviar mensagens para a fila com o nosso &lt;em&gt;service&lt;/em&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Adicionando método para buscar mensagens na fila
&lt;/h3&gt;

&lt;p&gt;Além de enviar mensagens, precisamos também de um método para buscar mensagens na fila e retornar uma &lt;em&gt;array&lt;/em&gt; delas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;receiveMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receiveMessageCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReceiveMessageCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;MaxNumberOfMessages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;WaitTimeSeconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;MessageAttributeNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;All&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiveMessageCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;Messages&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Messages&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nx"&gt;err&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;Entendendo as propriedades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;QueueUrl&lt;/code&gt;: A URL da nossa fila.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MaxNumberOfMessages&lt;/code&gt;: O número máximo de mensagens a serem retornadas. O Amazon SQS nunca retorna mais mensagens do que esse valor (no entanto, menos mensagens podem ser retornadas).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WaitTimeSeconds&lt;/code&gt;: A duração (em segundos) pela qual a chamada aguarda a chegada de uma mensagem na fila antes de retornar.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MessageAttributeNames&lt;/code&gt;: Atributos que serão recebidos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para saber mais sobre as propriedades consulte a documentação oficial sobre a interface &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/interfaces/receivemessagecommandinput.html"&gt;ReceiveMessageCommandInput&lt;/a&gt; da AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adicionando método de deletar mensagem da fila
&lt;/h3&gt;

&lt;p&gt;Após a mensagem ser recebida e a transação ser concluída pelo &lt;strong&gt;consumer&lt;/strong&gt;, é importante excluir a mensagem para evitar processamento duplicado. &lt;/p&gt;

&lt;p&gt;Para isso, vamos criar um método em nosso &lt;em&gt;service&lt;/em&gt; que receberá um parâmetro chamado &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/interfaces/message-1.html"&gt;&lt;code&gt;ReceiptHandle&lt;/code&gt;&lt;/a&gt;, que é um identificador associado ao recebimento de uma mensagem. Um novo identificador de recebimento é gerado cada vez que uma mensagem é recebida. Ao excluir uma mensagem, é necessário fornecer o &lt;code&gt;ReceiptHandle&lt;/code&gt; mais recente associado a ela para garantir que a mensagem correta seja excluída.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;deleteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;receiptHandle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deleteMessageCommand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DeleteMessageCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;QueueUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;queueUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;ReceiptHandle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;receiptHandle&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deleteMessageCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nx"&gt;err&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;Entendendo as propriedades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;QueueUrl&lt;/code&gt;: link da nossa fila.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ReceiptHandle&lt;/code&gt;: Identificador da nossa mensagem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para saber mais sobre as propriedades consulte a documentação oficial sobre a interface &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/interfaces/deletemessagecommandinput.html"&gt;DeleteMessageCommandInput&lt;/a&gt; da AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usando o &lt;em&gt;service&lt;/em&gt; de comunicação com o Amazon SQS no &lt;em&gt;producer&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Agora que criamos o service de comunicação com o Amazon SQS, podemos finalmente modificar a nossa rota &lt;code&gt;/request-transfer&lt;/code&gt; do &lt;strong&gt;producer&lt;/strong&gt;. Em vez de disparar uma requisição diretamente para a rota &lt;code&gt;/process-transfer&lt;/code&gt; do &lt;strong&gt;consumer&lt;/strong&gt;, o &lt;strong&gt;producer&lt;/strong&gt; enviará uma mensagem com as informações do pagamento para a nossa fila, para que o &lt;strong&gt;consumer&lt;/strong&gt; possa recebê-la e consumi-la no momento adequado.&lt;/p&gt;

&lt;p&gt;Nossa rota &lt;code&gt;/request-transfer&lt;/code&gt; terá, agora, o seguinte conteúdo:&lt;/p&gt;

&lt;p&gt;Primeiro criamos uma nova instância do &lt;code&gt;SqsService&lt;/code&gt; e, após isso, chamamos o método &lt;code&gt;sendMessage()&lt;/code&gt;, passando como &lt;strong&gt;body&lt;/strong&gt; as informações da nossa transação. Como o &lt;strong&gt;body&lt;/strong&gt; precisa ser uma &lt;em&gt;string&lt;/em&gt;, o método &lt;code&gt;JSON.stringify()&lt;/code&gt; é chamado para converter nosso objeto com as informações da transação em texto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/transfer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nx"&gt;fromAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;toAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;amount&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_MAIN_QUEUE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="nx"&gt;fromAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;toAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;amount&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sua transação será processada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Erro interno&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Consumindo as mensagens da fila no &lt;em&gt;consumer&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Agora que o &lt;strong&gt;producer&lt;/strong&gt; envia as mensagens para a fila e não se conecta mais diretamente ao &lt;strong&gt;consumer&lt;/strong&gt;, precisamos criar um &lt;strong&gt;worker&lt;/strong&gt; que busque constantemente por transações em nossa fila e as processe. Para isso, usaremos uma biblioteca bem conhecida do Node.js para agendamento de tarefas, chamada &lt;a href="https://www.npmjs.com/package/node-cron"&gt;&lt;code&gt;node-cron&lt;/code&gt;&lt;/a&gt;. Com ela, poderemos atribuir uma tarefa a ser executada repetidamente pelo &lt;strong&gt;consumer&lt;/strong&gt;. Essa tarefa será buscar novos pedidos de transações na fila e, no nosso caso, para facilitar a visualização do que está acontecendo, vamos definir um intervalo de 1 minuto. Ou seja, o &lt;strong&gt;consumer&lt;/strong&gt; buscará novas transações na fila e as processará a cada 1 minuto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando a task agendada com &lt;em&gt;node-cron&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Para criar uma task com &lt;code&gt;node-cron&lt;/code&gt; que seja executada a cada 1min, basta substituirmos nossa rota &lt;code&gt;/process-transfer&lt;/code&gt; por essa função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cron&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-cron&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* * * * *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Running every minute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora sempre que o nosso serviço &lt;strong&gt;consumer&lt;/strong&gt; estiver sendo executado, uma &lt;em&gt;task&lt;/em&gt; será realizada automaticamente a cada 1min.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consumindo mensagens do Amazon SQS dentro da task
&lt;/h3&gt;

&lt;p&gt;Agora que nossa task está sendo executada a cada 1min, precisamos fazer com que ela busque mensagens que estão na nossa fila, para isso, iremos criar uma nova instância do &lt;code&gt;SqsService&lt;/code&gt; e chamar o método &lt;code&gt;receiveMessages()&lt;/code&gt; que criamos anteriormente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* * * * *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_MAIN_QUEUE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receiveMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&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;O output será uma array de objetos &lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sqs/interfaces/message-1.html"&gt;&lt;code&gt;Message&lt;/code&gt;&lt;/a&gt;, que são as nossas mensagens:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nxk7Mm0z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b30jfyt570aud9xcftpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nxk7Mm0z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b30jfyt570aud9xcftpq.png" alt="Exemplo de uma mensagem retornada pela nossa fila do Amazon SQS" width="601" height="305"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Removendo mensagens da fila
&lt;/h3&gt;

&lt;p&gt;Agora que o nosso &lt;strong&gt;consumer&lt;/strong&gt; já recebe as mensagens da fila de forma autônoma, isto é, sem precisar ser "chamado" pelo &lt;strong&gt;producer&lt;/strong&gt;, vamos implementar um protótipo que simula o processamento da transação de cada mensagem. Ao final do processamento, a mensagem será removida da fila. &lt;/p&gt;

&lt;p&gt;É importante destacar que toda mensagem &lt;strong&gt;precisa&lt;/strong&gt; ser removida da fila após ser consumida, para evitar que ela seja processada duas vezes.&lt;/p&gt;

&lt;p&gt;A função que iremos adicionar faz um loop por cada mensagem recebida e simula seu processamento com um &lt;em&gt;setTimeout&lt;/em&gt; dentro de uma &lt;em&gt;Promise&lt;/em&gt;, demorando 5 segundos pra cada mensagem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* * * * *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_MAIN_QUEUE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receiveMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Simulando processamento da mensagem &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&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;Após o processamento precisamos remover a mensagem da fila. Pra isso iremos chamar o método &lt;code&gt;deleteMessage()&lt;/code&gt; do nosso &lt;code&gt;SqsService&lt;/code&gt;. Ele recebe como parâmetro o &lt;code&gt;ReceiptHandle&lt;/code&gt; da mensagem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* * * * *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqsService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AWS_MAIN_QUEUE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sqsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receiveMessages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Simulando processamento da mensagem &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5000&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="nx"&gt;sqsService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;ReceiptHandle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Mensagem &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; processada e removida da fila...`&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! Criamos um serviço de pagamentos que se comunica via mensageria com o &lt;code&gt;Amazon SQS&lt;/code&gt;. Perceba que, agora, o serviço que pede que pagamentos sejam feitos e o serviço que de fato processa o pagamento são totalmente independentes um do outro, o que facilita a escalabilidade e manutenção.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>api</category>
    </item>
    <item>
      <title>Shallow Copy vs Deep Copy no JavaScript</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Wed, 26 Apr 2023 18:47:36 +0000</pubDate>
      <link>https://dev.to/antiduhring/shallow-copy-vs-deep-copy-no-javascript-2h7g</link>
      <guid>https://dev.to/antiduhring/shallow-copy-vs-deep-copy-no-javascript-2h7g</guid>
      <description>&lt;p&gt;Uma &lt;em&gt;shallow copy&lt;/em&gt; de um objeto é uma cópia que, embora aponte para uma referência diferente do objeto original, suas propriedades ainda apontam para as mesmas referências na memória. Portanto, embora sejam objetos diferentes, a alteração do valor de uma propriedade do objeto original também alterará o valor da mesma propriedade na cópia, e vice-versa.&lt;/p&gt;

&lt;p&gt;É possível criar uma &lt;em&gt;shallow copy&lt;/em&gt; usando o método &lt;code&gt;Object.assign&lt;/code&gt;, &lt;em&gt;spread operator&lt;/em&gt; e etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Shallow copy&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ben&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Ben&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Ben&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Importante lembrar que, no JavaScript, todo valor primitivo (como número, string, etc.) é armazenado diretamente no objeto, e não apenas sua referência na memória. Por isso, mesmo em uma &lt;em&gt;shallow copy&lt;/em&gt; de um objeto, suas propriedades primitivas serão diferentes e a modificação do valor no objeto original não afetará o valor na cópia, e vice-versa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Shallow copy&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Bob&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Tom&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já a &lt;em&gt;deep copy&lt;/em&gt; é o oposto de uma &lt;em&gt;shallow copy&lt;/em&gt;, sendo uma cópia do objeto em que todas as referências apontam para locais diferentes na memória em relação ao objeto original. Dessa forma, alterar o valor de uma propriedade no objeto original não afetará o valor da mesma propriedade na cópia, e vice-versa.&lt;/p&gt;

&lt;p&gt;É possível criar uma &lt;em&gt;deep copy&lt;/em&gt; de um objeto usando o método &lt;code&gt;JSON.parse&lt;/code&gt;, a biblioteca &lt;code&gt;lodash&lt;/code&gt; do Node ou uma função recursiva que utilize &lt;em&gt;spread operator&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rob&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Deep copy&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ben&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Ben&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bestFriend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Rob&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compreender as diferenças entre &lt;em&gt;shallow copy&lt;/em&gt; e &lt;em&gt;deep copy&lt;/em&gt; pode ajudar a evitar erros ou mudanças inesperadas nos valores dos objetos.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Criando um algoritmo de pesquisa em largura em grafos</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Tue, 11 Apr 2023 20:08:54 +0000</pubDate>
      <link>https://dev.to/antiduhring/criando-um-algoritmo-de-pesquisa-em-largura-em-grafos-3af3</link>
      <guid>https://dev.to/antiduhring/criando-um-algoritmo-de-pesquisa-em-largura-em-grafos-3af3</guid>
      <description>&lt;p&gt;Grafos são estruturas de dados que consistem em vértices (ou nós) conectados por arestas (ou arcos). Eles são amplamente utilizados em várias áreas, como ciência da computação, matemática, física, biologia, entre outras. &lt;/p&gt;

&lt;p&gt;Na ciência da computação, por exemplo, os grafos são usados para representar relações entre objetos, como usuários em uma rede social, ou para modelar rotas e caminhos em mapas, como as ruas no Google Maps. Eles permitem a análise de dados complexos, possibilitando a descoberta de padrões e informações úteis. Vejamos o seguinte grafo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PDtyaONA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f21fk35en6h5z9j2mytb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PDtyaONA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f21fk35en6h5z9j2mytb.png" alt="Grafo com as seguintes vértices: A, B, C, D, E e F" width="461" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para responder perguntas como "&lt;em&gt;existe um caminho do vértice A ao vértice B?&lt;/em&gt;" ou "&lt;em&gt;qual é o caminho mínimo do vértice A ao vértice B?&lt;/em&gt;", uma das soluções é utilizar o algoritmo de pesquisa em largura (BFS - &lt;em&gt;breadth-first search&lt;/em&gt;). Ele começa no vértice A e expande sua pesquisa para os vértices conectados a ele, que são B e C. Em seguida, avança para os vértices conectados a B e C, e assim por diante, buscando em largura.&lt;/p&gt;

&lt;p&gt;Vamos criar um exemplo de algoritmo de pesquisa em largura usando JavaScript, para responder a seguinte questão: &lt;strong&gt;&lt;em&gt;Qual o caminho mais curto do vértice A ao vértice F?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Primeiro vamos definir as vértices e suas conexões como um objeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;F&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;D&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;E&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;F&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estamos dizendo que A se conecta com B e C, que B se conecta com A, D e F e assim sucessivamente.&lt;/p&gt;

&lt;p&gt;Agora vamos começar a criar nosso algoritmo. Primeiro precisamos que ele faça um &lt;em&gt;loop&lt;/em&gt; por todos os vértices do grafo e identifique quais já foram visitados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findShortestPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// fila dos vertices que serão visitados&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="c1"&gt;// objeto contendo os vértices que já foram visitados&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="c1"&gt;// objeto que vai identificar quais os vértices anteriores a um determinado vértice pra montarmos o caminho&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;predecessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

    &lt;span class="c1"&gt;// Loop enquanto houverem vértices para ser visitados&lt;/span&gt;
    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Obtém e remove o primeiro vértice da lista&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// RESTO DO NOSSO ALGORITMO&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;Agora precisamos fazer com que, a cada novo vértice buscado, a função obtenha o vértice anterior que se ligue a ele e adicione o caminho no nosso objeto &lt;code&gt;predecessor&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findShortestPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;predecessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// Obtém os vértices que estão conectados ao vértice atual&lt;/span&gt;
      &lt;span class="c1"&gt;// aqui são chamados de vizinhos&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neighbors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

      &lt;span class="c1"&gt;// Itera sobre cada vértice vizinho&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Apenas continua a busca se ele ainda não tiver sido visitado&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="c1"&gt;// Adiciona no objeto predecessor o vértice que está ligado a ele&lt;/span&gt;
            &lt;span class="nx"&gt;predecessor&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="c1"&gt;// Adiciona ele mesmo na fila de vértices para serem pesquisados&lt;/span&gt;
            &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// RESTO DO NOSSO ALGORITMO&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;Agora que o algoritmo já busca todos os vértices do nosso grafo, precisamos fazer com que ele obtenha o vértice de destino e, a partir do objeto &lt;code&gt;predecessor&lt;/code&gt;, construa o caminho de volta ao ponto inicial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findShortestPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;predecessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neighbors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;predecessor&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="c1"&gt;// Observa se o vizinho que está sendo checado atualmente...&lt;/span&gt;
          &lt;span class="c1"&gt;// é o nosso destino&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;endNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Começa a reconstruir o caminho mais curto a partir do vértice...&lt;/span&gt;
            &lt;span class="c1"&gt;// de chegada&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shortestPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;endNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="c1"&gt;// Obtém o vértice atual de onde os vizinhos foram obtidos&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;prevNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Loop enquanto o caminho ainda não tiver sido reconstruído...&lt;/span&gt;
            &lt;span class="c1"&gt;// até o ponto de partida&lt;/span&gt;
            &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevNode&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Adiciona no começo da array `shortestPath` o vértice `prevNode`&lt;/span&gt;
                &lt;span class="nx"&gt;shortestPath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;// Obtém o predecessor do `prevNode` e faz dele o `prevNode` atual&lt;/span&gt;
                &lt;span class="nx"&gt;prevNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;predecessor&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prevNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nx"&gt;shortestPath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;shortestPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;Ao executar o nosso código vemos o resultado da busca:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;F&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;D&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;E&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;F&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shortestPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findShortestPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;F&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shortestPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ['A', 'B', 'F']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos ver que o caminho mais curto do vértice ao vértice F de fato é &lt;strong&gt;&lt;em&gt;A -&amp;gt; B -&amp;gt; F&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U-09QotS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jw56k8mgbks4nmps2sp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U-09QotS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jw56k8mgbks4nmps2sp.png" alt="Imagem que mostra os vértices A, B e F conectados em destaque" width="461" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O algoritmo de busca em largura é uma ferramenta essencial na resolução de problemas que envolvem a descoberta do menor caminho entre dois pontos em um grafo. Mas é importante lembrar que cada aplicação pode ter suas particularidades e o algoritmo de pesquisa em largura não é o único e pode não ser o melhor algoritmo de busca pelo menor caminho em muitos casos. &lt;/p&gt;

&lt;p&gt;Saber implementar um algoritmo de pesquisa em largura pode ajudar a solucionar problemas complexos em diversas áreas, como redes de transporte, otimização de rotas e até mesmo jogos.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Como algoritmos melhoram a performance do seu código</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Sun, 26 Mar 2023 19:39:51 +0000</pubDate>
      <link>https://dev.to/antiduhring/como-algoritmos-melhoram-a-performance-do-seu-codigo-31mn</link>
      <guid>https://dev.to/antiduhring/como-algoritmos-melhoram-a-performance-do-seu-codigo-31mn</guid>
      <description>&lt;p&gt;Algoritmos são conjuntos de instruções que direcionam um computador para realizar uma tarefa específica. Eles estão presentes em todas as áreas da programação e são essenciais para otimizar o desempenho do código. O objetivo desse artigo é introduzir a importância dos algoritmos usando como exemplo a performance na ordenações de listas. &lt;/p&gt;

&lt;p&gt;Imagine o seguinte cenário: temos uma lista de 10 números &lt;code&gt;[3, 7, 2, 8, 1, 6, 9, 4, 5, 0]&lt;/code&gt; e queremos que seja ordenada do menor para o maior.&lt;/p&gt;

&lt;p&gt;Nesse caso, dois algoritmos bastante conhecidos (não são os únicos e nem os melhores, mas servem como exemplo) na área de ordenação de listas são o &lt;strong&gt;bubble sort&lt;/strong&gt; e o &lt;strong&gt;quick sort&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;O &lt;em&gt;bubble sort&lt;/em&gt; funciona da seguinte maneira: ele percorre a lista diversas vezes, comparando cada elemento com o seu sucessor e trocando o lugar de ambos caso necessário. Esse processo é repetido até que a lista esteja completamente ordenada. O tempo de execução médio desse algoritmo é &lt;code&gt;O(n^2)&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Nota: &lt;code&gt;O()&lt;/code&gt; é uma notação de medida de complexidade de tempo chamada &lt;a href="https://www.freecodecamp.org/portuguese/news/o-que-e-a-notacao-big-o-complexidade-de-tempo-e-de-espaco/"&gt;&lt;strong&gt;Big O&lt;/strong&gt;&lt;/a&gt;. Em resumo, serve pra descrever quantas ações aquele algoritmo precisa performar pra que atinja seu objetivo&lt;/p&gt;

&lt;p&gt;Imaginando nosso caso hipotético de uma lista com 10 números, cada número precisaria percorrer toda a lista e comparar os valores, o que são 10 ações pra cada elemento, por isso a complexidade de tempo é &lt;strong&gt;n^2&lt;/strong&gt;, que no caso seria &lt;strong&gt;10^2 = 10*10&lt;/strong&gt;, que é igual a &lt;strong&gt;100&lt;/strong&gt;. &lt;strong&gt;Ou seja, o &lt;em&gt;bubble sort&lt;/em&gt; requere 100 ações pra ordenar uma lista de 10 números&lt;/strong&gt;. Extrapolando o exemplo pra uma lista de 100 números, a quantidade de ações requeridas sobe pra &lt;strong&gt;10.000&lt;/strong&gt; (ou &lt;strong&gt;100^2 = 100*100&lt;/strong&gt;)!&lt;/p&gt;

&lt;p&gt;Por outro lado, o &lt;em&gt;quick sort&lt;/em&gt; é um algoritmo que utiliza uma estratégia conhecida como "&lt;em&gt;dividir para conquistar&lt;/em&gt;". Ele escolhe um elemento da lista como &lt;strong&gt;pivô&lt;/strong&gt; e, em seguida, divide a lista em duas partes: uma contendo elementos &lt;strong&gt;menores que o pivô&lt;/strong&gt; e outra contendo elementos &lt;strong&gt;maiores que o pivô&lt;/strong&gt;. Esse processo é repetido até que toda a lista esteja ordenada.  &lt;/p&gt;

&lt;p&gt;Voltando ao nosso caso de uma lista com 10 números, o &lt;em&gt;quick sort&lt;/em&gt; escolheria um elemento do array para ser o pivô. Neste caso, vamos escolher o elemento do meio, que é o número 1.&lt;/p&gt;

&lt;p&gt;O array é dividido em duas partes: &lt;strong&gt;uma parte com valores menores&lt;/strong&gt; que o pivô e outra &lt;strong&gt;com valores maiores ou iguais&lt;/strong&gt; ao pivô.&lt;br&gt;
A parte dos menores valores fica à esquerda do pivô, e a parte dos maiores valores fica à direita do pivô. Os valores iguais ao pivô podem ficar em qualquer uma das partes.&lt;/p&gt;

&lt;p&gt;A lista então é dividida em &lt;code&gt;[3, 2, 1, 4, 0]&lt;/code&gt; e &lt;code&gt;[7, 8, 6, 9, 5]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Agora devemos &lt;strong&gt;repetir&lt;/strong&gt; o processo pra ambas as listas.&lt;/p&gt;

&lt;p&gt;Vamos escolher um novo pivô para cada parte, e dividir o array novamente em duas partes: uma com valores menores que o pivô e outra com valores maiores ou iguais ao pivô.&lt;/p&gt;

&lt;p&gt;Para a lista da esquerda, escolhemos o elemento 2 como pivô e dividimos em &lt;code&gt;[1, 0]&lt;/code&gt; e &lt;code&gt;[3, 2, 4]&lt;/code&gt;. Para a lista da direita, escolhemos o elemento 8 como pivô e dividimos em &lt;code&gt;[7, 6, 5]&lt;/code&gt; e &lt;code&gt;[9]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Agora repetimos o processo até que todas as partes do array tenham tamanho 1 ou 0. Quando uma parte do array tem tamanho 1 ou 0, significa que ela já está ordenada.&lt;/p&gt;

&lt;p&gt;Ao final, o resultado será nossa lista ordenada da seguinte forma: &lt;code&gt;[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O tempo de execução médio do &lt;em&gt;quick sort&lt;/em&gt;, portanto, é &lt;code&gt;O(n * log2(n))&lt;/code&gt;, que significa, nesse caso, &lt;strong&gt;10 * log2(10) = 10 * 3,321 = 33,2&lt;/strong&gt;. Extrapolando o exemplo pra uma lista de 100 números temos &lt;strong&gt;100 * log2(100) = 100 * 6,643 = 664,3&lt;/strong&gt;. Ou seja, o algoritmo de &lt;em&gt;quick sort&lt;/em&gt; precisa performar, em média, &lt;strong&gt;664,3&lt;/strong&gt; ações pra ordenar uma lista de 100 números, bem menor do que o tempo de execução do &lt;em&gt;bubble sort&lt;/em&gt;, que precisa de &lt;strong&gt;10.000 ações&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Apenas com o uso de algoritmos e matemática diminuímos em quase &lt;strong&gt;1.400%&lt;/strong&gt; o tempo de execução do nosso código, por isso o domínio do assunto é tão crucial para programadores.&lt;/p&gt;

&lt;p&gt;Em resumo, os algoritmos são ferramentas importantes para a otimização do desempenho do código. Conhecer os fundamentos da programação é essencial para auxiliar na resolução de problemas de forma correta e &lt;strong&gt;eficiente&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Dica de leitura: &lt;em&gt;Entendendo Algoritmos: Um Guia Ilustrado Para Programadores e Outros Curiosos&lt;/em&gt;, &lt;strong&gt;Aditya Y. Bhargava&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Como criar uma docker image para sua API feita com Java?</title>
      <dc:creator>Mateus Vinícius</dc:creator>
      <pubDate>Tue, 21 Feb 2023 14:52:23 +0000</pubDate>
      <link>https://dev.to/antiduhring/como-criar-uma-docker-image-para-sua-api-feita-com-java-3gd2</link>
      <guid>https://dev.to/antiduhring/como-criar-uma-docker-image-para-sua-api-feita-com-java-3gd2</guid>
      <description>&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Uma &lt;strong&gt;&lt;em&gt;Docker Image&lt;/em&gt;&lt;/strong&gt; é um pacote executável que contém todas as ferramentas e softwares necessários para executar uma aplicação, incluindo, além do próprio código-fonte, bibliotecas, dependências, configurações e variáveis de ambiente. Ao executar uma &lt;strong&gt;&lt;em&gt;Docker Image&lt;/em&gt;&lt;/strong&gt; o resultado é a criação de um &lt;strong&gt;&lt;em&gt;container&lt;/em&gt;&lt;/strong&gt; , que é o ambiente isolado onde o conteúdo da imagem irá rodar. &lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;&lt;em&gt;container&lt;/em&gt;&lt;/strong&gt; é como se fosse uma miniatura do sistema operacional, que isola a aplicação do ambiente em que está sendo executada. Esse isolamento permite que ela funcione de forma independente do sistema operacional ou hardware da máquina utilizada. &lt;/p&gt;

&lt;p&gt;As &lt;strong&gt;&lt;em&gt;Docker Images&lt;/em&gt;&lt;/strong&gt; permitem que nós possamos criar ambientes de desenvolvimento e produção consistentes, sem conflitos ou problemas de compatibilidade. É o fim definitivo para o problema "&lt;em&gt;Mas na minha máquina funciona!&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;Além disso, as imagens podem ser compartilhadas no &lt;strong&gt;&lt;em&gt;Docker Hub&lt;/em&gt;&lt;/strong&gt;, e reutilizadas por outras equipes de desenvolvimento, tornando o processo de desenvolvimento mais eficiente e escalável. &lt;/p&gt;

&lt;p&gt;O objetivo deste tutorial será a criação de uma imagem especificamente para uma API Java com Spring Boot. Será usado &lt;strong&gt;&lt;em&gt;Maven&lt;/em&gt;&lt;/strong&gt; para gerenciamento e build, na sua versão &lt;strong&gt;&lt;em&gt;3.8.7&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalando o Docker
&lt;/h2&gt;

&lt;p&gt;Primeiro é necessário instalar o &lt;strong&gt;&lt;em&gt;Docker&lt;/em&gt;&lt;/strong&gt; no seu computador. A própria &lt;a href="https://docs.docker.com/engine/install/"&gt;documentação da ferramenta&lt;/a&gt; já traz tutoriais simplificados, com passo-à-passo específico para cada sistema operacional, basta escolher uma opção e seguir os comandos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando o Dockerfile
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/strong&gt; é o arquivo que conterá as instruções para a construção da &lt;strong&gt;&lt;em&gt;Docker Image&lt;/em&gt;&lt;/strong&gt;, como uma receita de cozinha que descreve todos os ingredientes e passos necessários para criar uma refeição. No caso do &lt;strong&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/strong&gt;, as instruções descrevem o que deve ser incluído na imagem Docker, como o sistema operacional, as bibliotecas e as dependências, e como configurar o ambiente para a aplicação. &lt;/p&gt;

&lt;p&gt;O primeiro passo é criar um arquivo de nome &lt;strong&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/strong&gt;, sem extensão, dentro da pasta raiz da aplicação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- app
    - .idea/
    - .mvn/
    - src/
    - target/
    - .gitignore
    - Dockerfile
    - HELP.md
    - mvnw
    - mvnw.cmd
    - pom.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O arquivo irá apontar para uma &lt;strong&gt;&lt;em&gt;Docker Image&lt;/em&gt;&lt;/strong&gt; que será usada como base para a criação da nossa própria imagem e também conterá todos os comandos necessários para a build da aplicação e sua execução.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escolhendo a imagem base
&lt;/h2&gt;

&lt;p&gt;Por termos escolhido o &lt;strong&gt;&lt;em&gt;Maven 3.8.7&lt;/em&gt;&lt;/strong&gt; como compilador e gerenciamento e o &lt;strong&gt;&lt;em&gt;JDK 19&lt;/em&gt;&lt;/strong&gt; para a execução da aplicação Java, deveremos usar como base a &lt;strong&gt;&lt;em&gt;Docker Image&lt;/em&gt;&lt;/strong&gt; &lt;a href="https://hub.docker.com/layers/library/maven/3.8.7-eclipse-temurin-19-alpine/images/sha256-035256f20554c181fc63b92efe7c813c85e5eb7e294be4dc365bbe4da74dd083?context=explore"&gt;maven:3.8.7-eclipse-temurin-19-alpine&lt;/a&gt;, que já contém ambas as ferramentas e suas dependências instaladas sob um sistema operacional linux. &lt;/p&gt;

&lt;p&gt;A escolha da imagem base vai variar conforme as necessidades, sendo possível utilizar desde uma imagem base de um Ubuntu novo, e dentro do próprio &lt;strong&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/strong&gt; configurar comandos para que o &lt;strong&gt;&lt;em&gt;Maven&lt;/em&gt;&lt;/strong&gt; e a &lt;strong&gt;&lt;em&gt;JDK&lt;/em&gt;&lt;/strong&gt; sejam instalados, quanto utilizar uma imagem já com ferramentas pré-instaladas, como é o caso da &lt;a href="https://hub.docker.com/layers/library/maven/3.8.7-eclipse-temurin-19-alpine/images/sha256-035256f20554c181fc63b92efe7c813c85e5eb7e294be4dc365bbe4da74dd083?context=explore"&gt;maven:3.8.7-eclipse-temurin-19-alpine&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adicionando a imagem base ao arquivo Dockerfile
&lt;/h2&gt;

&lt;p&gt;Agora iremos adicionar conteúdo ao arquivo Dockerfile, e o primeiro passo será apontar para a imagem base, e isso é feito com o comando &lt;strong&gt;&lt;em&gt;&lt;code&gt;FROM image-name&lt;/code&gt;&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start with maven:3.8.7-eclipse-temurin-19-alpine base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; maven:3.8.7-eclipse-temurin-19-alpine&lt;/span&gt;

&lt;span class="c"&gt;# Maintaner data &lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="Mateus Vinícius &amp;lt;mateus.limavn@gmail.com&amp;gt;"&lt;/span&gt;

&lt;span class="c"&gt;# End&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comando &lt;strong&gt;&lt;em&gt;&lt;code&gt;LABEL&lt;/code&gt;&lt;/em&gt;&lt;/strong&gt; é usado para adicionar informações e metadados à imagem que está sendo criada, como o nome do mantenedor, a versão da imagem, a descrição da aplicação e etc. Essa prática ajuda na organização e identificação das imagens, já que o comando &lt;code&gt;docker images&lt;/code&gt; exibe essas informações registradas no &lt;strong&gt;&lt;em&gt;&lt;code&gt;LABEL&lt;/code&gt;&lt;/em&gt;&lt;/strong&gt; juntamente com as informações da própria imagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adicionando comandos para a build da aplicação
&lt;/h2&gt;

&lt;p&gt;Após apontarmos a imagem que será usada como base, é hora de configurar os comandos que serão executados para fazer a build da nossa aplicação Java. O build será feito com o comando &lt;code&gt;mvn package&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start with maven:3.8.7-eclipse-temurin-19-alpine base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; maven:3.8.7-eclipse-temurin-19-alpine&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="Mateus Vinícius &amp;lt;mateus.limavn@gmail.com&amp;gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Set the working directory to /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the source code to the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Build the application with Maven&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn package

&lt;span class="c"&gt;#End&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comando &lt;code&gt;WORKDIR&lt;/code&gt; define o diretório de trabalho padrão para as próximas instruções do arquivo. Isso permite que os comandos que serão executados saibam qual é o caminho do diretório da aplicação sem que seja necessário repetir o caminho absoluto a todo momento. O padrão é usar o diretório &lt;code&gt;/app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Já o comando &lt;code&gt;COPY &amp;lt;fonte&amp;gt; &amp;lt;destino&amp;gt;&lt;/code&gt; copia o conteúdo da imagem para o container que será criado, que é o ambiente de execução da aplicação. Nesse caso todo o conteúdo da imagem será copiado para o container.&lt;/p&gt;

&lt;p&gt;Para fazer a build da aplicação Java utilizaremos o comando &lt;code&gt;mvn package&lt;/code&gt; do &lt;strong&gt;&lt;em&gt;Maven&lt;/em&gt;&lt;/strong&gt;, por isso ele é chamado com o &lt;code&gt;RUN&lt;/code&gt;, que serve para executar outros comandos ou instruções.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definindo as variáveis de ambiente
&lt;/h2&gt;

&lt;p&gt;A maioria dos projetos utilizam variáveis de ambiente, elas são usadas tanto pelas aplicações quanto pelo próprio sistema operacional para acessar as configurações definidas.&lt;/p&gt;

&lt;p&gt;No caso da aplicação Java que é usada de exemplo, as variáveis de ambiente estão sendo chamadas dentro do arquivo &lt;strong&gt;&lt;em&gt;application-prod.properties&lt;/em&gt;&lt;/strong&gt; da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.datasource.url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${DATASOURCE_URL}&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.driver-class-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;org.postgresql.Driver&lt;/span&gt;
&lt;span class="py"&gt;spring.jpa.properties.hibernate.dialect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;org.hibernate.dialect.PostgreSQLDialect&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.username&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${DATASOURCE_USERNAME}&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${DATASOURCE_PASSWORD}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No caso, os valores &lt;code&gt;${DATASOURCE_URL}&lt;/code&gt;, &lt;code&gt;${DATASOURCE_USERNAME}&lt;/code&gt; e &lt;code&gt;${DATASOURCE_PASSWORD}&lt;/code&gt; são as variáveis de ambiente. Elas estão definindo a &lt;em&gt;url&lt;/em&gt; de conexão com o banco de dados, o usuário &lt;code&gt;root&lt;/code&gt; desse banco e a sua senha.&lt;/p&gt;

&lt;p&gt;Pra facilitar o reaproveitamento da imagem o ideal é que essas propriedades de configuração da aplicação que sejam dinâmicas passem a ser atribuídas à variáveis de ambiente, assim o desenvolvedor poderá modificá-las antes de executar o container. &lt;/p&gt;

&lt;p&gt;Mas é importante, também, atribuir valores padrão à essas variáveis, e é pra isso que serve o comando &lt;code&gt;ENV&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start with maven:3.8.7-eclipse-temurin-19-alpine base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; maven:3.8.7-eclipse-temurin-19-alpine&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="Mateus Vinícius &amp;lt;mateus.limavn@gmail.com&amp;gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Set the working directory to /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the source code to the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Build the application with Maven&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn package

&lt;span class="c"&gt;# Set environment variables if needed&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_URL=jdbc:postgresql://localhost:5432/db&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_USERNAME=postgres&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_PASSWORD=postgrespassword&lt;/span&gt;

&lt;span class="c"&gt;#End&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Informando as portas que o container estará executando
&lt;/h2&gt;

&lt;p&gt;As portas que serão expostas para que a API receba requisições são definidas com o comando &lt;code&gt;EXPOSE&lt;/code&gt;, e, nesse caso, utilizaremos a padrão &lt;strong&gt;&lt;em&gt;8080&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start with maven:3.8.7-eclipse-temurin-19-alpine base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; maven:3.8.7-eclipse-temurin-19-alpine&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="Mateus Vinícius &amp;lt;mateus.limavn@gmail.com&amp;gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Set the working directory to /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the source code to the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Build the application with Maven&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn package

&lt;span class="c"&gt;# Set environment variables if needed&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_URL=jdbc:postgresql://localhost:5432/db&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_USERNAME=postgres&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_PASSWORD=postgrespassword&lt;/span&gt;

&lt;span class="c"&gt;# Expose default Spring Boot port&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;

&lt;span class="c"&gt;#End&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Definindo o comando para execução do arquivo jar
&lt;/h2&gt;

&lt;p&gt;Agora que o container já fez a build da aplicação, configurou as variáveis de ambiente e expôs as portas para requisições, chegou o momento de definir o comando para executar o arquivo &lt;code&gt;jar&lt;/code&gt; que é gerado pela build do &lt;strong&gt;&lt;em&gt;Maven&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para isso iremos utilizar o comando &lt;code&gt;CMD&lt;/code&gt;, que recebe uma array de argumentos que será executado em uma linha do terminal.&lt;/p&gt;

&lt;p&gt;O comando para executar uma aplicação java, que está compilada num arquivo &lt;code&gt;jar&lt;/code&gt;, e utilizando o profile de produção é &lt;code&gt;java -jar target/myapp-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod&lt;/code&gt;, portanto, o comando &lt;code&gt;CMD&lt;/code&gt; correspondente será &lt;code&gt;CMD ["java", "-jar", "target/myapp-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=prod"]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ao final nosso arquivo Dockerfile ficará com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start with maven:3.8.7-eclipse-temurin-19-alpine base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; maven:3.8.7-eclipse-temurin-19-alpine&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="Mateus Vinícius &amp;lt;mateus.limavn@gmail.com&amp;gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Set the working directory to /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy the source code to the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Build the application with Maven&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mvn package

&lt;span class="c"&gt;# Set environment variables if needed&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_URL=jdbc:postgresql://localhost:5432/db&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_USERNAME=postgres&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DATASOURCE_PASSWORD=postgrespassword&lt;/span&gt;

&lt;span class="c"&gt;# Expose default Spring Boot port&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;

&lt;span class="c"&gt;# Run the jar file&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java", "-jar", "target/myapp-0.0.1-SNAPSHOT.jar", "--spring.profiles.active=prod"]&lt;/span&gt;

&lt;span class="c"&gt;#End&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Criando a Docker Image
&lt;/h2&gt;

&lt;p&gt;Já com o &lt;strong&gt;&lt;em&gt;Docker&lt;/em&gt;&lt;/strong&gt; instalado e o arquivo &lt;strong&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/strong&gt; configurado, podemos realizar a build da imagem. Para isso, basta abrir no &lt;em&gt;terminal&lt;/em&gt; ou &lt;em&gt;prompt de comando&lt;/em&gt; a pasta da aplicação - a mesma em que o arquivo &lt;strong&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/strong&gt; se encontra - e executar o comando &lt;code&gt;docker image build -t myapp-api .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;&lt;em&gt;Docker&lt;/em&gt;&lt;/strong&gt; irá executar todos os comandos presentes no arquivo &lt;strong&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;/strong&gt;, o que inclui a build da aplicação usando o &lt;code&gt;mvn build&lt;/code&gt;, e, ao fim, irá gerar a imagem automaticamente.&lt;/p&gt;

&lt;p&gt;Para ver e executar a imagem gerada, basta rodar o comando &lt;code&gt;docker images&lt;/code&gt; no &lt;em&gt;terminal&lt;/em&gt; ou &lt;em&gt;prompt de comando&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;Com a imagem gerada rodar a aplicação se torna muito mais fácil, já que basta rodar o comando &lt;code&gt;docker run &amp;lt;nome-da-imagem&amp;gt;&lt;/code&gt; para que o container de execução seja criado.&lt;/p&gt;

&lt;p&gt;Agora você pode salvar essa imagem num repositório no &lt;strong&gt;&lt;em&gt;Docker Hub&lt;/em&gt;&lt;/strong&gt; para executar em qualquer servidor ou máquina pessoal, sem se preocupar com a configuração do ambiente ou problemas de incompatibilidade. Sua aplicação pode rodar em qualquer lugar!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>java</category>
      <category>webdev</category>
      <category>api</category>
    </item>
  </channel>
</rss>
