<?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>Forem: Yan.ts</title>
    <description>The latest articles on Forem by Yan.ts (@yanpiing).</description>
    <link>https://forem.com/yanpiing</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%2F856964%2F69824663-a4b3-4421-8ca5-d1858b1a3eac.jpeg</url>
      <title>Forem: Yan.ts</title>
      <link>https://forem.com/yanpiing</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/yanpiing"/>
    <language>en</language>
    <item>
      <title>Design Patterns</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Wed, 03 Aug 2022 04:03:04 +0000</pubDate>
      <link>https://forem.com/yanpiing/design-patterns-2246</link>
      <guid>https://forem.com/yanpiing/design-patterns-2246</guid>
      <description>&lt;p&gt;Design Patterns são um conjunto de soluções comuns para problemas recorrentes, inicialmente foram definidos pela Gang of Four (GoF) lá em 1994 no livro &lt;code&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Muitos padrões são utilizados até hoje como o singleton por exemplo que é usando por &lt;a href="https://docs.nestjs.com/fundamentals/injection-scopes"&gt;padrão no nestjs&lt;/a&gt; sempre que fazemos uma injeção de dependências. No entanto eles não são uma bala de prata e devem ser utilizados com cuidado&lt;/p&gt;

&lt;p&gt;Nesse artigo vou falar sobre alguns dos designs mas se quiser conhecer outros e principalmente ver implementações deles recomendo que leia o livro original ou utilize esse site &lt;a href="https://refactoring.guru/pt-br/design-patterns/catalog"&gt;https://refactoring.guru/pt-br/design-patterns/catalog&lt;/a&gt; onde além de exemplos bem simples de entender qual o problema que estamos tentando resolver com os patterns ele ainda tem exemplos de implementação em diversas linguagens&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Adapters
&lt;/h2&gt;

&lt;p&gt;O adpters é uma forma de abstrair libs externas deixando o código flexível  então por exemplo no javascript temos diversas bibliotecas com o intuito de lidar com datas (dateFns, DayJs, momentjs), a ideia desse padrão é, ao invés de utilizar diretamente a lib na classe onde vamos manipular datas, criarmos uma interface que declara todos os métodos que vamos utilizar e receber essa interface no construtor da classe que queremos manipular as datas, assim podemos facilmente trocar a implementação dessa interface por diversas libs diferentes porem para nossa classe não vai fazer diferença pois ela sempre vai estar chamando o método definido na interface, não importando quem implementou ele e nem como que ele foi implementado&lt;/p&gt;

&lt;h2&gt;
  
  
  Decorators
&lt;/h2&gt;

&lt;p&gt;A ideia do decorator é que quando uma classe pode conter mais de uma logica pertencente a ela, nos podemos passar uma outra instancia dela para ela mesma para que ela consiga chamar essas novas instancias, por exemplo, vamos supor que estou criando um modulo de notificações, onde quero enviar a notificação para o celular da pessoa então cria uma instancia que extende a classe notificações porém tem a logica de mandar a notificação para o celular, e crio também uma instancia para enviar e-mail da mesma forma, agora supondo que eu precise enviar uma notificação que é Celular + E-mail, o padrão então sugere que ao invés de chamarmos uma notificação e depois a outra, todas as notificações possam receber uma outra notificação no seu construtor e ir chamando a próxima até que não tenha recebido mais nenhuma, dessa forma podemos misturar as notificações de diversas formas&lt;/p&gt;

&lt;h2&gt;
  
  
  Composite
&lt;/h2&gt;

&lt;p&gt;Muito semelhante ao Decorators mas com diferença que a hierarquia importa mais. A ideia é deixar a gente compor objetos na estrutura de arvore e depois ir trabalhando com esses objetos de forma individual, então por exemplo se queremos saber o preço total de um pedido podemos receber itens que compõem esse pedido ou até mesmo um pedido anterior que vai compor esse pedido, e a ideia é percorrermos esse pedido anterior buscando o valor dele para somar com o valor dos itens do pedido atual e termos um valor total&lt;/p&gt;

&lt;h2&gt;
  
  
  Facade
&lt;/h2&gt;

&lt;p&gt;A ideia é ter um objeto que funciona como uma fachada escondendo um processo complexo onde tem que ser chamados vários métodos em ordens especificas, ao invés de deixar isso para o cliente nos podemos criar uma fachada com um método único que vai executar tudo na ordem que deve ser executada escondendo essa complexidade do cliente&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy
&lt;/h2&gt;

&lt;p&gt;O proxy tem como objetivo otimizar o tempo das chamadas, então por exemplo se eu preciso fazer algo que gasta muito recurso eu posso criar uma classe proxy que tem acesso a essa classe que queremos evitar chamar a toa, e então utilizamos a classe proxy para saber se a classe mais pesada deve ou não ser chamada, por exemplo, quero pegar um dado do banco de dados mas não tenho acesso, se eu fizer a chamada pelo proxy ele n vai deixar nem eu tentar acessar, mas se eu fizer normalmente eu vou conseguir e provavelmente vai falhar a chamada, outra utilização é usar o proxy como uma espécie de cache, digamos que eu precise de um valor que para conseguir esse valor eu preciso fazer uma conta complexa que demora muito tempo, se mais na frente na mesma execução eu precise desse valor novamente, o proxy pode me retornar ele direto&lt;/p&gt;

</description>
      <category>programming</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Kubernets</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Sun, 31 Jul 2022 02:31:59 +0000</pubDate>
      <link>https://forem.com/yanpiing/kubernets-32p6</link>
      <guid>https://forem.com/yanpiing/kubernets-32p6</guid>
      <description>&lt;p&gt;Kubernets é um orquestrado de containers, feito pela google ele veio do Borg que era uma ferramenta interna da empresa, um dos motivos da google criar o kubernets foi fazer a GCP (Google Cloud Provider) ficar mais competitiva com a AWS que na época dominava o mercado de cloud. Hoje em dia todas as grandes clouds dão suporte ao kubernets&lt;/p&gt;

&lt;p&gt;O kubernets é disponibilizado por um conjunto de APIS mas normalmente utilizamos ele pela CLI com o kubectl, o k8s(abreviação para kubernets) funciona de uma forma parecida com o docker, definimos um arquivo yaml onde passamos todas as configurações para o nosso pod e aplicamos esse yaml no kubernets onde ele sobe essas configurações.&lt;/p&gt;

&lt;p&gt;O k8s trabalha em formato de clusters (conjunto de maquinas), onde dentro desse cluster temos um node que é o master que quem vai controlar tudo o que os outros nodes vão fazer, esse node master tem os seguintes serviços rodando pra ele:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;control manager&lt;/li&gt;
&lt;li&gt;scheduler&lt;/li&gt;
&lt;li&gt;api server &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;e os outros nodes tem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kubelet&lt;/li&gt;
&lt;li&gt;kubeproxy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dinâmica
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sjN0pQo5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gqyoufypsuodyjho1p2a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sjN0pQo5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gqyoufypsuodyjho1p2a.png" alt="Image description" width="824" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Temos um cluster que é conjunto de maquinas onde cada uma dessas maquinas chamamos de nodes, cada maquina dessas possui uma quantidade de vCPU e Memória. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--80xK7DiG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3l54xmjelzed3rsvv3g8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--80xK7DiG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3l54xmjelzed3rsvv3g8.png" alt="Image description" width="880" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro do nosso cluster temos também os pods, os pods são unidades que contem os containers provisionados, eles representam os processos rodando no cluster, cada pod pode ter mais de um container, mas na maioria das vezes e inclusive todas as vezes que eu utilizei foi sempre um pod por container &lt;/p&gt;

&lt;p&gt;Temos também o Deployment que é um outro tipo de objeto do k8s que seu objetivo é provisionar os pods, mas para isso ele precisa saber quantas replicas desse pod precisamos, e para isso temos um replicaSet onde podemos informar quantas replicas de cada pod queremos, geralmente informamos isso na mesma descrição do deployment.&lt;/p&gt;

&lt;p&gt;O ReplicaSet funciona da seguinte forma, informamos quantos pods queremos de cada tipo, então por exemplo, quero 3 replicas para o meu serviço de pagamento, caso uma dessas replicas caia o replica set sobe outro pod igual no lugar imediatamente.&lt;/p&gt;

&lt;p&gt;Caso queira saber mais sobre quando utilizei o k8s pela primeira vez e principalmente como aprender a usar ele sem precisar gastar dinheiro com cloud para isso eu fiz esse &lt;a href="https://dev.to/yanpiing/usando-o-kubernets-pela-primeira-vez-1eoj"&gt;post a um tempo atrás&lt;/a&gt;&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>todayilearned</category>
      <category>kubernetes</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Extensão Gitflow</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Sat, 16 Jul 2022 04:19:17 +0000</pubDate>
      <link>https://forem.com/yanpiing/extensao-gitflow-3937</link>
      <guid>https://forem.com/yanpiing/extensao-gitflow-3937</guid>
      <description>&lt;h2&gt;
  
  
  Gitflow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S822ZYdX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfnjy5t9a8oxytzzlm8e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S822ZYdX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lfnjy5t9a8oxytzzlm8e.png" alt="Image description" width="602" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A ideia do GitFlow é que a branch master (hoje em dia o nome está sendo &lt;a href="https://www.theserverside.com/feature/Why-GitHub-renamed-its-master-branch-to-main#:~:text=GitHub%20took%20action%20based%20on,a%20different%20default%20for%20new"&gt;trocado para main&lt;/a&gt;) Vai ser a branch onde fica o sistema em produção para isso vamos ter uma branch auxiliar, no caso da imagem a branch "Develop" onde vamos subir os nossos códigos que vão ser produzidos a partir dessa branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5qfOzD25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztw42f239fjl18um27sg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5qfOzD25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztw42f239fjl18um27sg.png" alt="Image description" width="810" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois de um tempo a branch vamos ter uma segunda branch que vai ser a release onde vamos subir ela para produção, fazemos isso para poder continuar atualizando a branch develop.&lt;/p&gt;

&lt;p&gt;Uma exceção para esse fluxo é o hotfix, onde caso encontremos um bug em master que seja importante a resolução rápida, criamos uma nova branch a partir de master e fazemos o merge dela direto em master e em develop para garantir que os dois foram corrigidos.&lt;/p&gt;

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

&lt;p&gt;existe uma extensão para lidar com o gitflow ela pode ser instalada por esse link &lt;a href="https://github.com/petervanderdoes/gitflow-avh/wiki/Installing-on-Linux,-Unix,-etc"&gt;https://github.com/petervanderdoes/gitflow-avh/wiki/Installing-on-Linux,-Unix,-etc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;depois de instalarmos a extensão podemos rodar 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;git flow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e se ele retornar os comandos que pode usar está tudo certo.&lt;/p&gt;

&lt;p&gt;ao usarmos o&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git flow init 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ele vai pedir umas configurações para inicializar&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bZ2CAhwP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vvyhokui21rbb2vquvr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bZ2CAhwP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vvyhokui21rbb2vquvr.png" alt="Image description" width="678" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;e como usar a extensão? se quisermos criar uma nova feature a ideia é que vamos criar uma branch feature &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1l0z07qW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5d373bdjj8m5ajbyb7yg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1l0z07qW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5d373bdjj8m5ajbyb7yg.png" alt="Image description" width="729" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;perceba que a própria extensão criou uma nova branch com o prefixo de feature e me colocou nessa branch, criei um arquivo main.js nessa branch e isso era tudo que queria fazer nela, nesse caso vou rodar 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;git flow feature finish &amp;lt;nome_da_feature&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4r-pJCiN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gui6g9qrzoboikimw2qm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4r-pJCiN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gui6g9qrzoboikimw2qm.png" alt="Image description" width="688" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;a extensão já faz automaticamente o merge para a branch develop e me leva para ela. A continuação do fluxo é criar uma branch de release, então temos uma configuração para isso na extensão também&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git flow release start &amp;lt;versão_da_release&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TjFj_hnn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odch7h13814z1ovimj6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TjFj_hnn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odch7h13814z1ovimj6w.png" alt="Image description" width="717" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora podemos continuar criando features e passando elas para develop sem problemas &lt;/p&gt;

&lt;p&gt;e quando damos o finish no release ele vai pedir uma mensagem para o commit e uma tag e então vai fazer o merge direto com a main e com a develop para garantir a consistência&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fOPigFq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bayxwtjqx68enh8n34p6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fOPigFq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bayxwtjqx68enh8n34p6.png" alt="Image description" width="671" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O hotfix segue o mesmo padrão das outras, mas a diferença é que ele vai pedir uma tag quando usarmos o finish pois ele vai fazer um merge direto para main&lt;/p&gt;

&lt;h1&gt;
  
  
  Considerações
&lt;/h1&gt;

&lt;p&gt;Achei a extensão muito legal para conhecer e a forma que ela automatiza algumas coisas como a criação de novas branches já com o prefixo e a deleção dessas branches ao serem finalizadas , mas acabei não gostando dos merges automáticos para dev e master, no contexto do dia a dia acabo preferindo muito mais fazer pull requests ou no caso do gitlab merge requests para que os outros devs da equipe possam fazer os code reviews e garantir a qualidade do código&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Kafka Connect</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Fri, 08 Jul 2022 21:16:32 +0000</pubDate>
      <link>https://forem.com/yanpiing/kafka-connect-3i52</link>
      <guid>https://forem.com/yanpiing/kafka-connect-3i52</guid>
      <description>&lt;p&gt;Kafka connect é um componente do Apache Kafka que trabalha como um hub de dados centralizados para integrações simples, então ele serve muito para pegar dados de um lado e jogar para um banco de dados ou alguma outra aplicação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dinâmica
&lt;/h2&gt;

&lt;p&gt;O Kafka vai ter connectors que podem estar ligados a data sources ou Sinks, esse conector vai constantemente pegar os dados de um data source como um postgres por exemplo em um topico do kafka e desse topico para um Sink como um ElasticSearch&lt;/p&gt;

&lt;h3&gt;
  
  
  Standalone Workers
&lt;/h3&gt;

&lt;p&gt;O Kafka connect é formado a partir de workers que são na verdade maquinas que rodam tarefas ou seja eles ficam pegando os dados de um sistema A e guardando no Kafka ou pegando do kafka e jogadno em um sistema B, esses workers podem ter mais de uma tarefa para que eles rodem em paralelo&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed Workers
&lt;/h3&gt;

&lt;p&gt;Nesse caso os workers vão trabalhar em um cluster onde as maquinas vão se ajudar a trabalhar nas tarefas, por exemplo, se tivermos uma tarefa com mais de uma partição, podemos deixar esses workers cada um lendo de uma partição semelhante como o consumer do próprio kafka funciona. No caso de workers distribuídos os workers individualmente podem executar mais de uma tarefa também.&lt;/p&gt;

&lt;h2&gt;
  
  
  Converters
&lt;/h2&gt;

&lt;p&gt;As Tarefas usam os converters para mudar o formato dos dados para leitura ou escrita no kafka então podemos informar o tipo dos dados que estamos trabalhando, evitando assim o problema de por exemplo termos um int que acabou sendo convertido de forma errônea para string, temos algumas opções de formatos de dados como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avro&lt;/li&gt;
&lt;li&gt;Protobuf (dados binarios)&lt;/li&gt;
&lt;li&gt;JsonSchema&lt;/li&gt;
&lt;li&gt;Json &lt;/li&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;ByteArray&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TIJcsVh2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/svyazttzqcck12jfuc5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TIJcsVh2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/svyazttzqcck12jfuc5z.png" alt="Image description" width="832" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nessa imagem temos um exemplo mais ou menos de como funciona o connect pega os dados e converte para o formato Avro e salva no Kafka, e então o o conector do Sink pega esses dados converte para outro formato e joga de volta para a Sink&lt;/p&gt;

&lt;h2&gt;
  
  
  DLQ - Dead Letter Queue
&lt;/h2&gt;

&lt;p&gt;Quando tem um registro invalido o erro pode ser tratado na configuração do conector. Porem esse tipo de configuração só pode ser realizado para conectores do tipo Sink, que são dados que já estão no Kafka.&lt;/p&gt;

&lt;p&gt;Temos alguns tipos de tolerancia para esses errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;none: Caso dê erro a tarefa vai falhar, porem ela vai fazer a tarefa parar&lt;/li&gt;
&lt;li&gt;all: Ignora os errors e continua com a tarefa (porem dessa forma não vai ficar nos logs esse errors, vai ser de fato completamente ignorado)&lt;/li&gt;
&lt;li&gt;errors.deadleatterqueue.topic.name = : com a tolerância de errors como all e essa configuração, todas as vezes que der erro vamos pegar a mensagem e jogar no tópico que passamos o nome, e no header da mensagem vai ter o erro que o kafka connect encontrou&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>todayilearned</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Kafka</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Fri, 01 Jul 2022 22:25:21 +0000</pubDate>
      <link>https://forem.com/yanpiing/kafka-3ll7</link>
      <guid>https://forem.com/yanpiing/kafka-3ll7</guid>
      <description>&lt;p&gt;O Kafka é uma plataforma distribuída de streaming de eventos. Além disso ele é open source e utilizado por milhares de empresas.&lt;/p&gt;

&lt;p&gt;Hoje em dia tudo é evento e o kafka nos ajuda a processar esses eventos de forma rápida, fácil e resiliente. O kafka por padrão salva os eventos que passam por ele para guardar histórico, inclusive podem ser utilizados como um storage, nesse &lt;a href="https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying"&gt;post do blog do linkedin&lt;/a&gt; de 2013 o Jay Kreps fala uma pouco mais sobre isso (curiosidade: O Kafka nasceu no Linkedin).&lt;/p&gt;

&lt;h2&gt;
  
  
  Poderes do Kafka
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Altíssimo throughput: Ele tem uma capacidade muito alta de ser bombardeado por requisições&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Latência extremamente baixa (2ms): Leva muito pouco tempo para uma informação ser trafegada nele&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Escalável&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Armazenamento&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alta disponibilidade&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Existe driver para quase qualquer linguagem&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bibliotecas prontas para mais diversas tecnologias&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ferramentas open-source, ex: kafka-connect, kafka-streams, ksqldb&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Como funciona
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1j7TZPKk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc74kf0a0o7h63cvb7c6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1j7TZPKk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc74kf0a0o7h63cvb7c6.png" alt="Image description" width="827" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A dinâmica básica é um produtor de mensagem de um lado e um consumidor dessa mensagem dos outros  porem ao invés do produtor mandar a mensagem direto para o consumidor ele enviar para o kafka (que na verdade é um cluster de brokers), e então o broker salva o valor em seu banco de dados e então o consumer acessa esse cluster e pega essa nova mensagem. Existe uma concepção errada que inclusive eu tinha de que o kafka envia a mensagem para o consumer mas na verdade o consumer que vai buscar pela mensagem.&lt;/p&gt;

&lt;p&gt;A recomendação mínima para colocar o kafka em produção são 3 brokers, para gerenciar todas as questões com relação a esses brokers como: ver se a maquina está rodando, em qual maquina vai ser armazenado a mensagem e etc temos o apache zookeeper que também é um sistema open source da apache, porem atualmente o plano é retirar o zookeeper e deixar o kafka totalmente independente&lt;/p&gt;

&lt;h2&gt;
  
  
  Tópicos
&lt;/h2&gt;

&lt;p&gt;Tópico é o canal de comunicação responsável por receber e disponibilizar os dados enviados para o kafka, então quando o producer envia uma mensagem para um broker na verdade ele envia para um tópico desse broker e o consumer também lê as mensagens desse tópico. Podemos inclusive ter mais de um consumer lendo mensagens de um mesmo tópico, então podemos por exemplo ter um sistema de logs, e o sistema de evento lendo as mesmas mensagens do tópico.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PiV2C4f0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l11awb1tx43p31dz7sqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PiV2C4f0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l11awb1tx43p31dz7sqp.png" alt="Image description" width="880" height="480"&gt;&lt;/a&gt;&lt;br&gt;
Cada mensagem enviada para um tópico é armazenada uma depois da outra em ordem de chegada, para cada mensagem armazenada ela recebe um offset que é sua posição nesse array de mensagens. Dois consumers podem estar em diferentes offsets de um mesmo tópico sem problema algum&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomia de uma mensagem
&lt;/h2&gt;

&lt;p&gt;Uma mensagem é composta por 4 partes principais&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Headers
&lt;/h4&gt;

&lt;p&gt;São dados opcionais que podemos trabalhar como se fossem metadados que podemos passar para nos ajudar&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Key
&lt;/h4&gt;

&lt;p&gt;Como o nome diz é a chave da mensagem, é um conceito um pouco complicado de explicar que no começo me confundiu bastante, mas pense que ela é um parâmetro não obrigatório que podemos passar quando queremos garantir uma ordem de chegada de mensagens em um determinado contexto. Depois vou explicar com um exemplo.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Value
&lt;/h4&gt;

&lt;p&gt;Como o nome já diz é conteúdo da mensagem, os valores que enviamos naquela mensagem&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Timestamp
&lt;/h4&gt;

&lt;p&gt;Marca quando a mensagem foi enviada&lt;/p&gt;

&lt;h2&gt;
  
  
  Partições
&lt;/h2&gt;

&lt;p&gt;Cada tópico pode ter uma ou mais partições para garantir a distribuição e resiliência dos dados. Para evitar deixar todos os dados em um mesmo broker o kafka faz varias partições para um mesmo tópico em diferentes brokers para que assim caso um broker caia não aconteça de nenhum consumer conseguir ler essas mensagens. &lt;/p&gt;

&lt;p&gt;Outro beneficio de aumentar as partições é que podemos ter mais de uma replica de consumer lendo de um topico cada uma pode se conectar com uma partição e ler todas as mensagens dessa partição, multiplicando assim sua velocidade.&lt;/p&gt;

&lt;p&gt;Ex: Temos 1.000.000 de pagamentos em um tópico e apenas um serviço de processar esses pagamentos, esse serviço vai ter que então ler essas 1.000.000 mensagens para processarmos todos os pagamentos, mas e se replicarmos esse serviço? ai temos um problema de garantir que esses dois serviços não vão acabar lendo as mesmas mensagens, agora se adicionarmos mais uma partição e dividirmos 500.000 mensagens para cada, cada consumer pode se conectar em uma partição e vamos processar essas mensagens no dobro da velocidade incial&lt;/p&gt;

&lt;h2&gt;
  
  
  Como funciona a Key
&lt;/h2&gt;

&lt;p&gt;Vamos imaginar uma operação de compras onde a ordem é bem importante de ser mantida, então quando o cliente faz uma compra nós enviamos uma mensagem com uma key que pode ser um uuid gerado para representar essa compra, a partir de agora todas as mensagens que chegarem com essa key o kafka vai GARANTIR que vai manter a ordem de chegada mantendo essas mensagens com a mesma key na mesma partição, evitando assim de acontecer por exemplo a mensagem de emitir uma nota fiscal vir primeiro que a de aprovar pagamento. &lt;/p&gt;

&lt;p&gt;O consumidor que for ler a partição sempre vai pegar essas mensagens na ordem correta, diferente de se por exemplo elas estivessem em diferentes partições que não temos como garantir que um consumidor não vai consumir mais rápido que o outro gerando assim uma ordem errada de processamento&lt;/p&gt;

&lt;h2&gt;
  
  
  Replication Factor e Partition Leadership
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wqJv0S_U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qdl349483mmjqdozj32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wqJv0S_U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qdl349483mmjqdozj32.png" alt="Image description" width="880" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Trabalhando com partições já temos uma boa solução para como manter os dados distribuídos porem ainda não temos uma resiliencia total, pois se um broker cair vamos ter uma perda temporaria dos dados daquela partição o que pode ser tolerado, porem se o broker perder o hd por exemplo vamos ter uma perda definitiva daqueles dados o que não pode ser tolerado.&lt;/p&gt;

&lt;p&gt;Podemos então utilizar o replication factor, onde informamos quantas replicas de cada partição queremos, na imagem podemos ver que temos 1 copia de cada partição e sempre essa copia em brokers diferentes, assim, caso aconteça algo com o broker 1 por exemplo ainda temos todos os dados dele replicados nos brokers 2 e 3&lt;/p&gt;

&lt;p&gt;Sempre que replicamos as partições teremos uma partição líder e sempre que o consumidor for ler dessa partição ele vai ler também da partição líder. Somente se a partição líder cair que o Kafka vai fazer um novo sorteio e definir qual a nova partição que será a líder&lt;/p&gt;

&lt;h2&gt;
  
  
  Garantia de entrega das mensagens
&lt;/h2&gt;

&lt;p&gt;Quando o producer envia uma mensagem para o tópico ele pode configurar um parâmetro que é o Ack.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ack 0&lt;/strong&gt;: o producer informa que ele não precisa saber se a mensagem de fato chegou, isso também é chamado de FF: Fire and Forget onde simplesmente passamos a mensagem para o tópico sem se importar se ele recebeu ou não&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ack 1&lt;/strong&gt;: o producer envia uma mensagem e espera que a partição líder responda informando que salvou a mensagem. Ainda temos o risco de perder a mensagem caso o líder caia antes de replicar as mensagens para os seus seguidores&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ack -1&lt;/strong&gt;: O producer envia a mensagem, o líder salva essa mensagem, replica para os seguidores os seguidores avisam que salvaram e só então ele responde ao producer informando que salvou, é a forma de ter 100% de certeza que a mensagem foi salva&lt;/p&gt;

&lt;p&gt;Garantias de entrega no consumer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At most once&lt;/strong&gt;: O consumer vai receber as mensagens no máximo uma vez, é a forma mais performática porem pode perder mensagens no meio do caminho&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At least once&lt;/strong&gt;: O consumer vai receber as mensagens pelo menos uma vez, assim é garantido que ele vai receber, tem um tempo de processamento moderado mas é preciso garantir que o consumer sabe o que fazer ao receber uma mensagem repetida&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exactly once&lt;/strong&gt;: O consumer vai receber as mensagens exatamente uma vez. Essa forma tem a pior performance pois o kafka tem que garantir que o consumidor recebeu a mensagem que ele enviou e q ele ainda não recebeu a mensagem que ele vai enviar&lt;/p&gt;

&lt;h2&gt;
  
  
  Consumer Group
&lt;/h2&gt;

&lt;p&gt;Vamos supor um cenário com mais partições do que consumidores porem os consumidores estão em um mesmo grupo, nesse caso eles vão se dividir para ler as partições, agora vamos imaginar mais um consumidor que não está nesse mesmo grupo, esse consumidor vai ler de todas as partições. Agora se no nosso grupo tivermos mais consumers do que partições o que acontece é que esses consumers extra ficam esperando uma partição livre para que eles leiam, em um mesmo grupo nunca vai ter mais de um consumer por partição&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Fazendo deploy com o kubernets no GCP</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Thu, 30 Jun 2022 01:00:23 +0000</pubDate>
      <link>https://forem.com/yanpiing/fazendo-deploy-com-o-kubernets-no-gcp-3kjo</link>
      <guid>https://forem.com/yanpiing/fazendo-deploy-com-o-kubernets-no-gcp-3kjo</guid>
      <description>&lt;p&gt;Com uma conta ativa e com faturamento ativo no google cloud provider podemos procurar pelo kubernets engine na barra de pesquisa e ativar essa opção.&lt;/p&gt;

&lt;p&gt;Com ela ativa podemos criar um cluster do tipo standard, dentro das configurações do cluster q vou criar somente mudei o nome e o numero de nós de 3 para 2&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eT1K19nY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h7y4b0g12wlmdntzekm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eT1K19nY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h7y4b0g12wlmdntzekm1.png" alt="Image description" width="880" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como quero fazer esse teste com o kafka fui no confluent cloud e criei uma conta lá, e subi um cluster gratuito no google cloud por lá&lt;/p&gt;

&lt;p&gt;Em seguida para continuar &lt;a href="https://cloud.google.com/sdk/docs/install#deb"&gt;instalei o cli do google cloud&lt;/a&gt; mas não é obrigatório, se quiser abaixo de onde o google cloud coloca a string de conexão ele também dá a opção de usar o terminal online&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S-5bJvf3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9f3netw3eidwaaezxvvv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S-5bJvf3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9f3netw3eidwaaezxvvv.png" alt="Image description" width="880" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois de feita a conexão podemos testar rodar o &lt;code&gt;kubectl get nodes&lt;/code&gt; e então o output deve ser os nodes lá do GCP&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kp3rRqAQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qopiabw8chj20bbmp6cp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kp3rRqAQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qopiabw8chj20bbmp6cp.png" alt="Image description" width="880" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;depois disso criei uma pasta para colocar os arquivos k8s do meu simulador então criei um deploy.yml &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;se quiser saber mais sobre deployment pode ir no meu &lt;a href="https://dev.to/yanpiing/usando-o-kubernets-pela-primeira-vez-1eoj"&gt;post sobre kubernets&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simulator&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simulator&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simulator&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simulator&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yansb/codedelivery:latest&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simulator-volume&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/go/src/.env&lt;/span&gt;
              &lt;span class="na"&gt;subPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;


      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simulator-volume&lt;/span&gt;
          &lt;span class="na"&gt;configMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simulator-conf&lt;/span&gt;
            &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env&lt;/span&gt;
                &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;e um configmap.yml que tem minhas variáveis de ambiente&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;yml&lt;br&gt;
apiVersion: v1&lt;br&gt;
kind: ConfigMap&lt;br&gt;
metadata:&lt;br&gt;
  name: simulator-conf&lt;br&gt;
data:&lt;br&gt;
  env: |&lt;br&gt;
    KafkaReadTopic=route.new-direction&lt;br&gt;
    KafkaProduceTopic=route.new-position&lt;br&gt;
    KafkaBootstrapServers=&lt;br&gt;
    KafkaConsumerGroupId=simulator&lt;br&gt;
    security.protocol=SASL_SSL&lt;br&gt;
    sasl.mechanisms=PLAIN&lt;br&gt;
    sasl.username=&lt;br&gt;
    sasl.password=&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;p&gt;depois de criados esses arquivos temos que rodar os comandos &lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl apply -f k8s/simulator/configmap.yml&lt;/code&gt;&lt;br&gt;
&lt;code&gt;kubectl apply -f k8s/simulator/deploy.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;e agora nossos pods já estão subindo &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yIMlS3EQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4cucpb45iiaafrp1uln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yIMlS3EQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4cucpb45iiaafrp1uln.png" alt="Image description" width="451" height="49"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E como a aplicação q eu subi foi o simulator que está conectado no kafka posso verificar que o pod está online pelo confluent cloud&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rSjRf-HR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y4u333hktfrg08jc06eq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rSjRf-HR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y4u333hktfrg08jc06eq.png" alt="Image description" width="880" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ele já está conectado, recebendo e mandando mensagens.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>todayilearned</category>
      <category>googlecloud</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Observabilidade com kafka connect e elasticsearch</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Fri, 24 Jun 2022 21:15:15 +0000</pubDate>
      <link>https://forem.com/yanpiing/observabilidade-com-kafka-connect-e-elasticsearch-30lb</link>
      <guid>https://forem.com/yanpiing/observabilidade-com-kafka-connect-e-elasticsearch-30lb</guid>
      <description>&lt;h2&gt;
  
  
  Kafka connect
&lt;/h2&gt;

&lt;p&gt;O kafka connect é um serviço do kafka que serve para pegar dados de um serviço e jogar para um outro.&lt;/p&gt;

&lt;p&gt;Por exemplo pegar os dados do meu banco de dados e passar para um arquivo txt, ou para um elastic search ou algo desse tipo&lt;/p&gt;

&lt;p&gt;O kafka connect é um cluster com diversas maquinas que realizam essas tarefas, essas maquinas são chamadas de worker sendo que cada worker pode lidar com mais de uma tarefa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dashboard do kafka
&lt;/h2&gt;

&lt;p&gt;Irei deixar o yml do compose no final do post. Mas uma coisa q ele faz é colocar o control center da confluent na porta 9021 e é isso q vamos abrir.&lt;/p&gt;

&lt;p&gt;No menu lateral do dashboard tem a opção de connectors onde ele mostra todos os clusters do kafka connect conectados atualmente, de inicio não vai ter nenhum, ainda temos que fazer essa conexão, quando subir o docker-compose vai perceber que ele vai criar duas pastas no seu diretório atual &lt;code&gt;data&lt;/code&gt; e &lt;code&gt;es01&lt;/code&gt; essas pastas vão ser usadas para manter as configurações. Porem além delas também vamos criar uma pasta connectors com um arquivo &lt;code&gt;elasticsearch.properties&lt;/code&gt;, nesse arquivo vamos definir algumas configurações como o nome do desse conector, a classe dele, os tópicos que esse conector vai ouvir, a url de conexão, o tipo dos documentos e o conversor de valores para que os dados cheguem como json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;name=elasticsearch-sink&lt;/span&gt;
&lt;span class="s"&gt;connector.class=io.confluent.connect.elasticsearch.ElasticsearchSinkConnector&lt;/span&gt;
&lt;span class="s"&gt;topics=route.new-direction,route.new-position&lt;/span&gt;
&lt;span class="s"&gt;connection.url=http://es01:9200&lt;/span&gt;
&lt;span class="s"&gt;type.name=_doc&lt;/span&gt;
&lt;span class="s"&gt;value.converter=org.apache.kafka.connect.json.JsonConverter&lt;/span&gt;
&lt;span class="s"&gt;value.converter.schemas.enable=false&lt;/span&gt;
&lt;span class="s"&gt;schema.ignore=true&lt;/span&gt;
&lt;span class="s"&gt;key.ignore=true&lt;/span&gt;
&lt;span class="s"&gt;transforms=InsertField&lt;/span&gt;
&lt;span class="s"&gt;transforms.InsertField.type=org.apache.kafka.connect.transforms.InsertField$Value&lt;/span&gt;
&lt;span class="s"&gt;transforms.InsertField.timestamp.field=timestamp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com esse arquivo criado podemos voltar ao dashboard na parte de conectores e adicionar um novo conector fazendo o upload dele. Se tudo der certo (caso algo dê errado escrevi o que aconteceu de errado comigo e como solucionei no final do post) na parte de connectors ele vai exibir um connector como running &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3FJBZLqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23guyhcbzt8k6vnftqa9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3FJBZLqY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23guyhcbzt8k6vnftqa9.png" alt="Image description" width="880" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se formos agora no Kibana, que está na porta 5601 podemos abrir o menu lateral e  ir em  Stack Management &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6mvSFw6H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jkbxf2j4c4vr2klnm3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6mvSFw6H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jkbxf2j4c4vr2klnm3r.png" alt="Image description" width="292" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nessa pagina temos o Index Management que vai nos mostrar já os dois tópicos que selecionamos pra ele escutar. E temos também o Index Patterns.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HcrVaccF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2jx83go8n6u6x5yrifo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HcrVaccF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i2jx83go8n6u6x5yrifo.png" alt="Image description" width="279" height="717"&gt;&lt;/a&gt;&lt;br&gt;
Onde vamos criar um novo index-patern com base nos  nossos tópicos, se eles já tiverem recebido uma mensagem com o kibana rodando quando criarmos o pattern ele já vai vai vir com os campos desse tópico&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mP4vSJlO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bn6f0xte20sj0t8zqzjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mP4vSJlO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bn6f0xte20sj0t8zqzjt.png" alt="Image description" width="880" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora se formos no menu lateral do kibana e clickar na parte de analytics ele já vai passar a mostrar todas as mensagem que recebemos em cada tópico&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZXnds-81--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zyhtsajmnvgqfnee6949.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZXnds-81--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zyhtsajmnvgqfnee6949.png" alt="Image description" width="321" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kj3pXbW8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ej4r5g8sm562udgh27o8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kj3pXbW8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ej4r5g8sm562udgh27o8.png" alt="Image description" width="880" height="403"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Adicionando os tipos dos campos
&lt;/h2&gt;

&lt;p&gt;Para ficar com os index melhor formatados apaguei os que foram gerados automaticamente e fui na parte de devTools do menu do kibana, lá escrevi os seguintes comandos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUT route.new-position
{
  "mappings": {
   "properties": {
      "clientId": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "routeId": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "timestamp": {
        "type": "date"
      },
      "finished": {
        "type": "boolean"
      },
      "position": {
        "type": "geo_point"
      }
    }
  } 
}

PUT route.new-direction
{
  "mappings": {
   "properties": {
      "clientId": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "routeId": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "timestamp": {
        "type": "date"
      }
    }
  } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora o position vai ser lido como uma localização ao invés de numero como estava antes e podemos visualizar ele no mapa &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j5GBdsKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ntx5cyjm0owxjfa8h5vu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j5GBdsKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ntx5cyjm0owxjfa8h5vu.png" alt="Image description" width="880" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;clickando em visualize vamos para o mapa onde podemos visualizar esses positions no mapa&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---CDuitjv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l4o3afc3jstid95z8muw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---CDuitjv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l4o3afc3jstid95z8muw.png" alt="Image description" width="880" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando visualizações
&lt;/h2&gt;

&lt;p&gt;Na opção de visualizações vamos criar uma nova visualização do tipo Lens &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ob2G5JP2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ked50o7tbxy3kcswyixv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ob2G5JP2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ked50o7tbxy3kcswyixv.png" alt="Image description" width="880" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro da parte de visualizações podemos adicionar os dados que queremos e exibir-los da forma desejada&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ia_1bKPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kjg2oz73wmij4lgqcscl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ia_1bKPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kjg2oz73wmij4lgqcscl.png" alt="Image description" width="880" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então por exemplo, coloquei o contador de records do tópico new-direction, mudei seu tipo para métrica e coloquei o nome de &lt;code&gt;corridas&lt;/code&gt; e então salvei.&lt;/p&gt;

&lt;p&gt;Criei também a visualização de mapa e por fim criei um dashboard com todas essas informações&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VaZmjio8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bspbpsus6zty797u74pl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VaZmjio8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bspbpsus6zty797u74pl.png" alt="Image description" width="880" height="265"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker-compose
&lt;/h2&gt;

&lt;p&gt;Aqui o docker compose que usei para aprender, lembre de trocar o ip para o seu próprio, caso não saiba qual o ip pode rodar esse comando &lt;br&gt;
&lt;code&gt;docker run -it --rm alpine nslookup host.docker.internal&lt;/code&gt; que o docker te informa qual o ip&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  

  &lt;span class="na"&gt;zookeeper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-zookeeper:latest&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ZOOKEEPER_CLIENT_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2181&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:192.168.65.2"&lt;/span&gt;

  &lt;span class="na"&gt;kafka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-kafka:latest&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zookeeper&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9092:9092"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9094:9094"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_BROKER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ZOOKEEPER_CONNECT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zookeeper:2181&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_INTER_BROKER_LISTENER_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL://:9092,OUTSIDE://:9094&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL://kafka:9092,OUTSIDE://host.docker.internal:9094&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INTERNAL:PLAINTEXT,OUTSIDE:PLAINTEXT&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:192.168.65.2"&lt;/span&gt;

  &lt;span class="na"&gt;kafka-topics-generator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-kafka:latest&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;bash -c&lt;/span&gt;
        &lt;span class="s"&gt;"sleep 5s &amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="s"&gt;kafka-topics --create --topic=route.new-direction --if-not-exists --bootstrap-server=kafka:9092 &amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="s"&gt;kafka-topics --create --topic=route.new-position --if-not-exists --bootstrap-server=kafka:9092"&lt;/span&gt;

  &lt;span class="na"&gt;control-center&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-enterprise-control-center:6.0.1&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;control-center&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9021:9021"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CONTROL_CENTER_BOOTSTRAP_SERVERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;kafka:9092'&lt;/span&gt;
      &lt;span class="na"&gt;CONTROL_CENTER_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;CONTROL_CENTER_CONNECT_CLUSTER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://kafka-connect:8083&lt;/span&gt;
      &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9021&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:192.168.65.2"&lt;/span&gt;

  &lt;span class="na"&gt;kafka-connect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-kafka-connect-base:6.0.0&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka-connect&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zookeeper&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8083:8083&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_BOOTSTRAP_SERVERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kafka:9092"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_REST_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8083&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_GROUP_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka-connect&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_CONFIG_STORAGE_TOPIC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;_connect-configs&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_OFFSET_STORAGE_TOPIC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;_connect-offsets&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_STATUS_STORAGE_TOPIC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;_connect-status&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_KEY_CONVERTER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.apache.kafka.connect.storage.StringConverter&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_VALUE_CONVERTER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.apache.kafka.connect.json.JsonConverter&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_INTERNAL_KEY_CONVERTER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;org.apache.kafka.connect.json.JsonConverter"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_INTERNAL_VALUE_CONVERTER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;org.apache.kafka.connect.json.JsonConverter"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_REST_ADVERTISED_HOST_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kafka-connect"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_LOG4J_ROOT_LOGLEVEL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INFO"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_LOG4J_LOGGERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;org.apache.kafka.connect.runtime.rest=WARN,org.reflections=ERROR"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_LOG4J_APPENDER_STDOUT_LAYOUT_CONVERSIONPATTERN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[%d]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%p&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%X{connector.context}%m&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(%c:%L)%n"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_STATUS_STORAGE_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
      &lt;span class="c1"&gt;# # Optional settings to include to support Confluent Control Center&lt;/span&gt;
      &lt;span class="c1"&gt;#   CONNECT_PRODUCER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringProducerInterceptor"&lt;/span&gt;
      &lt;span class="c1"&gt;#   CONNECT_CONSUMER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringConsumerInterceptor"&lt;/span&gt;
      &lt;span class="c1"&gt;#  ---------------&lt;/span&gt;
      &lt;span class="na"&gt;CONNECT_PLUGIN_PATH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/share/java,/usr/share/confluent-hub-components,/data/connect-jars&lt;/span&gt;
    &lt;span class="c1"&gt;# If you want to use the Confluent Hub installer to d/l component, but make them available&lt;/span&gt;
    &lt;span class="c1"&gt;# when running this offline, spin up the stack once and then run :&lt;/span&gt;
    &lt;span class="c1"&gt;#   docker cp kafka-connect:/usr/share/confluent-hub-components ./data/connect-jars&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;$PWD/data:/data&lt;/span&gt;
    &lt;span class="c1"&gt;# In the command section, $ are replaced with $$ to avoid the error 'Invalid interpolation format for "command" option'&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "Installing Connector"&lt;/span&gt;
        &lt;span class="s"&gt;confluent-hub install --no-prompt confluentinc/kafka-connect-elasticsearch:10.0.1&lt;/span&gt;
        &lt;span class="s"&gt;#&lt;/span&gt;
        &lt;span class="s"&gt;echo "Launching Kafka Connect worker"&lt;/span&gt;
        &lt;span class="s"&gt;/etc/confluent/docker/run &amp;amp;&lt;/span&gt;
        &lt;span class="s"&gt;#&lt;/span&gt;
        &lt;span class="s"&gt;sleep infinity&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:192.168.65.2"&lt;/span&gt;

  &lt;span class="na"&gt;es01&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/elasticsearch/elasticsearch:7.11.2&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;es01&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node.name=es01&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cluster.name=es-docker-cluster&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cluster.initial_master_nodes=es01&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bootstrap.memory_lock=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ES_JAVA_OPTS=-Xms512m&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-Xmx512m"&lt;/span&gt;
    &lt;span class="na"&gt;ulimits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;memlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;soft&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-1&lt;/span&gt;
        &lt;span class="na"&gt;hard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-1&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./es01:/usr/share/elasticsearch/data&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;9200:9200&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:192.168.65.2"&lt;/span&gt;

  &lt;span class="na"&gt;kibana&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/kibana/kibana:7.11.2&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kib01&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5601:5601&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ELASTICSEARCH_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://es01:9200&lt;/span&gt;
      &lt;span class="na"&gt;ELASTICSEARCH_HOSTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;["http://es01:9200"]'&lt;/span&gt;
    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:192.168.65.2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Problemas que encontrei
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ao tentar rodar o docker-compose depois de criar o es01 precisei alterar as permissoes dessa pasta pois ela não estava deixando o docker do elastic criar os arquivos dentro dela&lt;br&gt;
&lt;code&gt;sudo chown -R 1000:1000 es01&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ao subir o elasticsearch ele reclama do meu vm.max_map_count, tive que redefinir essa variavel no meu sistema rodando o comando: &lt;br&gt;
&lt;code&gt;sysctl -w vm.max_map_count=262144&lt;/code&gt;, porem isso só dura a sessão atual, se quiser uma solução mais duradoura nessa pagina encontrei tambem&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/51445846/elasticsearch-max-virtual-memory-areas-vm-max-map-count-65530-is-too-low-inc"&gt;https://stackoverflow.com/questions/51445846/elasticsearch-max-virtual-memory-areas-vm-max-map-count-65530-is-too-low-inc&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>todayilearned</category>
      <category>elasticsearch</category>
    </item>
    <item>
      <title>RabbitMQ</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Tue, 21 Jun 2022 02:02:03 +0000</pubDate>
      <link>https://forem.com/yanpiing/rabbitmq-goc</link>
      <guid>https://forem.com/yanpiing/rabbitmq-goc</guid>
      <description>&lt;p&gt;O RabbitMQ é um Message broker, ele faz o meio de campo entre a pessoa que envia a mensagem a pessoa q vai receber a mensagem. Ele implementa os protocolos AMQP, MQTT, STOMP e HTTP, sendo que o mais utilizado é o AMQP, que é baseado no TCP deixando o assim com uma velocidade muito rápida. Ele foi desenvolvido em Erlang, facilita o processo de desacoplamento entre os serviços pois ele que vai lidar com a comunicação entre esses serviços, ele é extremamente rápido e poderoso, além disso ele tem I/O por padrão diferente do Kafka que temos que implementar técnicas para isso. &lt;/p&gt;

&lt;h2&gt;
  
  
  Por baixo dos panos
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--58nxyKGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u5vds9ia8obzcoxau5w7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--58nxyKGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u5vds9ia8obzcoxau5w7.png" alt="Image description" width="880" height="435"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Temos um client e um server, e essa conexão acontece por padrão por TCP, que de inicio é um pouco lenta, mas para evitar esse processo toda vez que formos no conectar e consumir uma fila no RabbitMQ ele abre apenas uma conexão e dentro dessa conexão ele cria subconexões que são chamadas de channels. Evitando assim todo o processo de abertura de conexão, isso é chamado de multiplexing connection, todo channel aberto também é uma nova thread&lt;/p&gt;

&lt;h2&gt;
  
  
  Funcionamento Básico
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zEl6Gb1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvtw44gprrlihej3q7g6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zEl6Gb1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvtw44gprrlihej3q7g6.png" alt="Image description" width="880" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Temos um Publisher que como o nome já diz é o cara que vai publicar a mensagem e o consumidor que é quem vai ler a mensagem. Porem o publisher não envia a mensagem diretamente para o consumidor, ele envia para uma exchange que pega a mensagem que o publisher mandou, processa a mensagem e descobre para qual fila a mensagem deveria ser enviada e ai envia a mensagem para essa fila, e então o consumidor fica lendo essa fila de mensagens &lt;/p&gt;

&lt;h2&gt;
  
  
  Tipos de Exchange
&lt;/h2&gt;

&lt;p&gt;Em um sistema podemos ter n filas e n exchanges, sendo que n filas podem estar conectadas com n exchanges e n exchanges podem estar conectados com n filas&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Direct&lt;br&gt;
A exchange manda a mensagem especificamente para uma determinada fila&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fanout&lt;br&gt;
Quando manda uma mensagem pra essa exchange ela envia essa mensagem para todas as filas ligadas a essa exchange&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Topic&lt;br&gt;
Adicionamos algumas regras para dependendo do routing key ela encaminhar seguindo essa regra&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Headers&lt;br&gt;
O header da mensagem determina em qual fila queremos que a mensagem seja entregue&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Direct Exchange
&lt;/h3&gt;

&lt;p&gt;Na mensagem vamos especificar qual a routing Key da fila que queremos enviar a mensagem e então o exchange faz somente o processo de encaminhar a mensagem para a fila com o mesmo routing key&lt;/p&gt;

&lt;h3&gt;
  
  
  Fanout Exchange
&lt;/h3&gt;

&lt;p&gt;Nesse caso não passamos nenhuma routing key, enviamos apenas uma mensagem e essa mensagem vai ser replicada para todas as filas vinculadas a essa exchange&lt;/p&gt;

&lt;p&gt;Muito útil por exemplo em um sistema de compras onde queremos informar a diversos sistemas que a compra ocorreu como o sistema de estoque, administrativo, logs, nota fiscal e etc... Basta conectarmos todos esses sistemas na mesma exchange que ela já encaminha a mensagem para todos&lt;/p&gt;

&lt;h3&gt;
  
  
  Topic Exchange
&lt;/h3&gt;

&lt;p&gt;Ele também funciona com as routing keys porem nesse caso as routing keys conseguem ter regras semelhantes a RegEx, e a exchange vai procurar quais as filas que dão match nessa RegEx&lt;/p&gt;

&lt;h2&gt;
  
  
  Queues
&lt;/h2&gt;

&lt;p&gt;As filas trabalham no padrão FIFO (First in First Out)&lt;/p&gt;

&lt;h3&gt;
  
  
  Propriedades
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Durable: Se ela deve ou não ser salva depois do restart do broker por padrão elas vem como duráveis&lt;/li&gt;
&lt;li&gt;Auto-delete: Removida automaticamente quando o consumer se desconecta&lt;/li&gt;
&lt;li&gt;Expiry: Define o tempo que não há mensagens ou clientes consumindo&lt;/li&gt;
&lt;li&gt;Message TTL: Tempo de vida da mensagem&lt;/li&gt;
&lt;li&gt;Max length ou bytes: Quantidade de mensagens que podem ir para uma fila ou o tamanho de bytes máximo permitido&lt;/li&gt;
&lt;li&gt;Overflow: O que fazer quando a fila encher

&lt;ul&gt;
&lt;li&gt;Drop Head (remove a última)&lt;/li&gt;
&lt;li&gt;Reject publish (não aceita novas mensagens)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Exclusive: Somente o channel que criou pode acessar&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Dead letter queues
&lt;/h3&gt;

&lt;p&gt;Algumas mensagens não conseguem ser entregues por algum motivo. Essas mensagens são encaminhadas para uma exchange especifica que roteia elas para uma dead letter queue, e então elas podem ser consumidas e averiguadas posteriormente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lazy queues
&lt;/h3&gt;

&lt;p&gt;Quando o RabbitMQ chega no limite da memoria as mensagens passam a ser armazenadas em disco. Porem o ponto negativo é que exige um alto I/O, quando há muitas mensagens em uma fila por qualquer motivo. há a possibilidade de liberar a memória jogando algumas mensagens especificas para o disco&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulador
&lt;/h2&gt;

&lt;p&gt;Utilizei um &lt;a href="http://tryrabbitmq.com/"&gt;simulador&lt;/a&gt; de RabbitMQ para testar os conceitos aprendidos &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzneLUve--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nys9w7uivvdf78qw34ck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzneLUve--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nys9w7uivvdf78qw34ck.png" alt="Image description" width="604" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Confiabilidade
&lt;/h2&gt;

&lt;p&gt;Como garantir que as mensagens não serão perdidas no meio do caminho? e que as mensagens puderam ser processadas corretamente pelos consumidores?&lt;/p&gt;

&lt;p&gt;O RabbitMQ tem alguns recursos pensados para resolver essas situações:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Consumer acknowledgement: quando um consumer avisa que recebeu a mensagem&lt;/li&gt;
&lt;li&gt;Publisher confirm: Todas as vezes que enviamos a mensagem o publisher informa que a imagem chegou até a exchange&lt;/li&gt;
&lt;li&gt;Filas e mensagens duráveis / persistidas&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Consumer acknowledgement
&lt;/h3&gt;

&lt;p&gt;Existem 3 tipos de consumer acnowledgement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Basic.Ack&lt;br&gt;
O consumer recebe a mensagem e informa que está tudo ok&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Basic.Reject&lt;br&gt;
Rejeita a mensagem fazendo ela voltar e ficar na fila novamente&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Basic.Nack&lt;br&gt;
É semelhante ao reject porem pode rejeitar mais de uma ao mesmo tempo&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Publisher confirms
&lt;/h3&gt;

&lt;p&gt;A mensagem vai ter um id que vai ser do tipo int, quando o publisher enviar essa mensagem para a exchange, ela avisa para o publisher que recebeu a mensagem e passa o id, então o publisher fica sabendo que a mensagem foi recebida pela exchange. Porem se a exchange tiver algum problema ela vai retornar um Nack passando o id da mensagem que deu o problema para que o publisher saiba que aquela mensagem não foi publicada&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Kong API Gateway</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Sat, 18 Jun 2022 14:11:13 +0000</pubDate>
      <link>https://forem.com/yanpiing/kong-api-gateway-3pk6</link>
      <guid>https://forem.com/yanpiing/kong-api-gateway-3pk6</guid>
      <description>&lt;p&gt;Alguns pontos sobre o kong &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Api Gateway Open Source e gratuito&lt;/li&gt;
&lt;li&gt;Caracteristicas Micro Gateway
ou seja, ele não prove configurações para controles de ciclo de vida&lt;/li&gt;
&lt;li&gt;Deployment flexível&lt;/li&gt;
&lt;li&gt;Pronto para kubernets&lt;/li&gt;
&lt;li&gt;Extensível via &lt;a href="https://docs.konghq.com/hub/" rel="noopener noreferrer"&gt;plugins&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Modelos de deployment
&lt;/h2&gt;

&lt;p&gt;O kong tem 3 modelos de deployment&lt;/p&gt;

&lt;h3&gt;
  
  
  DB-Less
&lt;/h3&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%2Fb5z17xdttzg3axd3zsvj.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%2Fb5z17xdttzg3axd3zsvj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fazemos a configuração dele por um arquivo Yaml ou JSON e subimos ele com base no arquivo, quando ele subir essa configuração ver carregada na memoria de cada nó do Kong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Com danco de dados
&lt;/h3&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%2F84facp5odwm7cc87m4sr.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%2F84facp5odwm7cc87m4sr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As configurações ficam todas em um banco de dados compartilhado por todos os nós. Um dos nós vai agir como control-plane e passar as configurações para o postgres que passa para os outros nós&lt;/p&gt;

&lt;h3&gt;
  
  
  Hibrido
&lt;/h3&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%2Fm9jmgieba30ejoo6l6ym.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%2Fm9jmgieba30ejoo6l6ym.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O modelo de deployment hibrido é o modelo recomendado pela equipe do Kong, a ideia é ter um control-plane que somente ele vai acessar o banco de dados, diferente do deploy com banco onde todas as instancias tem acesso ao banco. Nesse modelo hibrido os outros nós vão sempre receber as configurações do control-plane &lt;/p&gt;

&lt;h2&gt;
  
  
  Konga
&lt;/h2&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%2Fdz92lw9l3pf403apnvjn.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%2Fdz92lw9l3pf403apnvjn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interface administrativa para o Kong&lt;/li&gt;
&lt;li&gt;Visualização de métricas das instâncias&lt;/li&gt;
&lt;li&gt;Controle de usuarios&lt;/li&gt;
&lt;li&gt;Gerencia mais de um Kong&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Servicos
&lt;/h2&gt;

&lt;p&gt;Um serviço é uma entidade que representa uma API ou microsserviço upstream. Por exemplo um microsserviço de pagamentos ou de cadastro etc..&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando um novo serviço
&lt;/h3&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%2F9ub2rn44sxlviw52vp2a.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%2F9ub2rn44sxlviw52vp2a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Primeiro temos que ir até a pagina de services e clickar no botão de adicionar um novo service &lt;/p&gt;

&lt;p&gt;e então cadastrar ele:&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%2Fw06u12ytq0ha9pci8lt4.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%2Fw06u12ytq0ha9pci8lt4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Rotas
&lt;/h3&gt;

&lt;p&gt;As rotas são os caminhos de url que permite que um serviço cadastrado no nosso API Gateway seja acessado através do gateway&lt;/p&gt;

&lt;p&gt;Para cadastrar uma rota temos que ir dentro do serviço cadastrado e ir na opção "Routes" quando criamos uma rota podemos definir algumas configurações uma delas sendo o Host, &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%2Ftsmh9av1c8rry9924f9b.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%2Ftsmh9av1c8rry9924f9b.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando definimos o Host somente requests que tem o host esperado vão conseguir acessar aquela rota&lt;/p&gt;

&lt;p&gt;com o Host: &lt;br&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%2Fskrbr4j0vg4250v9nxqh.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%2Fskrbr4j0vg4250v9nxqh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;sem o Host:&lt;br&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%2Fo71mfzh3boeddrqbukuq.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%2Fo71mfzh3boeddrqbukuq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins
&lt;/h2&gt;

&lt;p&gt;Plugins são um pedaço de código que pode ser executado dentro de um ciclo de vida de uma requisição HTTP, tanto no request como no response, em outras Gateways isso pode ser encontrado como policy mas no Kong se chama plugin&lt;/p&gt;

&lt;p&gt;Os plugins podem ser configurados nas Rotas, Serviços, Consumers e Globalmente, tem uma precedência para as configurações&lt;/p&gt;

&lt;p&gt;essa é a ordem de precedência, quanto menor, mais prioridade&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%2Fkahiz6ssyc0l33osiswf.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%2Fkahiz6ssyc0l33osiswf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos escrever nossos proprios plugins em Lua, Javascript e Golang. Porêm o suporte é muito maior para Lua.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consumers
&lt;/h2&gt;

&lt;p&gt;É quem pode consumir sua API, para testar essa parte, criei dois consumidores, um que é um usuário e uma app &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%2F5dshwopvzv3sjsg7sw8b.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%2F5dshwopvzv3sjsg7sw8b.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;no usuário fui até a parte de credentials e criei uma senha para esse usuário, enquanto na app fui nessa parte também porem criei uma API key&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%2Fuzsvta8gom75eiivpk7m.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%2Fuzsvta8gom75eiivpk7m.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois disso foi só utilizar o plugin basic auth que a minha api já está me retornando como unauthorized&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%2F8ctnautkjno4jg0hk26w.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%2F8ctnautkjno4jg0hk26w.png" alt="Image description"&gt;&lt;/a&gt;&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%2Fb2axomjmojh3rdg80649.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%2Fb2axomjmojh3rdg80649.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apesar de não ser uma solução de fato muito segura, é muito interessante a facilidade para aplicar isso &lt;/p&gt;

&lt;h2&gt;
  
  
  Observabilidade
&lt;/h2&gt;

&lt;p&gt;O kong tem plugins de suporte ao prometheus além de um &lt;a href="https://grafana.com/grafana/dashboards/7424" rel="noopener noreferrer"&gt;dashboard oficial no grafana&lt;/a&gt; basta subirmos o prometheus e o grafana no docker-compose e instalar o plugin do prometheus no kong que temos um dashboard totalmente funcional&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%2Fovp9a081kijqyjpavm3s.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%2Fovp9a081kijqyjpavm3s.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Além disso tem todo um suporte para diversos sistemas de logs sendo facilmente possivel integrar um Datadog por exemplo&lt;/p&gt;

</description>
      <category>api</category>
    </item>
    <item>
      <title>API Gateway</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Fri, 17 Jun 2022 16:13:57 +0000</pubDate>
      <link>https://forem.com/yanpiing/api-gateway-iio</link>
      <guid>https://forem.com/yanpiing/api-gateway-iio</guid>
      <description>&lt;h2&gt;
  
  
  O que é API
&lt;/h2&gt;

&lt;p&gt;APIs são um conjunto de operações bem definidas com o objetivo de fornecer aos seus consumidores um serviço, produto ou integração&lt;/p&gt;

&lt;p&gt;Na pratica o consumidor de uma API utiliza o serviço sem precisar entender os detalhes da implementação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AO43Elhy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cjs61mnx11oigtsolgrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AO43Elhy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cjs61mnx11oigtsolgrr.png" alt='Uma imagem com 4 personagens, um cozinheiro com a legenda "Backend", um casal jantando com a legenda "Frontend" e um garçom com a legenda "APIs" ' width="880" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essa imagem ilustra bem o objetivo da API, seguindo essa analogia de restaurante um casal que pediu uma refeição geralmente não liga muito quem é a pessoa que está preparando essa refeição, eles ligam que o prato chegue até a mesa.&lt;/p&gt;

&lt;p&gt;Da mesma forma quando vamos consumir uma API no Frontend, não importa se ela foi construída em Node, Java, Go ou qualquer outra linguagem, o que importa é o front receber o que ele espera&lt;/p&gt;

&lt;p&gt;Existem algumas APIs famosas por serem muito bem desenhadas fazendo com que empresas ou desenvolvedores solo possam integrar facilmente com essas APIs, por exemplo a &lt;a href="https://developer.twitter.com/en/docs/twitter-api"&gt;API do twitter&lt;/a&gt; que é super bem documentada.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Gateway
&lt;/h2&gt;

&lt;p&gt;Os API gateways surgiram para resolver um problema gerado pela arquitetura de microsserviços, vamos imaginar que temos uma api publica e um cliente quer fazer uma integração com ela, porem nosso Backend é distribuído, já pensou falar pro cliente qual a api que ele precisa chamar para cada microsserviço que ele queira trabalhar? Isso seria inviável.&lt;/p&gt;

&lt;p&gt;Eles são ferramentas de gerenciamento, geralmente adicionadas entre um cliente e um grupo de sistemas, atuando como um ponto unico de entrada para as APIS&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hQ_bc5_q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y8ubhkml6ni1pvnpun8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hQ_bc5_q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y8ubhkml6ni1pvnpun8u.png" alt="Imagem mostrando dois fronts diferentes se comunicando com uma api por um único ponto de entrada" width="804" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nessa imagem podemos ver dois clients Front consumindo a API porem eles falam com a API Gateway e a Gateway redireciona a requisição para o microsserviço que eles querem de fato se comunicar, inclusive fazendo a tradução de protocolo pois tem duas apis REST e uma AMQP, isso fica abstraído para o front&lt;/p&gt;

&lt;p&gt;O Gateway vai ser sim um single point of failure (ponto único de falha), portanto temos que garantir a escalabilidade e resiliência dele.&lt;/p&gt;

&lt;h3&gt;
  
  
  Responsabilidades do Gateway
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Autenticação (Isso não isenta o serviço de ter uma autenticação própria com permissionamento e tudo mais)&lt;/li&gt;
&lt;li&gt;Controle de logs&lt;/li&gt;
&lt;li&gt;Gerenciamento de APIs (routing)&lt;/li&gt;
&lt;li&gt;Métricas padronizadas (ops team)&lt;/li&gt;
&lt;li&gt;Tracing Distribuido&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tipos de API Gateway
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Enterprise Gateway
&lt;/h3&gt;

&lt;p&gt;O foco dele é permitir gerenciar exposição e gerenciamento de apis voltadas ao negocio. Em geral ele permite controlar o ciclo de vida da API também.&lt;/p&gt;

&lt;p&gt;Como o Enterprise Gateway normalmente tem muitas funcionalidades extras temos que tomar cuidado para não deixar ele fortemente acoplado com a nossa aplicação dificultando assim uma migração no futuro.&lt;/p&gt;

&lt;p&gt;Seu proposito principal é a exposição, composição e  gerenciamento de APIs externas ou internas, a manutenção em geral é feita pelo portal do API gateway e ela suporta múltiplos ambientes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Micro/Microservices Gateway
&lt;/h3&gt;

&lt;p&gt;Geralmente esse tipo de gateway tem a capacidade de "rotear" o trafego de entrada para APIs ou serviços. Em geral ele não tem suporte para o ciclo de vida da API e a equipe tem que cuidar disso em um processo separado. Geralmente é open source.&lt;/p&gt;

&lt;p&gt;Em geral não possuem dependências externas, e são componentes standalone, facilitando assim o kubernets gerenciar o estado necessário para execução da aplicação&lt;/p&gt;

&lt;p&gt;Seu proposito principal é a exposição, observabilidade e monitoramento de serviços, a manutenção é feita pelo time de API que via configuração declarativa fazem atualizações, isso faz parte do deployment do serviço ela controla um único ambiente, mas possui suporte a um roteamento mais dinâmico como por exemplo o Canary para facilitar o debug.&lt;/p&gt;

&lt;p&gt;Algumas boas praticas são, usar a flexibilidade do deployment para "particionar" as APIs. E tentar ser Stateless o máximo possível aumentando assim muito a facilidade da escalabilidade e disponibilidade&lt;/p&gt;

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

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

&lt;ul&gt;
&lt;li&gt;Padronização de alguma features como logging e segurança&lt;/li&gt;
&lt;li&gt;Ajuda na governança de rede da companhia&lt;/li&gt;
&lt;li&gt;Ponto único de entrada na rede facilitando o gerenciamento&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Adiciona complexidade na arquitetura&lt;/li&gt;
&lt;li&gt;Precisa de um cuidado extra, devido a disponibilidade&lt;/li&gt;
&lt;li&gt;Ferramenta que precisa de manutenção/atualização&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>todayilearned</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Usando o Kubernets pela primeira vez</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Fri, 17 Jun 2022 00:16:56 +0000</pubDate>
      <link>https://forem.com/yanpiing/usando-o-kubernets-pela-primeira-vez-1eoj</link>
      <guid>https://forem.com/yanpiing/usando-o-kubernets-pela-primeira-vez-1eoj</guid>
      <description>&lt;p&gt;Já subi uma aplicação para a AWS umas 3 vezes mas todas foram um processo muito manual usando o EC2, hoje pela primeira vez usei o kubernets para automatizar esse processo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernets (K8s)
&lt;/h2&gt;

&lt;p&gt;O kubernets é um orquestadror de containers que fica responsável por transformar esses containers em pods e subir esses containers de forma mais automatizada para uma cloud como AWS ou GCP ou outras opções, porem ele não faz só isso, ele também tem o load balancer onde ele tenta distribuir as cargas para não deixar um pod sobrecarregado e também toda a parte de service discovery além de levantar pods novos sempre que os antigos caírem&lt;/p&gt;

&lt;h2&gt;
  
  
  Como usar o K8s
&lt;/h2&gt;

&lt;p&gt;Primeiro vamos criar um arquivo do tipo yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse arquivo inicial temos:&lt;br&gt;
&lt;code&gt;apiVersion&lt;/code&gt;: Versão da api do k8s, nesse caso é a v1&lt;br&gt;
&lt;code&gt;kind&lt;/code&gt;: qual o tipo do recurso a ser criado, nesse caso um pod&lt;br&gt;
&lt;code&gt;metadata&lt;/code&gt;: dados complementares&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: nome do pod&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;labels&lt;/code&gt;: label do pod então podemos depois filtrar por pods com a label &lt;code&gt;ngnix&lt;/code&gt; por exemplo
&lt;code&gt;spec&lt;/code&gt;: especificação do serviço&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;containers&lt;/code&gt;: qual o container dentro daquele pod com seu nome a sua imagem e a sua porta
&amp;gt; Existem casos de termos mais de um pod em um container porem como regra geral geralmente temos um pod por container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com isso temos já um pod, para testar esse pod podemos usar o &lt;a href="https://kind.sigs.k8s.io/"&gt;kind&lt;/a&gt; que serve para rodar o kubernets localmente, no próprio site do kind eles ensinam como instalar em diversos sistemas operacionais. Depois de instalado podemos rodar o comando &lt;br&gt;
&lt;code&gt;kind create cluster --name={algo}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E0vWjSHU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qm7io6yqmuz586m1yu42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E0vWjSHU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qm7io6yqmuz586m1yu42.png" alt="Image description" width="301" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;e entao o kind vai sugerir rodarmos o comando &lt;code&gt;kubectl cluster-info --context kind-{algo}&lt;/code&gt; mas para isso vamos precisar do &lt;a href="https://kubernetes.io/docs/tasks/tools/"&gt;kubectl&lt;/a&gt; depois de rodarmos o comando do kubectl conseguimos ver que o kubernets já está como ready&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z0WEeXAc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nqtohr2y8a174yz4ac0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z0WEeXAc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nqtohr2y8a174yz4ac0n.png" alt="Image description" width="439" height="48"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;por padrão o kubernets tem o control-plane que gerencia tudo, e quem é gerenciado são as maquinas que ficam conectadas no control-plane. Para rodar um cluster kubernets é recomendado no minimo 3 maquinas&lt;/p&gt;

&lt;p&gt;agora para conectar o pod precisamos rodar &lt;code&gt;kubectl apply -f {nome_do_yml}&lt;/code&gt; e com o &lt;code&gt;kubectl get pods&lt;/code&gt; ele vai retornar o pod rodando, e para conectar com o ngnix? temos que dar um port-forward com o comando &lt;code&gt;kubectl port-forward pod/nginx 9090:80&lt;/code&gt; onde 80 é a porta que declaramos no yml e o 9090 é a porta que disponibilizei no meu computador, então se eu for no meu localhost 9090 vou encontrar o nginx&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7jilBFF3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32izewh4z854dnu4uo4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7jilBFF3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32izewh4z854dnu4uo4m.png" alt="Image description" width="617" height="284"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  ReplicaSet
&lt;/h4&gt;

&lt;p&gt;Porem o kubernets ainda não está mantendo o pod online todo o tempo, se rodarmos o comando &lt;code&gt;kubectl delete pod nginx&lt;/code&gt; o pod vai ficar fora do ar. Para garantir que os pods estejam sempre online precisamos adicionar o Replica set, que fica gerenciando os pods e vendo se algum pod saiu do ar para ele criar um novo. &lt;/p&gt;

&lt;p&gt;O yml do replicaSet ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ReplicaSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;onde ele é do tipo ReplicaSet e ele monitora todos os pods que a label é 'nginx', ele tem também um template igual ao pod que definimos no yaml anterior, para que ele saiba como vai ser o pod que ele vai criar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PYbf6jxf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1jylvd0rzvfw77bgc65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PYbf6jxf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1jylvd0rzvfw77bgc65.png" alt="Image description" width="380" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos ver que agora sempre que eu excluo um pod o replicaSet logo em seguida sobe um novo no lugar, além disso é possivel ver que já está salva a configuração que eu desejo manter apenas uma replica daquele pod.&lt;/p&gt;

&lt;h4&gt;
  
  
  Deployments
&lt;/h4&gt;

&lt;p&gt;Se eu quiser mudar a versão da imagem que estou utilizando o replicaSet não vai fazer essa mudança de forma automática, para isso vou precisar matar o pod para quando subir novamente ele subir com a versão nova, o replicaSet só verifica se o pod caiu e quantos pods eu quero.&lt;/p&gt;

&lt;p&gt;Agora imagine essa situação onde eu tenho por exemplo 100 replicas, eu teria que matar os pods para atualizar a versão da imagem. E para isso temos os deployments, que são responsaveis por cuidar dos replicasets.&lt;/p&gt;

&lt;p&gt;O Deployment sempre que quisermos mudar a versão da imagem ele vai criar um novo replicaSet, então por exemplo, temos 10 pods na versão 1.0, queremos atualizar para a versão 1.1, o deployment cria um novo replicaset com a versão 1.1 e pedindo 10 pods, enquanto no da versão 1.0 ele pede por 0 pods, e se a versão 1.1 estiver quebrada e precisarmos voltar ele pede por 10 pods na versão 1.0 e 0 pods na versão 1.1&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O yml do deployment é igual ao do replicaSet, só muda que no kind ao inves de ReplicaSet vai ser Deployment, porem todo o processo é mesmo, basta dar um apply que vai funcionar&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MN0QBhA6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4drexlqmy38sx47or2qj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MN0QBhA6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4drexlqmy38sx47or2qj.png" alt="Image description" width="523" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Da para ver como ele fica alternando entre os replicaSets conforme a configuração muda &lt;/p&gt;

&lt;h2&gt;
  
  
  Rodando o kubernets com o meu servidor
&lt;/h2&gt;

&lt;p&gt;Para isso criei um servidor bem basico em GO, tudo que ele faz é escrever hello world quando acessamos a porta 9090&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;"net/http"&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hello&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;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":9090"&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;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&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;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&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;alem disso vou criar um arquivo docker&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="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; main.go .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64 &lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 go build &lt;span class="nt"&gt;-o&lt;/span&gt; server main.go

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; scratch&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/server .&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "./server" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;vou buildar esse arquivo &lt;code&gt;docker build -t yansb/goserver:latest .&lt;/code&gt; e se e eu rodar o comando &lt;code&gt;docker run --rm -p 9090:9090 yansb/goserver:latest&lt;/code&gt; já consigo acessar minha porta 9090 e ver o hello world, depois disso posso dar um push dessa imagem para o meu &lt;a href="https://hub.docker.com/repository/docker/yansb/goserver"&gt;dockerhub&lt;/a&gt;, agora ja posso criar um novo yaml com o essa imagem e fazer esse novo deployment &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wZWFgB2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mivm6mm31oa6sj60q6rk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wZWFgB2y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mivm6mm31oa6sj60q6rk.png" alt="Image description" width="615" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se eu der um port-forward e for na porta 9090 já consigo ver o meu hello world &lt;/p&gt;
&lt;h4&gt;
  
  
  Load balancer
&lt;/h4&gt;

&lt;p&gt;Agora com diversas replicas dos pods (10 com o GO e 10 nginx) temos um problema, como K8s vai saber para qual pod mandar a pessoa que está acessando a aplicação&lt;/p&gt;

&lt;p&gt;Vamos criar um yaml para o service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse service vai pegar todos os pods com a label nginx e vai fazer o loadBalance baseado nessa seleção agora qualquer pessoa que internamente procurar pelo nginx-service ou pelo ip dele, vai chegar até um dos nginx.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1DfNcAEF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4aqbn3ml4u93z1dtj7ux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1DfNcAEF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4aqbn3ml4u93z1dtj7ux.png" alt="Image description" width="688" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O external ip está como pending pois meu computador não consegue gerar um IP externo, porem se estivesse rodando na aws, já poderíamos acessar esse ip externo e ter acesso ao ngnix&lt;/p&gt;

&lt;p&gt;Tudo que fiz hoje com o kubernets está nesse repositório: &lt;a href="https://github.com/Yansb/full-cycle-course/tree/master/kubernets"&gt;https://github.com/Yansb/full-cycle-course/tree/master/kubernets&lt;/a&gt;&lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>braziliandevs</category>
      <category>kubernetes</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Configurando testes de integração no Nestjs com o Typeorm</title>
      <dc:creator>Yan.ts</dc:creator>
      <pubDate>Thu, 16 Jun 2022 00:59:10 +0000</pubDate>
      <link>https://forem.com/yanpiing/configurando-testes-de-integracao-no-nestjs-com-o-typeorm-37o3</link>
      <guid>https://forem.com/yanpiing/configurando-testes-de-integracao-no-nestjs-com-o-typeorm-37o3</guid>
      <description>&lt;h2&gt;
  
  
  Teste de integração
&lt;/h2&gt;

&lt;p&gt;Testes de integração como o nome já dá uma noção, são testes integrados com serviços externos, então por exemplo: em um teste unitário eu faço o mock do retorno do banco de dados para não precisar me conectar no banco de dados e fazer as queries. Enquanto nos testes de integração a ideia é subir um banco de dados separado só para teste e rodar e depois destruir esse banco.&lt;/p&gt;

&lt;p&gt;Por que usar o teste de integração? tive essa necessidade principalmente pois os testes unitários não me deixaram confortável em garantir o pleno funcionamento da aplicação. Em alguns endpoints onde a função principal era fazer uma busca paginada por exemplo os testes unitários não bastavam pois o que mais importa nessa função é a querie que vai rodar no banco e as suas variações com filtros, e no teste unitário como eu que defino o retorno que a função vai ter não ia ter como testar isso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fazendo as configurações
&lt;/h2&gt;

&lt;p&gt;Primeiro precisei configurar uma conexão 'mãe' que vai ser responsável por criar o banco de dados, e também configurar uma conexão secundaria que vai ser a conexão com o banco de testes&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;masterConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;database&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;DATABASE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;host&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;DATABASE_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;password&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;DATABASE_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&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;DATABASE_PORT&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;parseInt&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;DATABASE_PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;username&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;DATABASE_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;entities&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;dist/**/*.entity{.ts,.js}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;migrations&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;dist/src/db/migrations/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;master&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;migrationsRun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DataSource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...(&lt;/span&gt;&lt;span class="nx"&gt;masterConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;PostgresConnectionOptions&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;migrationsRun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e então fiz uma função para fazer a conexão e criar o banco de dados o banco de dados e gerei um nome aleatório para o banco &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Não é obrigatório gerar um nome aleatório pois ainda vou apagar o banco de testes quando acabar com teste poderia também ser um nome definido como 'test_db' por exemplo&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nessa função fazemos a conexão que vai gerar o banco, geramos ele e retornamos a conexão com esse banco gerado&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;databaseName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`test_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;databaseIntegrationSetup&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;masterConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialize&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;masterConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`CREATE DATABASE "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="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;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&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;stack&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="nx"&gt;stringify&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="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;,&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;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E uma função para fechar a conexão com o banco de dados, onde ele dropa o database criado para testes e fecha a conexã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;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;closeDatabaseIntegrationConnections&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;masterConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`DROP DATABASE "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;masterConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="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;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&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;stack&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="nx"&gt;stringify&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="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;,&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;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="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;
  
  
  Inicializando o teste
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Integrations tests&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="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;INestApplication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;beforeAll&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;databaseConnection&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;databaseIntegrationSetup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestingModule&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;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;TypeOrmModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;databaseConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createNestApplication&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;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;afterAll&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&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;closeDatabaseIntegrationConnections&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should be defined&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="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para definirmos o teste a gente basicamente vai pegar a conexão com o database que retornamos na primeira função e vamos declarar um modulo de testes e passar essa conexão para o modulo do Typeorm, e vamos inicializar o app nesse momento o teste já vai passar, porem depois de todos os testes rodarem precisamos fechar o app e chamar a função de fechar a conexão com o banco de dados e apagar esse banco criado só para testes&lt;/p&gt;

</description>
      <category>testing</category>
      <category>typescript</category>
      <category>todayilearned</category>
    </item>
  </channel>
</rss>
