<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Convenia</title>
    <description>The latest articles on DEV Community by Convenia (@convenia).</description>
    <link>https://dev.to/convenia</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%2Forganization%2Fprofile_image%2F2645%2Ff43f6bb0-7107-47f4-b5c8-3fe59fcd22f0.png</url>
      <title>DEV Community: Convenia</title>
      <link>https://dev.to/convenia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/convenia"/>
    <language>en</language>
    <item>
      <title>Imagem Docker. Para rodar projetos PHP em menos de 30 segundos.</title>
      <dc:creator>Leonardo Lemos</dc:creator>
      <pubDate>Tue, 06 Jan 2026 15:02:25 +0000</pubDate>
      <link>https://dev.to/convenia/imagem-docker-para-rodar-projetos-php-em-menos-de-30-segundos-dee</link>
      <guid>https://dev.to/convenia/imagem-docker-para-rodar-projetos-php-em-menos-de-30-segundos-dee</guid>
      <description>&lt;h2&gt;
  
  
  Release da imagem PHP Full da Convenia, com PHP 8.5
&lt;/h2&gt;

&lt;p&gt;Nesta semana, lançamos a &lt;strong&gt;versão 8.5 da nossa imagem Docker para aplicações PHP&lt;/strong&gt;, agora com &lt;strong&gt;PHP 8.5&lt;/strong&gt; e nesse post vamos falar um pouco de como utilizar essa imagem.&lt;/p&gt;

&lt;p&gt;Na &lt;strong&gt;Convenia&lt;/strong&gt;, a maior &lt;em&gt;HR Tech&lt;/em&gt; do Brasil, utilizamos essa imagem &lt;strong&gt;de forma padronizada em todos os nossos projetos&lt;/strong&gt;. Isso significa que qualquer desenvolvedor da equipe sabe exatamente como iniciar, testar e implantar aplicações sem surpresas no ambiente — seja em desenvolvimento, homologação ou produção. &lt;a href="https://dev.to/convenia/utilizando-uma-imagem-base-para-suas-aplicacoes-php-1g8a"&gt;Nesse post&lt;/a&gt; abordamos todas as vantagens de padronizar a forma de executar aplicações&lt;/p&gt;

&lt;p&gt;Essa imagem está disponível desde a versão &lt;strong&gt;8.1&lt;/strong&gt;, sendo amplamente &lt;strong&gt;testada e utilizada&lt;/strong&gt; em produção em centenas de projetos e pipelines da Convenia e já acumula mais de 10K de pulls no &lt;a href="https://hub.docker.com/r/convenia/php-full" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que é a imagem Docker PHP Full?
&lt;/h2&gt;

&lt;p&gt;A imagem Docker &lt;strong&gt;PHP Full&lt;/strong&gt; é um ambiente containerizado que já contém tudo o que aplicações PHP precisam para rodar com segurança e desempenho:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP pré-configurado com versões modernas&lt;/li&gt;
&lt;li&gt;Servidor web integrado&lt;/li&gt;
&lt;li&gt;Ferramentas úteis como Composer, cron e extensões comuns&lt;/li&gt;
&lt;li&gt;Testes de integridade e atualizações regulares&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Convenia mantém esse padrão há diversas versões — do &lt;strong&gt;PHP 8.1 até o novo 8.5&lt;/strong&gt; — garantindo estabilidade e suporte contínuo para todos os projetos da empresa.&lt;/p&gt;




&lt;h2&gt;
  
  
  Como usar a imagem
&lt;/h2&gt;

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

&lt;p&gt;Para começar com a imagem PHP Full da Convenia, basta usar o Docker ou Docker Compose.&lt;/p&gt;

&lt;h4&gt;
  
  
  Usando Docker
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 80:80 convenia/php-full:8.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao acessar o seu localhost será possível ver uma documentação similar a essa&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0pfg0js1hbg5pqqortx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0pfg0js1hbg5pqqortx.png" alt="Documentação da imagem sendo servida pela própria imagem em execução" width="652" height="1053"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Essa página é a própria documentação da imagem sendo servida pelo PHP + nginx. No proximo exemplo com o docker compose vemos como executar a nossa aplicação dentro da imagem, é só montar um volume ou copiar a aplicação para o diretório &lt;code&gt;/var/www/app&lt;/code&gt; dentro do container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usando com Docker Compose
&lt;/h3&gt;

&lt;p&gt;Crie um arquivo &lt;code&gt;docker-compose.yml&lt;/code&gt; na raiz do seu projeto:&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;services&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="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;convenia/php-full:8.5&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;app&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;.:/var/www/app&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;80:80"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse arquivo pode ser colocado na raiz de um projeto Laravel por exemplo, e ao subir a stack do compose o projeto já deve executar sem maiores problemas.&lt;/p&gt;

&lt;p&gt;Na verdade é possível colocar esse arquivo em qualquer aplicação PHP que tenha a pasta public como entrypoint do request, aplicações Symfony, Laravel. Se o entrypoint for na raiz apenas acrescente a pasta public ao montar o volume:&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;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;.:/var/www/app/public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Atualizações automáticas
&lt;/h3&gt;

&lt;p&gt;A imagem é construída e atualizada semanalmente para garantir o uso de versões seguras e livres de vulnerabilidades conhecidas, com escaneamento contínuo de dependências. O último build pode ser consultado no &lt;a href="https://github.com/convenia/php-full-8.1-image/actions" rel="noopener noreferrer"&gt;workflow do Github Actions&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Segurança
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;O serviço FPM (porta 9000) é exposto &lt;strong&gt;apenas internamente no container&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;É recomendado &lt;strong&gt;bloquear a porta 9000&lt;/strong&gt; em ambientes externos&lt;/li&gt;
&lt;li&gt;A imagem já vem com as configurações de segurança recomendadas para produção. Como desabilitar mensagens de erros e afins.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Exemplos de customização
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Substituir configuração do Nginx
&lt;/h3&gt;

&lt;p&gt;Você pode substituir a configuração padrão do servidor web:&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;services&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="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;convenia/php-full:8.5&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;./nginx.conf:/etc/nginx/http.d/default.conf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim adapta o container às regras específicas do seu projeto.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tarefas agendadas com cron
&lt;/h2&gt;

&lt;p&gt;A imagem já inclui o binário &lt;code&gt;cron&lt;/code&gt;, facilitando tarefas agendadas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adicione um arquivo &lt;code&gt;crontab&lt;/code&gt; com os comandos desejados;&lt;/li&gt;
&lt;li&gt;Copie para o container:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; crontab /etc/crontabs/root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Inicie cron no container:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; mycronimage crond &lt;span class="nt"&gt;-l&lt;/span&gt; 2 &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso facilita execução de comandos como o scheduler do Laravel. &lt;/p&gt;




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

&lt;p&gt;Seguem uma listinha com as vantagens da utilização dessa imagem em projetos PHP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistência entre ambientes&lt;/li&gt;
&lt;li&gt;Facilidade de uso&lt;/li&gt;
&lt;li&gt;Atualizações contínuas&lt;/li&gt;
&lt;li&gt;Padrão único para toda a empresa&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>php</category>
    </item>
    <item>
      <title>Spot By NetApp análise da utilização do Elasticgroup na Convenia</title>
      <dc:creator>Leonardo Lemos</dc:creator>
      <pubDate>Fri, 26 May 2023 20:24:37 +0000</pubDate>
      <link>https://dev.to/convenia/spot-by-netapp-analise-da-utilizacao-do-elasticgroup-na-convenia-519h</link>
      <guid>https://dev.to/convenia/spot-by-netapp-analise-da-utilizacao-do-elasticgroup-na-convenia-519h</guid>
      <description>&lt;p&gt;Nesse post tenho como objetivo contar um pouco de como está sendo a utilização da &lt;a href="https://spot.io/" rel="noopener noreferrer"&gt;Spot by NetApp&lt;/a&gt;. Importante analisar que a Spot tem um monte de produtos voltados para cloud, nesse post vou analisar apenas o &lt;a href="https://spot.io/resources/aws-autoscaling/understanding-ec2-auto-scaling-groups/" rel="noopener noreferrer"&gt;Elasticgroup&lt;/a&gt; que é o produto da Spot voltado para gerenciar as instâncias EC2, similar ao &lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html" rel="noopener noreferrer"&gt;AutoScalingGroup(ASG)&lt;/a&gt; da AWS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBS: Sempre que me referir a "Spot" com inicial maiúscula estou me referindo à empresa SpotByNetapp e sempre que eu me referir a "spot" com inicial minúscula estou me referindo ao tipo de instancia spot da AWS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Na Convenia já utilizávamos instâncias spot para todo serviço que não fossem crítico e admitissem interrupções. No mês da black friday utilizamos exclusivamente instâncias “On Demand” para evitar interrupções massivas devido ao esgotamento da oferta spot, esse foi o resultado:&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%2F9ygrilmgtnpk6zo4vyjr.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%2F9ygrilmgtnpk6zo4vyjr.png" alt="Imagem mostrando um spike de custo no mês da black friday. aproximademente o dobro do custo."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No gráfico acima existe um spike de custo em dezembro causado pela utilização das instancias "On Demand". Após analisar o custo fizemos uma reunião de &lt;a href="https://dev.to/convenia/transformando-falhas-em-oportunidades-a-importancia-da-reuniao-de-postmortem-45jg"&gt;post mortem&lt;/a&gt; e decidimos avaliar o &lt;a href="https://spot.io/resources/aws-autoscaling/understanding-ec2-auto-scaling-groups/" rel="noopener noreferrer"&gt;Elasticgroup&lt;/a&gt; da Spot que promete fallback para “on demand” caso a oferta spot se esgote.&lt;/p&gt;

&lt;p&gt;De inicio posso dizer que gostamos de resultado final e passamos todos as instâncias para serem gerenciadas pelo Elasticgroup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como foi a integração??
&lt;/h2&gt;

&lt;p&gt;Sempre que precisamos testar qualquer coisa dentro da Convenia fazemos uma &lt;a href="https://blog.randon.com.br/proof-of-concept/" rel="noopener noreferrer"&gt;POC&lt;/a&gt; com algum serviço interno para entender realmente os pontos negativos e positivos, e foi isso que fizemos.&lt;/p&gt;

&lt;p&gt;O primeiro passo para integração é fazer a ligação da conta da Spot com a sua conta da AWS seguindo o &lt;a href="https://docs.spot.io/cloud-analyzer/getting-started/connect-account-multiple-organizations-to-single-master-payer" rel="noopener noreferrer"&gt;passo a passo&lt;/a&gt; na própria documentação da Spot, esse passo apesar de muito bem explicado contém algumas etapas, caso haja dúvida na implantação ou mesmo em relação as possibilidades que a Spot pode trazer sugiro uma conversa com o pessoal da &lt;a href="https://www.realcloud.systems/" rel="noopener noreferrer"&gt;RealCloud&lt;/a&gt; que nos ajudou bastante a entender os produtos da spot e entender como fazer essa migração.&lt;/p&gt;

&lt;p&gt;Após linkar a conta da AWS com a Spot seguimos um wizard que importa as configurações do AutoScalingGroup da aws para um Elasticgroup dentro da spot. Apenas isso foi necessário para ter as instancias sendo gerenciadas pela Spot, após a criação do Elastic group podemos inativar o nosso AutoScalingGroup(setando a capacidade desejada, mínima e máxima para 0) ou mesmo remove-lo.&lt;/p&gt;

&lt;p&gt;No nosso caso, fazer essa migração para o primeiro serviço durou cerca de uma hora. Continuamos monitorando para ver como o Elasticgroup faria as trocas de instancias para conseguir mais saving e fizemos mais alguns testes para forçar refresh de instancias e interrupções para entender como ele lida com isso, na nossa experiência não tivemos nem uma surpresa, simplesmente não perde em nada para o ASG da AWS, ainda tem algumas funcionalidades a mais como vou falar mais para frente.&lt;/p&gt;

&lt;p&gt;Um outro ponto importante que vale ressaltar durante a integração é que a RealCloud nos acompanhou durante todo o processo, e o billing começou a rodar apenas após a integração de todos os serviços.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quais as vantagens da adoção da Spot?
&lt;/h2&gt;

&lt;p&gt;A resposta lógica para essa pergunta seria custo mas vou começar falando das coisas que não tem haver com custo, o custo vamos analisar mais profundamente no próximo tópico, então seguem as outras vantagens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fallback para “On Demand”&lt;/strong&gt;: Esse é um dos principais motivadores para a adoção na minha opinião, é muito difícil prever a oferta spot com eficiência, a AWS promete avisar sobre interrupções com 2 minutos de antecedência, dessa forma é possível construir automações para lidar com a interrupção mas eu particularmente não gosto de lidar com isso artesanalmente. O que acabamos fazendo é manter as instancias mais críticas com “On Demand”. Poder confiar que o Elasticgroup vai fazer o fallback corretamente te permite spotizar até as instancias mais críticas e evita que você faça a loucura de voltar todas as instancias para “On Demand” nas vesperas de uma black friday causando aquele spike de custo mostrado no inicio.&lt;/p&gt;

&lt;p&gt;Abaixo os logs do Elasticgroup fazendo a substituição de instancias spot pot "On Demand":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5/21/2023, 5:30 AM, INFO, Updating group
5/21/2023, 5:30 AM, INFO, Falling back to on-demand, no spot instances could be launched.
5/21/2023, 5:30 AM, INFO, Scheduling action: [scale] ( , scaleTargetCapacity: 5 , scaleMinCapacity: 5 , scaleMaxCapacity: 8)
5/21/2023, 5:30 AM, INFO, Instances: [i-01b3bc7d84018f540,i-0762fba5e0348ef70,i-0d204f6f3e1b6a9a5,i-04182456095d6e21d] have been launched. Reason: Group update
5/21/2023, 5:30 AM, INFO, Updating Group Succeed
5/21/2023, 5:31 AM, INFO, Instance [i-0d204f6f3e1b6a9a5,i-01b3bc7d84018f540,i-04182456095d6e21d,i-0762fba5e0348ef70] successfully registered to load balancer: rh-live-core-84
5/21/2023, 5:31 AM, INFO, Instance [i-0d204f6f3e1b6a9a5,i-01b3bc7d84018f540,i-04182456095d6e21d,i-0762fba5e0348ef70] successfully registered to load balancer: rh-live-internal-core-84
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Scheduled scalling:&lt;/strong&gt; O Elasticgroup nos permite definir alguns schedulers no formato de cron para escalar as maquinas em determinados horários. Na Convenia deixamos no mínimo duas instancias rodando para os serviços principais durante o dia e por ser um sistema muito focado no publico brasileiro, o tráfego cai bastante durante a noite, nesse caso podemos configurar esse scheduler para desligar as instancias redundantes pela madrugada, trazendo um saving ainda maior&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%2Ff3f64vz336uqrkxdmegg.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%2Ff3f64vz336uqrkxdmegg.png" alt="Imagem mostrando a configuração do scheduler da spot, diminuindo a capacidade durante a noite e retomando pela manhâ"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplicidade na organização de recursos:&lt;/strong&gt; Para manter práticas do CodeReview e manter uma padronização mínima dos serviços utilizamos o &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;terraform&lt;/a&gt;. Geralmente ao criar o autoscaling dentro da AWS acabamos criando uma serie de recursos avulsos, como scaling policies, asg attachments entre outros. Ao adicionar o recurso de Elasticgroup no nosso terraform notamos uma boa simplificação visto que o Elasticgroup é um único recursão que aglomera todas as funcionalidades, no final trocamos diversos recursos do terraform por apenas um.&lt;/p&gt;

&lt;p&gt;Abaixo um exemplo real de um Elasticgroup criado pelo terraform na Convenia:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"spotinst_elastigroup_aws"&lt;/span&gt; &lt;span class="s2"&gt;"core_webserver_live_asg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"core_webserver_live_asg"&lt;/span&gt;
  &lt;span class="nx"&gt;spot_percentage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
  &lt;span class="nx"&gt;orientation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"balanced"&lt;/span&gt;
  &lt;span class="nx"&gt;draining_timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
  &lt;span class="nx"&gt;fallback_to_ondemand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;desired_capacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
  &lt;span class="nx"&gt;min_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
  &lt;span class="nx"&gt;max_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
  &lt;span class="nx"&gt;capacity_unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"instance"&lt;/span&gt;

  &lt;span class="nx"&gt;scaling_target_policy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;policy_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CPU track scaling"&lt;/span&gt;
    &lt;span class="nx"&gt;namespace&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AWS/EC2"&lt;/span&gt;
    &lt;span class="nx"&gt;metric_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CPUUtilization"&lt;/span&gt;
    &lt;span class="nx"&gt;statistic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"average"&lt;/span&gt;
    &lt;span class="nx"&gt;unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"percent"&lt;/span&gt;
    &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;
    &lt;span class="nx"&gt;cooldown&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;instance_types_ondemand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t3.small"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_types_spot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"t3.small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"t3a.small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Linux/UNIX"&lt;/span&gt;

  &lt;span class="nx"&gt;target_group_arns&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;aws_alb_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core_live_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;aws_alb_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core_internal_live_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;security_groups&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;enable_monitoring&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;ebs_optimized&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;image_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vault_generic_secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;swarm_base_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"image_id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;ebs_block_device&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;device_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/dev/sda1"&lt;/span&gt;
    &lt;span class="nx"&gt;delete_on_termination&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;volume_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"32"&lt;/span&gt;
    &lt;span class="nx"&gt;volume_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gp3"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"user_data.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;swarm_token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;swarm_token&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Workload"&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"live-core"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name"&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"live-core-webserver-elasticgroup"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;iam_instance_profile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-super-secret-policy arn"&lt;/span&gt;
  &lt;span class="nx"&gt;health_check_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"TARGET_GROUP"&lt;/span&gt;
  &lt;span class="nx"&gt;health_check_grace_period&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;

  &lt;span class="nx"&gt;scheduled_task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;is_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;task_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scale"&lt;/span&gt;
    &lt;span class="nx"&gt;cron_expression&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0 23 * * *"&lt;/span&gt;
    &lt;span class="nx"&gt;scale_target_capacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nx"&gt;scale_min_capacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nx"&gt;scale_max_capacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;scheduled_task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;is_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;task_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scale"&lt;/span&gt;
    &lt;span class="nx"&gt;cron_expression&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"30 8 * * *"&lt;/span&gt;
    &lt;span class="nx"&gt;scale_target_capacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="nx"&gt;scale_min_capacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="nx"&gt;scale_max_capacity&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;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;

  &lt;span class="nx"&gt;lifecycle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ignore_changes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;desired_capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Custo sobre o saving: Talvez esse seja uma dos principais atrativos na venda dos serviços pela Spot, o modelo de billing da Spot é sobre o seu saving logo não existe a possibilidade de você pagar por algo que você não vai ter, retorno garantido! Se seu billing não diminui você não paga nada.&lt;/p&gt;

&lt;p&gt;Esses foram algumas das vantagens que notamos nessa migração mas confesso que a Convenia não utiliza todo o poder da Spot, ainda existe possibilidade para spotizar instancias statefull entre outras coisas, independente do seu case acho difícil acreditar que a Spot não tem alguma solução que possa trazer algum tipo de saving, quanto maior o seu sistema(em quantidade de maquinas) mais passa a fazer sentido essa adoção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mas e o Custo??
&lt;/h2&gt;

&lt;p&gt;O principal motivador para a adoção da Spot é redução de custos, essa é a bandeira deles! A Convenia tem uma infra relativamente pequena e para quantificar esse saving adequadamente precisamos nos atentar a alguns detalhes.&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%2F9ygrilmgtnpk6zo4vyjr.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%2F9ygrilmgtnpk6zo4vyjr.png" alt="Imagem mostrando um spike de custo no mês da black friday. aproximademente o dobro do custo."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como mostrado no gráfico de billing acima, que contém apenas custo “On Demand e Spot”, em setembro de 2022 e abril de 2023 o custo permanece mais ou menos no mesmo patamar, isso é bom pois nesses últimos meses nossa infra cresceu um pouco, spotizar as instancias críticas que antes não eram spot nos permitiu esse resultado.&lt;/p&gt;

&lt;p&gt;A spot tem um custo sobre o saving: nossa conta da spot varia em torno de 130 Bidens. Quando adicionamos esse custo ao valor mensal mostrado no billing da aws notamos que a conta de abril de 2023 supera um pouco a conta de setembro de 2022, isso se deve ao crescimento da nossa infra nesses meses mas mesmo sem esse crescimento não acredito que o saving teria sido expressivo a ponto de justificar a adoção da Spot apenas por custo. Importante notar que quanto maior for a sua infra maior é a justificativa para a adoção, talvez a Convenia não tenha tido resultados tão expressivos pelo tamanho da infra e pelo fato de já utilizar Instancias spot para alguns serviços, claro que o saving poderia ser ainda maior se spotizarmos as instancias statfull que temos.&lt;/p&gt;

&lt;p&gt;Nosso total de desconto devido a instancias spot ficavam em torno de 65%, a taxa de Spot é de 28% sobre esse saving de 65 mas o que ninguem conta é que para uma empresa brasileira utilizando a Spot teremos algumas impostos que somados com a taxa da Spot podem arranhar os 40% desse saving.&lt;/p&gt;

&lt;p&gt;Outra detalhe muito importante que é radicalmente negligenciado é o custo da mão de obra, por mais que a integração seja simples, trocar os ASGs massivamente pelo Elasticgroup exige uma validação mínima além de um acompanhamento para ver se está funcionando como previsto e se está atingindo o saving previsto, no fim o time vai morrer com alguns dias em cima dessa integração e mão de obra é caro!&lt;/p&gt;

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

&lt;p&gt;No final, analisando o conjunto de vantagens e desvantagens julgo como positiva a utilização da Spot, se tivesse que julgar apenas a redução de custo com computing já não faria tanto sentido, mas ter um fallback para “on demand” automático, simples e confiável é a maior das vantagens para min, visto que não vamos ver spikes de custo nas épocas de black friday, o que já compensaria o preço pago pelo serviço da spot.&lt;/p&gt;

&lt;p&gt;Essa conclusão de custo é muito particular da Convenia que tem uma infra relativamente pequena e já era bem espotizada antes. Conforme o crescimento da empresa acredito que o saving proporcionado passa a ser cada vez mais relevante. No aws summit de 2022 o Nubank mostrou um pouco do case deles de utilização da Spot, com o volume deles a spotização pode trazer um valor absurdo de custos, pra quem quiser ver esse case mais de perto só ver &lt;a href="https://www.youtube.com/watch?v=8rtuCSldLDY" rel="noopener noreferrer"&gt;aqui no youtube&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>convenia</category>
      <category>cloudcomputing</category>
    </item>
    <item>
      <title>Transformando falhas em oportunidades: A importância da reunião de postmortem</title>
      <dc:creator>Yan Porfirio</dc:creator>
      <pubDate>Thu, 13 Apr 2023 13:59:44 +0000</pubDate>
      <link>https://dev.to/convenia/transformando-falhas-em-oportunidades-a-importancia-da-reuniao-de-postmortem-45jg</link>
      <guid>https://dev.to/convenia/transformando-falhas-em-oportunidades-a-importancia-da-reuniao-de-postmortem-45jg</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Olá pessoal, tudo bem ? Eu sou Yan Porfirio, analista de segurança da informação na Convenia e vou falar um pouco mais sobre post mortem e como isso impacta diretamente a área de segurança e compliance no que diz respeito a disponibilidade e integridade dos dados e do sistema. Mas afinal, o que é o post mortem ?&lt;/p&gt;

&lt;p&gt;O post mortem é uma reunião que é feita no fim de todo projeto ou procedimento, é uma espécie de retrospectiva, onde a equipe analisa o que foi feito, o que deu certo e pontos a serem melhorados.&lt;/p&gt;

&lt;p&gt;Aqui na Convenia, além de realizamos esse rito após o fim de um projeto ou procedimento, realizamos também após algum incidente relacionado a tecnologia, um exemplo disso, é a queda de algum serviço. Essa reunião é um processo que ajuda a melhorar os nossos serviços e entendermos o porquê ocorreu a falha, alterando processos organizacionais para incorporar lições aprendidas. Um post mortem é mais do que apenas uma apuração dos fatos. &lt;/p&gt;

&lt;p&gt;Na verdade, as funções mais importantes de um post mortem são promover melhorias nos processos e melhores práticas para repetir sucessos. Geralmente costuma ser uma reunião rápida, de no máximo 1 hora, que reunimos o time responsável pelo gerenciamento do serviço que foi impactado no incidente, e detalhamos o que ocorreu, o porque ocorreu, tempo de duração e o que podemos fazer para não acontecer novamente. &lt;/p&gt;

&lt;p&gt;Em um determinado momento, no meio de 2022 sentimos falta de uma métrica para conseguirmos mensurar a periodicidade e o impacto desses incidentes, foi onde decidi implementar o RIT, que é o relatório de incidentes de tecnologia. &lt;/p&gt;

&lt;h2&gt;
  
  
  O que é feito em caso de incidente ou indisponibilidade
&lt;/h2&gt;

&lt;p&gt;Quando somos afetados por algum evento adverso, seguimos um fluxo de trabalho composto por 3 passos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TKuiEelX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k5sr1awrlae4af012za8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TKuiEelX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k5sr1awrlae4af012za8.png" alt="Fluxo 3 passos" width="685" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Identificar o problema (equipe responsável pelo serviço em questão é mobilizada para descobrir a causa raiz);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resolução rápida do problema (seja definitiva ou provisória com uma task mais estruturada para o futuro);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O time pensa em medidas preventivas e aprendizados para o problema em questão. Posteriormente, preenchemos um RIT (Relatório de incidente de Tecnologia).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  O que é o RIT ?
&lt;/h2&gt;

&lt;p&gt;Esse documento é preenchido no decorrer da reunião de post mortem, conforme vamos debatendo os pontos, vamos preenchendo e no final revisamos o que escrevemos. Logo de início, preenchemos uma descrição resumida do que aconteceu, seguido pela severidade do incidente, tipo de impacto, origem do alerta e a qual setor o incidente foi informado. &lt;/p&gt;

&lt;p&gt;Após essa análise inicial, partimos para o detalhamento do incidente, informamos qual foi a sua categoria, como por exemplo: alteração não planejada, não conformidade com a nossa política de segurança, falha de backup, ou alguma outra categoria ainda não catalogada. Após essa definição de categoria, descrevemos o que ocorreu, qual foi a extensão e impactos desse incidente, as causas e áreas envolvidas.&lt;/p&gt;

&lt;p&gt;Finalizando esse detalhamento do incidente, descrevemos como foi feito o tratamento desse incidente, descrevemos ações executadas para o tratamento ou contorno desse incidente com a maior riqueza de detalhes possível. E para terminar, fazemos uma análise final e encerramento do incidente, que é onde detalhamos se outras ações e recursos serão necessários para não acontecer outro incidente dessa natureza e se possível, informamos o prazo e os responsáveis por executar essas ações de melhorias. Além disso, descrevemos também sobre as lições aprendidas, o que tiramos de lição do incidente, o que aprendemos com o que ocorreu, e o que devemos fazer para não se repetir. Caso queira baixar o template desse documento, estamos deixando &lt;a href="https://images-convenia.s3.us-east-1.amazonaws.com/img/TEMPLATE%20-%20RIT%20-%20Relat%C3%B3rio%20de%20Incidente%20de%20Tecnologia.pdf"&gt;disponível aqui&lt;/a&gt;.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Importância de adotar esses processos.
&lt;/h2&gt;

&lt;p&gt;Adotar o post mortem e a partir daí, realizar o preenchimento de um RIT é essencial para conseguirmos periodicamente revisar os planos de ação para entender se eles foram implementados de fato. A partir desse conjunto de ferramentas é possível entender as falhas, entender o que aprendemos e mitigar os riscos, além de uma métrica e melhor entendimento dos incidentes passados. Outro ponto importante para defendermos essa implementação, é aumentar a cultura de aprender com os erros, erros irão acontecer, isso é normal no processo de produto, mas devemos aprender com eles e conseguir também tirar pontos positivos, para implementar melhorias ou melhorar algum processo quebrado que não temos visibilidade. &lt;/p&gt;

&lt;h2&gt;
  
  
  Caso real de uso na Convenia
&lt;/h2&gt;

&lt;p&gt;Além dos pontos já citados no artigo, destaco um grande aprendizado que conseguimos retirar nesse processo de post mortem + RIT.&lt;/p&gt;

&lt;p&gt;Sempre fizemos backups de todos nossos bancos e instâncias, mas de uma lição aprendida no preenchimento desses documentos, repensamos na nossa política, e após algumas análises, decidimos melhorar  nosso processo, começamos a fazer um backup contínuo, que é um backup que se existir perda, será de no máximo 5 minutos. &lt;/p&gt;

&lt;p&gt;Não só conseguimos melhorar nossos processos internos, como conseguimos também passar mais segurança e um melhor produto para o nosso cliente.&lt;/p&gt;

&lt;p&gt;Outro ponto a se destacar, é que de tempos em tempos, nos reunimos e fazemos um resumo de todos os relatórios preenchidos, e com isso, conseguimos visualizar se implementamos as melhorias apontadas, ou tem alguma pendente. No começo, apenas um squad seguia esse processo, mas com o passar do tempo, o restante do time consegue ver as vantagens, e atualmente todos os squads adotam essa prática.&lt;/p&gt;

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

&lt;p&gt;A reunião de postmortem é uma ferramenta fundamental para promover a melhoria contínua e o aprendizado organizacional. Um exemplo disso é o nosso case com o backup contínuo, que nos trouxe ainda mais segurança e melhora no nosso &lt;a href="https://aws.amazon.com/pt/blogs/mt/establishing-rpo-and-rto-targets-for-cloud-applications/"&gt;RTO e RPO&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ao permitir que as equipes revisitem processos passados, a reunião de postmortem possibilita a identificação de pontos fortes e fracos, além de fornecer insights valiosos para evitar erros futuros. É importante ressaltar que, para que a reunião de postmortem seja efetiva, é necessário estabelecer um ambiente seguro e confidencial para que os membros da equipe possam falar abertamente e expor suas ideias. Além disso, é preciso garantir que as discussões resultem em ações concretas e medidas para melhorias. O postmortem pode ajudar as equipes a evoluírem e aprimorarem seu desempenho, tornando-se mais eficientes e eficazes em suas atividades, e com isso, garantir mais satisfação ao cliente final.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A trilha DevOps</title>
      <dc:creator>Gustavo Schiavon</dc:creator>
      <pubDate>Mon, 27 Mar 2023 12:05:09 +0000</pubDate>
      <link>https://dev.to/convenia/a-trilha-devops-25ph</link>
      <guid>https://dev.to/convenia/a-trilha-devops-25ph</guid>
      <description>&lt;p&gt;Algum tempo atrás, prestes a completar 20 anos de carreira, e 40 de idade, parei para repensar minha vida como um todo, e claro, minha carreira faz parte dela. Parece crise de meia idade, mas não é exatamente isso, porém, isso é assunto para outro post.&lt;/p&gt;

&lt;p&gt;E antes que você se pergunte se DevOps é pra você, saiba que essa é uma trilha que atende tanto profissionais que vieram de infraestrutura como é o meu caso, quanto profissionais que vieram de desenvolvimento como é o caso do meu amigo e parceiro, o Tech Lead Leonardo Lemos, que gentilmente revisou esse texto, ou até profissionais que pretendem ingressar em TI.&lt;/p&gt;

&lt;p&gt;No momento que escrevo esse post, o mercado de tecnologia no Brasil tem um GAP de aproximadamente de 400 mil vagas, e a previsão é que esses números dobrem nos próximos dois anos, pois as faculdades formam bem menos profissionais do que o mercado busca, além da concorrência de empresas de fora que pagam em dólar ou em euro.&lt;/p&gt;

&lt;p&gt;Por fim, especialistas afirmam que a profissão de Platform Engineer estará entre as mais requisitadas do mercado no próximo ano.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;center&gt; Cloud Engineer, DevOps Engineer, SRE ou Plataform Engineer?
&lt;/center&gt;
&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%2Fyt7smrago29683brt1ru.jpg" 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%2Fyt7smrago29683brt1ru.jpg" alt="DevOps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com exceção do Cloud Engineer, para efeito de compreensão vamos tratar todas as demais funções como DevOps, visto que o stack delas é bem similar. “E o Cloud Engineer?” Ele já está englobado de certa forma na stack do DevOps, então não iremos focar neste texto.&lt;/p&gt;

&lt;p&gt;Um ponto interessante a citar sobre o Cloud Engineer, e é único que irei me ater, é que ele costuma ter uma visão multi-cloud, o que de certa forma amplia o leque de opções desse profissional frente ao mercado.&lt;/p&gt;

&lt;p&gt;E por fim, o que é o DevOps? Ele é Developer, ele é Infraestrutura, e ao mesmo tempo não é exatamente nenhum dos dois. Mas como assim? Vem comigo que eu te explico. Antes de mais nada, meu nome é Gustavo Schiavon, sou DevOps Engineer na Convenia, uma das pioneiras e principais HR Techs do Brasil.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;center&gt; Trilha DevOps
&lt;/center&gt;
&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%2Fow6tjgzt2ywinpq9dlqi.jpg" 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%2Fow6tjgzt2ywinpq9dlqi.jpg" alt="Mind"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A trilha DevOps engloba uma série de ferramentas, de diferentes finalidades, e sim, você precisa se especializar em ao menos uma de cada dessas ferramentas. Lembra do Cloud Engineer, então, a cloud é uma dessas ferramentas, afinal, você também é Infra.&lt;/p&gt;

&lt;p&gt;Além da cloud, você vai ter que se familiarizar com alguma ferramenta de CI/CD (lembre-se desse nome), observabilidade, mensageria, logs, repositório de código, testes, linguagem de programação (automação), container, orquestração de container, filas, e uma de infraestrutura como código, pois não se esqueça você também é Dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;center&gt; Vamos por partes, desmembrando e desmistificando a stack DevOps
&lt;/center&gt;
&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%2F6q40frnm13pwr3p4se40.jpg" 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%2F6q40frnm13pwr3p4se40.jpg" alt="Stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloud - Vamos começar pelo item sem o qual nada existe, e que sugiro que seja seu ponto de partida. Embora existam dezenas de players no mercado, os principais ainda são AWS, Azure, GCP, OCP. Todos eles permitem que você utilize grande parte dos serviços gratuitamente para testar, e alguns serviços ainda são gratuitos para sempre. De todas, a AWS é a maior e mais madura delas, e com uma ótima trilha de aprendizado na própria plataforma .&lt;/p&gt;

&lt;p&gt;CI/CD - Essa é a ferramenta, e porque não dizer, o conceito que melhor define a cultura DevOps. Imagine uma aplicação que “quase” nunca fica fora do ar. Sonho de todo plantonista, não é? Parte do que torna isso possível, são os pipelines CI/CD, que são instruções que irão dizer onde buscar o código, como buildar o container, que repositório salvar, e depois onde fazer o deploy. Alguns dos principais são o Jenkins, o Github Actions, e o Circle CI. O Jenkins costuma ser o mais usado.&lt;/p&gt;

&lt;p&gt;Observabilidade: Tem um ditado que diz, que não se mede aquilo que não se gerencia, também é verdade que ninguém gosta de ficar ao sabor do vento, ou ser pego de surpresa. Ferramentas de observabilidade, te dão um panorama sobre a saúde de seu ambiente, e te alertam em caso de falhas, ou uso de recursos acima do normal. Os principais são o Prometheus, o Zabbix e o CloudWatch para quando se trabalha com AWS. Assim como o Zabbix costumava ser a principal opção para ambientes on premises, o Prometheus é uma solução muito difundida na cloud. Em ambos os casos, e para o CloudWatch também, é comum se usar o Grafana para centralizar os dados.&lt;/p&gt;

&lt;p&gt;Mensageria: Foi se o tempo que a mensageria servia somente para trocar informações entre pessoas, hoje esses recursos estão diretamente ligados a ferramentas de monitoramento, por exemplo, para alarmar o time em tempo real, caso algo relevante deva ser analisado. Alguns bons exemplos de recursos assim são o Slack, HipChat e o IRC. O Slack é uma opção bastante utilizada, e que permite diversos tipos de integrações, como hooks, api token, entre outros.&lt;/p&gt;

&lt;p&gt;Logs: Se observabilidade te diz que tem algo errado, são os logs que vão dizer exatamente o que é, ou seja, saber que sua máquina está com alto consumo de CPU é importante, mas melhor que isso, é entender o que em sua aplicação está ocasionando isso. Exemplo de ferramentas que entregam essa visão é o Loki, o Sentry e o New Relic. Mas uma solução muito utilizada é a pilha ELK, que é composta pelo trio ElasticSearch, LogStash e Kibana.&lt;/p&gt;

&lt;p&gt;Repositório de código: Tão importante quanto ter um código limpo, é ter um código versionado, e revisado. Para nossa sorte existem diversas soluções, que auxiliam nesse trabalho. As principais são o GitLab, GitHub e o GitBucket. O GitHub costuma ser o mais utilizado.&lt;/p&gt;

&lt;p&gt;Testes: Assim como a maioria dos processos nessa cultura, os testes da aplicação devem ser rotinas automatizadas (testes sintéticos), até para que isso também entre numa esteira de monitoramento, e possamos ter controle se algum recurso não está disponível, ou se o tempo de resposta não está adequado. Algumas opções são o Selenium, Cucumber e o Datadog. Na Convenia utilizamos o Datadog para fazer monitoramento sintético e gerar métricas de SLI (indicador de nível de serviço), e atrelado a ele temos um OKR (objetivos e resultados chave). &lt;/p&gt;

&lt;p&gt;Linguagem de programação: Embora essa não seja o foco principal do DevOps, é importante saber lógica de programação, até porque para criar rotinas de automação, quase sempre será necessário criar um código para isso. A primeira linguagem que se deve ter em mente pensando nisso é o Python, além de entender de Shell Script e dependendo da trilha, Powershell. Assim como o Python costuma ser utilizado como uma das principais linguagens para automação, o Shell Script é o recurso nativo no Linux, que permite criar scripts para automatizar processos, a propósito, se você ainda não conhece de Linux, principalmente a parte de terminal, recomendo fortemente que estude.&lt;/p&gt;

&lt;p&gt;Container: Toda aplicação moderna, é desenhada para rodar na forma de micro serviço. Sendo assim, é fundamental entender de container, como eles trabalham, como conversam com o servidor, e como entregam a aplicação. Embora existam outras opções no mercado como o Podman, sugiro fortemente que você estude Docker, que é o padrão que o mercado trabalha, e é um recurso que se pode subir facilmente através do terminal do Linux.&lt;/p&gt;

&lt;p&gt;Orquestração de Container: Trabalhar com containers stand alone é possível, mas é sofrível, além de fugir a maioria das vezes da cultura de DevOps de entrega contínua. Assim, existe uma forma mais amigável de entrega e gestão de containers que é através de um orquestrador. Ele vai entregar de uma melhor forma, e gerenciar possíveis quedas, por exemplo. O padrão do mercado em orquestração de containers Docker é o Kubernetes, mas o Swarm também é usado, principalmente pelo fato de sua implementação ser muito mais simples que a do Kubernetes.&lt;/p&gt;

&lt;p&gt;Filas: Os módulos de uma aplicação dividida em micro serviços, podem receber muitas requisições, assim como podem ocorrer de um desses módulos ficar indisponível quando outro módulo requisitar, ou precisar entregar um recurso. Um sistema de filas, opera fazendo a gestão dessas requisições e entregas de forma mais ordenada e assíncrona. O RabbitMQ assim como o Kafka fazem essa gestão.&lt;/p&gt;

&lt;p&gt;Infraestrutura como código: A cereja do bolo sem dúvida é a infraestrutura como código, é ela que transforma o profissional de Infra em Dev e vice-versa. Embora não seja 100% necessária, é ela que permite ter todas as vantagens de dev em infra, como code-review, versionamento, etc. Diversas linguagens são bastante usadas para provisionar infraestrutura, como o Terraform, Ansible, Puppet e Chef. De todas elas, recomendo começar pelo Terraform, que além de ser amplamente utilizado para provisionar recursos em diversas tecnologias, é desenvolvido pela HashiCorp, que desenvolve outras soluções voltadas para cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;center&gt; E como eu entro nessa?
&lt;/center&gt;
&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%2F39y8zdkabr00c1r4sccj.jpg" 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%2F39y8zdkabr00c1r4sccj.jpg" alt="Start"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sugiro então que se prepare, e não tenha medo de dar um passo pra trás. “Mas eu já sou um Dev ou Infra Senior, mesmo assim vou ter que retornar duas casas?” Sim, vai, “cada escolha é uma renúncia, isso é a vida”. Então sente-se, ponha suas prioridades na balança, e pontue as vantagens de permanecer onde está, ou viver esse novo momento em sua carreira. &lt;/p&gt;

&lt;p&gt;Chegou a conclusão que é isso mesmo que você quer, então separe um tempo do seu dia para estudar, crie contas nas plataformas, pesquise, pergunte, participe de grupos de WhatsApp, Telegram, Discord, fóruns de discussão, e quando sentir segurança, se candidate em processos para medir a febre, a grande maioria tem desafios onde você poderá colocar em prática o que aprendeu até agora. &lt;/p&gt;

&lt;p&gt;Agora é com você, e se precisar de uma força, é só chamar!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Cibersecurity, construindo um firewall humano.</title>
      <dc:creator>Yan Porfirio</dc:creator>
      <pubDate>Fri, 13 Jan 2023 12:46:19 +0000</pubDate>
      <link>https://dev.to/convenia/cibersecurity-construindo-um-firewall-humano-5f54</link>
      <guid>https://dev.to/convenia/cibersecurity-construindo-um-firewall-humano-5f54</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Olá pessoal, tudo bem ? Me chamo Yan e hoje sou analista de segurança da informação na Convenia. Recentemente, iniciamos uma jornada de conscientização e treinamentos relacionados à segurança da informação e LGPD com todos os nossos colaboradores. A plataforma escolhida para nos apoiar foi a Hacker Rangers! Com a ajuda desse parceiro e o engajamento dos nossos colaboradores, começamos a colher muitos bons frutos relacionados à proteção de dados aqui na Convenia. No decorrer deste artigo, irei pontuar os desafios encontrados, algumas mudanças positivas e os resultados refletidos no dia a dia da nossa empresa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Análise inicial
&lt;/h2&gt;

&lt;p&gt;Para entender onde estávamos, me baseei em um teste phishing realizado por uma outra plataforma há alguns meses antes de iniciarmos esse novo formato de treinamentos, e o resultado de cliques nesse teste era de 35%. Além desse número expressivo, notamos que os colaboradores não consumiam um conteúdo de qualidade e da forma adequada, dificultando assim uma conscientização assertiva e a usabilidade dessas informações no dia a dia. &lt;/p&gt;

&lt;h2&gt;
  
  
  Desafios iniciais
&lt;/h2&gt;

&lt;p&gt;Encontramos alguns desafios para implementar o nosso programa de conscientização. Acredito que vale a pena pontuar dois:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;O primeiro foi a dificuldade de manter o engajamento dos colaboradores. Geralmente, os conteúdos de cibersegurança costumam ser maçantes, pouco interativos e repletos de um linguajar mais técnico. Dessa forma, torna-se muito difícil “prender” a atenção dos colaboradores, que não estão acostumados com alguns termos sobre o assunto.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O segundo desafio encontrado logo no início da caminhada foi a dificuldade de realizar testes de phishing em massa. A maioria das plataformas oferece um modelo “travado”, que não podemos mudar, ou que sempre cai no spam na caixa de e-mail. Isso acaba não só dificultando a execução do teste, mas também mascarando o resultado real.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hacker Rangers ao resgate !
&lt;/h2&gt;

&lt;p&gt;Após identificarmos esses desafios, começamos uma parceria com a plataforma Hacker Rangers, que oferece conteúdos sobre cibersegurança e LGPD de uma maneira mais leve, com cursos de curta duração e linguagem de fácil entendimento.&lt;/p&gt;

&lt;p&gt;Mas o principal é que ela nos permite criar um ciclo de competição gamificada, que acende um espírito de competitividade e mantém os colaboradores engajados durante toda a temporada, que dura 12 semanas.&lt;/p&gt;

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

&lt;p&gt;Essa ferramenta também conseguiu nos atender na questão do teste de phishing, já que a plataforma é toda interativa e nos proporciona a opção de editar o e-mail da maneira que queremos. Além disso, caso exista alguma interação do usuário com a mensagem, como um clique no e-mail ou uma submissão de dados, ele é automaticamente direcionado para uma página que o avisa que ele caiu em um teste de phishing simulado, que também apresenta algumas orientações para que isso não volte a acontecer.&lt;/p&gt;

&lt;p&gt;A ideia no nosso teste de phishing não é prejudicar ou enganar nossos colaboradores, mas, sim, medir o nosso grau de maturidade em segurança e, principalmente, treiná-los para não cair em phishings reais, visto que esse tipo de golpe cresce de maneira assustadora dia após dia. E ter recursos para disparar e-mails personalizados, com a nossa identidade visual e com o domínio o mais próximo do nosso, nos ajuda muito nessa tarefa de conscientização e treinamento para situações reais.&lt;/p&gt;

&lt;p&gt;Após pouco mais de 3 meses, começamos a colher os resultados desse programa de conscientização e treinamentos. Conforme dito anteriormente, em nosso último teste de phishing, realizado antes do começo desse programa, o índice de clique dos colaboradores era de 35%. No teste mais recente, após o início da conscientização com o Hacker Rangers, conseguimos diminuir esse índice para 6,4%. Sabemos que em uma campanha phishing existem diversos fatores subjetivos, mas esses números já nos fornecem um norte para onde seguir.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  O papel das ciberatitudes na construção de um firewall humano
&lt;/h2&gt;

&lt;p&gt;Além de uma melhoria expressiva no número de cliques em simulações de phishing, o que mais nos chamou a atenção foi a mudança de cultura dos colaboradores. Depois desses três meses, quando eles recebem qualquer e-mail suspeito ou com algum conteúdo estranho, antes de clicarem em qualquer coisa, eles me procuram e pedem orientação, ou denunciam como spam e depois me notificam. O mais legal é que a plataforma oferece uma ferramenta típica para isso: as chamadas “Ciberatitudes”, um espaço onde o colaborador pode dar dicas e sugestões variadas e, o mais importante, reportar os riscos de segurança identificados na empresa.&lt;/p&gt;

&lt;p&gt;Essa mudança era o que esperávamos de fato. Uma mudança de cultura, uma criação de um “firewall humano”, pois se todos estiverem engajados e consumindo um conhecimento de qualidade, todos estarão preparados para identificar ameaças, reportar riscos em potencial e não cair em golpes — não só no ambiente corporativo, mas também na sua vida pessoal!&lt;/p&gt;

&lt;p&gt;Esse foi outro ponto importante para nós: não criar apenas colaboradores mais conscientes, mas pessoas mais conscientes, que compartilham o conteúdo aprendido com seus amigos e familiares, difundindo esse conhecimento e diminuindo cada vez mais os crimes virtuais. Na imagem abaixo, podemos ver como os colaboradores interagem e dão feedbacks via Ciberatitudes: &lt;/p&gt;

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

&lt;p&gt;O nosso objetivo é diminuir ainda mais os números obtidos no último teste de phishing. Após o encerramento da temporada, convidamos toda a empresa para uma reunião e, conforme demonstrado na imagem abaixo, apresentamos o resultado alcançado e demos dicas de como não cair em futuros testes de phishing — e, principalmente, em phishings reais.&lt;/p&gt;

&lt;p&gt;Alertamos a todos de existem alguns padrões em tentativas de golpes online, tais como: assuntos urgentes ou que exigem uma rápida resposta; produtos milagrosos que prometem resolver seus problemas de forma rápida e simples; erros ortográficos; anexos suspeitos; e, claro, a solicitação de conteúdo sigiloso.&lt;/p&gt;

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

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

&lt;p&gt;Compartilhamos da ideia de que nossos clientes são a alma e a razão da nossa existência e merecem sempre o melhor. E, visando oferecer esse melhor a eles, conseguimos, após a nossa primeira temporada, a certificação White Certified, concedida pela Hacker Rangers.&lt;/p&gt;

&lt;p&gt;Essa é uma forma de reconhecimento para empresas que realizam programas de conscientização em cibersegurança de forma engajada e positiva, que incentivam a mudança de comportamento no trabalho e na vida pessoal e que obtêm, como resultado, colaboradores com amplo conhecimento das políticas da empresa, que atuam ativamente para prevenir e reportar incidentes.&lt;/p&gt;

&lt;p&gt;Nosso anseio agora é manter os nossos colaboradores engajados e aumentar cada vez mais a excelência do nosso programa! &lt;/p&gt;

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

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

&lt;p&gt;Após esse tempo de maturação do nosso programa, constatamos que um programa de conscientização é fundamental para qualquer empresa, pois, com uma campanha bem construída, conseguimos oferecer conteúdo de qualidade e informações importantes para nossos colaboradores.&lt;/p&gt;

&lt;p&gt;Agora, eles conseguem refletir analiticamente sobre cada ação a ser executada, aumentando, assim, o nosso grau de maturidade em questões de segurança. Como consequência, conseguimos oferecer um produto ainda mais seguro para o nosso cliente!&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Mongo Atlas, porque utilizar o recurso de VPC Peering no seu cluster?</title>
      <dc:creator>Leonardo Lemos</dc:creator>
      <pubDate>Thu, 29 Dec 2022 12:39:52 +0000</pubDate>
      <link>https://dev.to/convenia/mongo-atlas-porque-utilizar-o-recurso-de-vpc-peering-no-seu-cluster-32cn</link>
      <guid>https://dev.to/convenia/mongo-atlas-porque-utilizar-o-recurso-de-vpc-peering-no-seu-cluster-32cn</guid>
      <description>&lt;p&gt;Nesse post quero compartilhar uma dica bem valiosa que adotamos na &lt;a href="https://convenia.com.br" rel="noopener noreferrer"&gt;Convenia&lt;/a&gt;. Nossa stack é composta de microserviços e utilizamos extensamente MongoDB e RabbitMQ, esse último para comunicação entre os serviços, como mostrado &lt;a href="https://imasters.com.br/php/aprenda-agora-arquitetura-event-driven-com-laravel-pigeon" rel="noopener noreferrer"&gt;nesse post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Toda infra da Convenia roda dentro da AWS e a AWS não tem uma boa opção gerenciada de MongoDB ou RabbitMQ, então utilizamos o &lt;a href="https://www.mongodb.com/atlas/database" rel="noopener noreferrer"&gt; Mongo Atlas&lt;/a&gt; e o &lt;a href="https://www.cloudamqp.com/" rel="noopener noreferrer"&gt;CloudAmqp&lt;/a&gt; para aliviar o trabalho de manutenção nesses serviços.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problemas
&lt;/h2&gt;

&lt;p&gt;Vamos tomar como exemplo a comunicação entre o serviço gerenciado do Mongo Atlas e a nossa aplicação, após provisionar tudo da maneira mais simples devemos chegar a essa arquitetura:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxp72kpmz1g7tzybt5v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxp72kpmz1g7tzybt5v1.png" alt="Diagrama Mongo Atlas sem VPC Peering" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na verdade isso funciona relativamente bem, a aplicação funcionaria de maneira aceitável no entando parece um caminho longo da nossa aplicação(API) até o banco de dados o que não é o ideal, na verdade o banco de dados deve ficar o mais "perto" possível da nossa aplicação, na arquitetura acima eu consigo pontuar alguns problemas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Custo: o &lt;a href="https://docs.aws.amazon.com/pt_br/vpc/latest/userguide/vpc-nat-gateway.html" rel="noopener noreferrer"&gt;NAT gateway&lt;/a&gt; faz parte de toda arquitetura de rede que inclui uma subnet privada, a grosso modo ele é responsável por prover acesso à internet aos componentes internos da rede. O gande problema é que esse NAT é um elemento caro na infraestrutura pois tem um custo apenas por existir(pois tem ip público) e também cobra um custo relativo ao tráfego que passa por ele. No nosso caso os dados da nossa aplicação estão passando por ele para chegar ao MongoDB, o mesmo não aconteceria se o banco estivesse dentro da mesma subnet da aplicação, nesse caso a aplicação conseguiria conversar diretamente com o banco.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance: Claro, sair pelo internet gateway para internet e passar "sei la por onde" até chegar no nosso banco de dados vai introduzir um pouco de latência e naturalmente diminuir a resiliência da aplicação, o mesmo não aconteceria com um banco na mesma subnet da nossa aplicação.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Segurança: De todos os pontos, este é o item mais preocupante, principalmente no caso da Convenia que trafega dados pessoais em época de LGPD. A conexão entre a aplicação e os serviços externos é criptografada, isso significa que é relativamente segura pois mesmo se o tráfego for interceptado os dados não podem ser acessados. Mas mesmo com a criptografia é desconcertante ter o tráfego suscetível a um ataque, seria melhor se esses dados nem passassem pelo mundo externo.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Pensando bem, nosso cluster de MongoDB está provisionado dentro da AWS, nossa aplicação também está dentro da AWS, nossa aplicação realmente precisa fazer toda essa volta para chegar até o banco? Para o nosso bem a resposta para essa pergunta é "não", quase todos os possíveis serviços que você pode pensar em consumir oferecem uma maneira de garantir que a comunicação com eles permaneça inteiramente dentro da AWS, a maneira mais comum é o &lt;a href="https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html" rel="noopener noreferrer"&gt;VPC Peering&lt;/a&gt; que tanto o &lt;a href="https://www.mongodb.com/docs/atlas/security-vpc-peering/" rel="noopener noreferrer"&gt;Mongo Atlas&lt;/a&gt; quanto o &lt;a href="https://www.cloudamqp.com/blog/amazon-vpc-peering.html" rel="noopener noreferrer"&gt;CloudAmqp&lt;/a&gt; fornecem. O &lt;a href="https://www.datadoghq.com/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; por exemplo fornece um &lt;a href="https://docs.datadoghq.com/agent/guide/private-link/?tab=useast1" rel="noopener noreferrer"&gt;endpoint&lt;/a&gt; para acesso direto, dessa forma todo o tráfego permanece dentro da rede interna da AWS e nem passa pelo NAT Gateway.&lt;/p&gt;

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

&lt;p&gt;Após criar o VPC Peering do Mongo Atlas como &lt;a href="https://www.mongodb.com/docs/atlas/security-vpc-peering/" rel="noopener noreferrer"&gt;nesse passo a passo&lt;/a&gt;, chegamos na arquitetura acima, essa arquitetura é muito mais segura, performática e elimina o custo do NAT Gateway. A outra arquitetura nem deveria ser considerada, principalmente se a empresa trabalha com dados sensíveis. Perceba que no diagrama acima nem aparecem os "Internet Gateways", isso porque a partir de agora a aplicação vai consumir a aplicação diretamente através do Peering.&lt;/p&gt;

&lt;p&gt;Com relação aos problemas apontados anteriormente, uma vez que não precisamos mais sair para internet para chegar até nosso banco de dados, o custo com Tráfego do Nat Gateway deve reduzir, talvez se nossa aplicação não precisar de algum outro recurso interno seria possível até remover o NAT Gateway.&lt;/p&gt;

&lt;p&gt;O banco de dados já estava próximo à nossa aplicação, nossa aplicação apenas não conseguia chegar até ele da maneira mais fácil, após fazer o Peering nossa aplicação passa a conhecer o melhor caminho até o banco, ficando a poucos saltos do banco e melhorando a performance e resiliência.&lt;/p&gt;

&lt;p&gt;Por último devemos notar que agora é impossível de um elemento desconhecido interceptar o tráfego entre nossa aplicação e o banco, isso diminui muito a superfície de ataque que um suposto Hackerzinho malvado poderia utilizar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Últimas configurações
&lt;/h2&gt;

&lt;p&gt;Agora já conseguimos atingir 90% dos nossos objetivos, mas para finalizar precisamos impedir que o Mongo Atlas seja acessível externamente. Geralmente esse tipo de serviço gerenciado relacionado a infraestrutura tem uma área de Network como a do Atlas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivluxb4oxaobf129bhn8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivluxb4oxaobf129bhn8.png" alt="Configurando regras de acesso ao cluster de mongo" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A imagem acima contém as regras de acesso da Convenia para o Atlas, temos dois peerings logo temos 2 regras de acesso permitindo apenas acessos vindos das 2 VPCs da Convenia. Aqui o ideal é remover qualquer regra permitindo o intervalo &lt;code&gt;0.0.0.0/0&lt;/code&gt;, esse intervalo permite acesso global ao cluster.&lt;/p&gt;

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

&lt;p&gt;A utilização de recursos como VPC Peering e VPC Endpoints podem aumentar a performance e melhorar a segurança da sua aplicação, bem como diminuir o custo com tráfego no Nat gateway. Aliás mantenha distância do Nat gateway, saia para internet apenas quando for realmente necessário. &lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>aws</category>
      <category>convenia</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Utilizando uma imagem base para suas aplicações PHP</title>
      <dc:creator>Leonardo Lemos</dc:creator>
      <pubDate>Thu, 28 Jul 2022 18:04:00 +0000</pubDate>
      <link>https://dev.to/convenia/utilizando-uma-imagem-base-para-suas-aplicacoes-php-1g8a</link>
      <guid>https://dev.to/convenia/utilizando-uma-imagem-base-para-suas-aplicacoes-php-1g8a</guid>
      <description>&lt;p&gt;Para garantir a padronização das aplicações e facilitar o trabalho do dia a dia, na &lt;a href="//convenia.com.br"&gt;Convenia&lt;/a&gt;, utilizamos uma imagem base para todas as aplicações. O proposito desse post é mostrar as vantagens dessa abordagem e como criar suas aplicações a partir dessa imagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Porque padronizar a imagem base?
&lt;/h2&gt;

&lt;p&gt;Na &lt;a href="//convenia.com.br"&gt;Convenia&lt;/a&gt; temos uma stack bem homogênea quase que inteiramente em &lt;a href="https://www.php.net/" rel="noopener noreferrer"&gt;PHP&lt;/a&gt;, manter uma imagem diferente em cada projeto aumenta a chance de aparecer um problema específico com uma versão específica de uma biblioteca que está instalada apenas em um projeto, o desenvolvedor que mantém esse projeto terá que resolver esse problema e não terá como reaproveitar o conhecimento dos amigos visto que esse problema ocorreu apenas no projeto dele.&lt;/p&gt;

&lt;p&gt;Seguindo a mesma linha de raciocínio imagine o quão diferente os setups podem parecer sem uma padronização, manter essa padronização ajuda bastante quando o desenvolvedor muda de projeto ou mesmo quando ele faz um "merge request" em um outro projeto, dessa forma ganhamos agilidade por não ter que estudar especificidades de cada projeto.&lt;/p&gt;

&lt;p&gt;Novas features e correções de bugs são centralizadas em apenas uma imagem ao invés de serem feitas em cada projeto.&lt;/p&gt;

&lt;p&gt;Bom e finalmente eliminamos o famoso "na minha maquina funciona". Já que estamos utilizando um container padronizado no ambiente de desenvolvimento porque não utilizar o mesmo container em ambiente de produção(com alguns cuidados claro)? Isso praticamente erradica a possibilidade de ocorrer um erro proveniente da discrepância entre uma biblioteca visto que quase todas as bibliotecas vão ser idênticas. Esse risco só não é nulo porque inevitavelmente vamos ter que instalar alguma extensão antes de enviar para produção(opcache por exemplo).&lt;/p&gt;

&lt;p&gt;Em algum momento teremos que gerar uma nova imagem a partir da imagem base contendo a aplicação para rodar em produção. Se todos os projetos tem a necessidade de ter um webserver por exemplo porque não adicionar esse webserver já na imagem base? Isso vai tornar a etapa de build do pipeline muito mais rápida visto que passamos a maioria das coisas comuns aos projetos para a imagem base, temos um deploy mais ágil!&lt;/p&gt;

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

&lt;p&gt;Para rodar uma aplicações PHP da forma convencional são necessários 2 containers, o &lt;a href="https://www.php.net/manual/pt_BR/install.fpm.php" rel="noopener noreferrer"&gt;PHP-FPM&lt;/a&gt; e um servidor web como &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;nginx&lt;/a&gt; ou &lt;a href="https://httpd.apache.org/" rel="noopener noreferrer"&gt;apache&lt;/a&gt;. Rodar esses 2 componentes separadamente, apesar de ser o recomendado, demanda que o desenvolvedor mergulhe em detalhes referentes à comunicação entre os containers e até mesmo configuração de volumes, muitas vezes esses detalhes não são interessantes no momento, desenvolvedores iniciantes se sentem bem perdidos nesses detalhes.&lt;/p&gt;

&lt;p&gt;Analisando outras stacks como nodejs vamos perceber que é relativamente mais simples containerizar esse tipo de aplicação, pois o próprio processo do node já é capaz de servir os requests sendo necessário apenas um container, mas e se podessemos rodar uma aplicação PHP com a mesma simplicidade? Essa é a proposta da imagem &lt;a href="https://hub.docker.com/r/convenia/php-full" rel="noopener noreferrer"&gt;PHP Full&lt;/a&gt; que utilizamos aqui na convenia como imagem base de todas as aplicações PHP.&lt;/p&gt;

&lt;p&gt;Vamos executar a imagem PHP Full com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -p 80:80 convenia/php-full:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comando acima executa um container apartir da image &lt;code&gt;convenia/php-full:latest&lt;/code&gt; e binda a porta 80 do container à porta 80 do host, logo ao entrar no nosso localhost pelo browser(em windows e macOS pode ser necessário utilizar o IP da vm do docker, dependendo do seu setup) devemos ver a página da documentação:&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%2Fic7jr0iph4i64wxx0ovf.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%2Fic7jr0iph4i64wxx0ovf.png" alt="Página padrão do container contendo a documentação"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essa documentação é um arquivo PHP, isso significa que a imagem já está pronta para servir nossa aplicação, tudo que precisamos fazer é colocar nossa aplicação dentro do diretório &lt;code&gt;/var/www/app&lt;/code&gt; que é onde a imagem procura por padrão.&lt;/p&gt;

&lt;p&gt;Para fazer um lab bem rápido vamos executar um comando no terminal para instalar uma aplicação &lt;a href="https://laravel.com/" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt; fresh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --user 1000 --rm -v $(pwd):/app composer create-project laravel/laravel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso deve utilizar o &lt;a href="https://getcomposer.org/" rel="noopener noreferrer"&gt;composer&lt;/a&gt; para criar uma aplicação Laravel bem na pasta em que executamos o comando. Em seguida vamos executar o seguinte comando para criar um container "colocando" a aplicação Laravel que criamos no passo anterior dentro da pasta &lt;code&gt;/var/www/app&lt;/code&gt;, é nessa pasta que o webserver dentro do container olha para servir a aplicação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -p 80:80 -v $(pwd)/laravel:/var/www/app convenia/php-full:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após executar o comando podemos entrar no nosso browser novamente porém agora o resultado é esse:&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%2Fpaknc650djxtq735n2wo.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%2Fpaknc650djxtq735n2wo.png" alt="Página padrão do Laravel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pronto finalmente estamos rodando nossa aplicação PHP dentro do container, e tudo que fizemos foi copiar a aplicação para uma pasta específica dentro do container, esse é o propósito dessa imagem, prover uma forma simples e segura para executar aplicações PHP podendo ser utilizado em ambiente de desenvolvimento e produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando um arquivo Docker Compose
&lt;/h2&gt;

&lt;p&gt;Já sabemos como utilizar nossa imagem porém em um ambiente real podemos sentir a necessidade de rodar mais de um container, containers de serviços como mysql e redis para nossa aplicação e o próprio container da nossa aplicação pode começar a ficar complexo pois pode surgir a necessidade de utilizar mais volumes, podemos definir uma network para isolar nossa aplicação. Logo o comando para rodar esse container vai ficando cada vez mais complexo e rodar a stack completa se torna uma tarefa árdua. Para resolver esse problema utilizamos um arquivo &lt;code&gt;docker-compose.yml&lt;/code&gt; que deve ser criado na raiz do projeto:&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.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;app&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;convenia/php-full:latest&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;application&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;.:/var/www/app&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;80:80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse arquivo contém todos os detalhes que incluímos via linha de comando quando rodamos nosso container e ele é versionado junto com a aplicação, dessa forma qualquer pessoa que pegar o projeto consegue executar a stack toda com um único comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após executar esse comando devemos ver o mesmo resultado de quando utilizamos o comando anterior, devemos ver a aplicação rodando no browser.&lt;/p&gt;

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

&lt;p&gt;Com certeza padronizar uma imagem base nos seus projetos não vai resolver todos os seus problemas mas ajuda a diminuir a complexidade na implantação e evita silos de conhecimento relacionados ao setup local, espero ter contribuído com esse post, deixe sua opinião nos comentários ou me da um grito no &lt;a href="https://twitter.com/ConveniaTech" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Os cuidados para um deploy "Zero Down Time"</title>
      <dc:creator>Leonardo Lemos</dc:creator>
      <pubDate>Tue, 07 Dec 2021 21:36:15 +0000</pubDate>
      <link>https://dev.to/convenia/os-cuidados-para-um-deploy-zero-down-time-5a3</link>
      <guid>https://dev.to/convenia/os-cuidados-para-um-deploy-zero-down-time-5a3</guid>
      <description>&lt;p&gt;Atualmente existem ferramentas que nos ajudam a executar containers em produção e a maioria delas trazem funcionalidades preciosas como "Health Checks", "Limite de recursos" e até mesmo prometem um deploy &lt;a href="https://avikdas.com/2020/06/30/scalability-concepts-zero-downtime-deployments.html"&gt;"Zero Down Time"&lt;/a&gt;, o foco deste post é nesse último Item. Na &lt;a href="https://convenia.com.br/"&gt;Convenia&lt;/a&gt; utilizamos o &lt;a href="https://docs.docker.com/engine/swarm/"&gt;Docker Swarm&lt;/a&gt; para gerenciar alguns containers em produção e o Docker Swarm entrega esse tipo de deploy "Zero Down Time" através de uma simples configuração, porém após alguns testes em uma API sob stress constatamos que sempre ocorriam alguns erros no momento do deploy. Aprofundando a análise do que poderia causar esses erros, percebemos que podemos cometer alguns "equívocos" que nos impedem de ter um deploy verdadeiramente sem Down Time e ainda podemos constatar que esses "equívocos" são comuns em outras ferramentas como &lt;a href="https://kubernetes.io/pt-br/"&gt;Kubernetes&lt;/a&gt; também, dai saiu a motivação para escrever esse post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Graceful ShutDown
&lt;/h2&gt;

&lt;p&gt;A grosso modo podemos definir "Graceful shutdown" como a maneira "natural" em que um processo é desligado. Muitos processos abrem sockets e trabalham com estado em memória então para esses processos desligarem naturalmente muito provavelmente eles vão fechar as conexões abertas e persistirem o estado, que está na memória, no HD para que não haja perda de dados e para poder retomarem as atividades sem maiores problemas quando forem reiniciados, em uma queda de energia por exemplo, os processos não tem esse privilégio, nesse caso podemos nos deparar com erros durante a próxima inicialização do processo, isso é conhecido como "Hard Shutdown".&lt;/p&gt;

&lt;p&gt;A boa notícia é que todos os softwares mais difundidos fazem isso por padrão, o &lt;a href="https://www.nginx.com/"&gt;nginx&lt;/a&gt; quando recebe o "sinal" de desligamento espera a resposta de todos os requests que estão em execução no momento, antes de desligar de fato. Esse "Graceful Shutdown" é importante porque o deploy consiste na "troca" de um processo com a versão antiga do software pelo mesmo processo contendo a versão nova, ao desligar o processo contendo a versão antiga, os requests que estiverem em execução não podem falhar, pois eles ainda estão sendo respondidos pelo processo antigo enquanto os novos requests já estão sendo servidos pelo processo novo como mostrado na imagem abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kti9Rd0V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ft293jsqsbem1iyh7dbf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kti9Rd0V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ft293jsqsbem1iyh7dbf.png" alt="Troca dos containers em um deploy" width="741" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na &lt;a href="https://convenia.com.br"&gt;Convenia&lt;/a&gt; temos muitos listeners feitos com o &lt;a href="https://convenia.github.io/Pigeon/#/"&gt;Pigeon&lt;/a&gt;, nesse caso não estamos falando de um webserver e sim de um &lt;a href="https://convenia.github.io/Pigeon/#/EVENT_DRIVEN?id=listening-for-events"&gt;consumer&lt;/a&gt; que "ouve" uma fila do &lt;a href="https://www.rabbitmq.com/"&gt;RabbitMQ&lt;/a&gt;, você já deve imaginar que para "ouvir" essa fila temos que ter uma conexão aberta com o &lt;a href="https://www.rabbitmq.com/"&gt;RabbitMQ&lt;/a&gt; então nada mais justo que fechar as conexões no momento em que o processo for desligado, é justamente isso que o &lt;a href="https://convenia.github.io/Pigeon/#/"&gt;Pigeon&lt;/a&gt; faz no código a seguir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;listenSignals&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;defined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AMQP_WITHOUT_SIGNALS'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'AMQP_WITHOUT_SIGNALS'&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="nb"&gt;pcntl_async_signals&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="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SIGTERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'signalHandler'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'signalHandler'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nb"&gt;pcntl_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SIGQUIT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'signalHandler'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;signalHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$signalNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$signalNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;SIGTERM&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;// 15 : supervisor default stop&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;quitHard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;SIGQUIT&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;// 3  : kill -s QUIT&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;quitHard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="no"&gt;SIGINT&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="c1"&gt;// 2  : ctrl+c&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;break&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;Nesse código definimos handlers para os sinais de desligamento que o processo pode receber e chamamos os métodos &lt;code&gt;quit()&lt;/code&gt; e &lt;code&gt;quitHard()&lt;/code&gt; que têm como objetivo fechar a conexão com o RabbitMQ. Até agora falamos muito sobre esses sinais que os processos podem receber de outro processos, ou até mesmo do kernel, mas caso você não estaja familiarizado ou se não souber exatamente a diferença entre eles, você pode ficar um pouco mais por dentro &lt;a href="https://www.ctl.io/developers/blog/post/gracefully-stopping-docker-containers/"&gt;nesse artigo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  PID 1
&lt;/h2&gt;

&lt;p&gt;Quando utilizamos &lt;a href="https://www.docker.com/"&gt;docker&lt;/a&gt; para executar nossa aplicação em produção e fazemos um deploy, um container com a nova versão da aplicação é iniciado,o container com a versão antiga da aplicação recebe o sinal "SIGTERM" que é um pedido formal de desligamento, caso o container demore mais que 10 segundos para  desligar ele será morto, logo o processo dentro do container tem 10 segundos para fazer o seu "Graceful Shutdown". A grande pegadinha é que dentro do container apenas o processo de ID 1 vai receber esse sinal, se dentro do container iniciarmos um outro processo antes da nossa aplicação, esse processo vai portar o id 1 e não a nossa aplicação. Agora que temos outro processo recebendo os sinais de desligamento no lugar da nossa aplicação, nunca vamos ter a oportunidade de fazer um Graceful Shutdown porque nunca saberemos o momento de desligar, por mais que esse pareça um erro bobo na verdade isso acaba acontecendo com uma certa frequência como por exemplo nos &lt;a href="https://docs.docker.com/engine/reference/builder/"&gt;Dockerfiles&lt;/a&gt; a seguir:&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="s"&gt; nginx:latest&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["nginx", "-g", "daemon off;"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Dockerfile acima está com o &lt;code&gt;ENTRYPOINT&lt;/code&gt; no formato de array, se você entrar dentro do container gerado por esse Dockerfie e executar o comando &lt;code&gt;pstree&lt;/code&gt; verá o seguinte output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_7H596n2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/du8k1y9gv6pgpl7bii58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_7H596n2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/du8k1y9gv6pgpl7bii58.png" alt="Output do comando pstree em um container corretamente configurado" width="756" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perceba que o "nginx" é o primeiro processo mais a esquerda, isso significa que atingiremos o objetivo de ter um Graceful Shutdown visto que o nginx vai receber os sinais pessoalmente e ele sabe muito bem como lidar, para tirar a dúvida podemos executar um &lt;code&gt;docker stop&lt;/code&gt; no container em execução e provavelmente veremos o container sendo desligado quase instantaneamente.&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="s"&gt; nginx:latest&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; nginx -g 'daemon off;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Mudança no dockerfile acima foi sutil, mas faz toda a diferença, com a sintaxe corrida do &lt;code&gt;ENTRYPOINT&lt;/code&gt; o comando em questão é executato pelo shell dentro do container, segue o output do &lt;code&gt;pstree&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1i-Qiwoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7d1x9fa3ekg7ei2x0oll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1i-Qiwoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7d1x9fa3ekg7ei2x0oll.png" alt="output do comando pstree em um container mal configurado" width="756" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora o processo mais a esquerda é o &lt;code&gt;sh&lt;/code&gt;, ele quem receberá os sinais de desligamento e por acaso não sabe muito bem o que fazer com esses sinais, se você executar um &lt;code&gt;docker stop&lt;/code&gt; nesse container verá que demora 10 segundos para parar, dessa forma não faremos o "Graceful Shutdown" e nunca teremos um verdadeiro deploy "Zero Down Time" porque sempre que o container com a versão antiga do código morrer, vai levar os requests que estão em execução para a vala junto. Logo devemos nos assegurar que nosso processo está recebendo o sinal de desligamento corretamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vários processos no mesmo container
&lt;/h2&gt;

&lt;p&gt;É conceitualmente correto que o container contenha apenas um processo(PID 1), mas é relativamente comum aparecer a necessidade de executar mais de um processo no mesmo container. Tomando como exemplo uma aplicação &lt;a href="https://www.php.net/"&gt;PHP&lt;/a&gt;, que não é capaz de responder como uma aplicação completa(HTTP) apenas com o processo do &lt;a href="https://www.php.net/manual/pt_BR/install.fpm.php"&gt;PHP-FPM&lt;/a&gt;, pois necessita de um &lt;a href="https://www.nginx.com/resources/glossary/reverse-proxy-server/"&gt;reverse proxy&lt;/a&gt; como &lt;a href="https://www.apache.org/"&gt;apache&lt;/a&gt; ou &lt;a href="https://www.nginx.com/"&gt;nginx&lt;/a&gt; para isso, como poderíamos fazer um único container  contendo tanto nginx como php-fmp e que funcione como uma aplicação completa capaz de entender o protocolo HTTP? A própria &lt;a href="https://docs.docker.com/config/containers/multi-service_container/"&gt;documentação do docker nos traz algumas recomendações&lt;/a&gt; sendo que dentre elas a melhor seria utilizar o &lt;a href="http://supervisord.org/"&gt;supervisord&lt;/a&gt; como processo principal no container, cuidando dos outros processos. O supervisord é capaz de propagar os sinais de desligamento que recebe para os processos filhos, sendo assim tanto o nginx quanto o PHP-FPM terão a possibilidade de fazer um "Graceful Shutdown" assim que o supervisord receber o sinal SIGTERM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prioridade dos processos dentro do container
&lt;/h2&gt;

&lt;p&gt;Bom temos uma aplicação PHP sendo executada em produção e seguimos tudo que foi falado até agora, estamos executando tanto o php-fpm quanto o nginx, ambos rodando sobre o supervisord, porém por incrível que pareça estamos notando o erro &lt;code&gt;502&lt;/code&gt; durante o deploy. Isso acontece porque durante o deploy um novo container é criado e o supervisord simplesmente não sabe qual processo deve iniciar primeiro, se por acaso o nginx estiver pronto para receber um request, mas o php-fpm ainda não foi corretamente iniciado então temos um &lt;code&gt;502&lt;/code&gt;. Resolver esse problema de prioridade entre os processos é relativamente simples, o supervisord tem uma flag priority que tem o proposito de dizer quem é o processo de maior prioridade, entre outras palavras esse processo deve ser criado primeiro e morrer por último, a seguir segue uma configuração real de uma aplicação da &lt;a href="https://convenia.com.br"&gt;Convenia&lt;/a&gt; em produção:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[supervisord]
nodaemon=true

[program:nginx]
command = nginx -c /etc/nginx/nginx.conf  -g 'daemon off;'
user = app
autostart = true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true

[program:php-fpm]
command = /usr/sbin/php-fpm7 -F
priority = 1
user = app
autostart = true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse é um arquivo de configuração do supervisord, perceba a configuração do php-fpm &lt;code&gt;priority = 1&lt;/code&gt;, essa configuração vai instruir o supervisord a criar o php-fpm primeiro e a desligar ele por último, agora sim temos um deploy perfeito, sem downtime.&lt;/p&gt;

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

&lt;p&gt;Para alcançar um deploy perfeito não adianta simplesmente utilizar os orquestradores mais poderosos do mercado, precisamos tomar alguns cuidados com o nosso container e aplicação também:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Garantir que a aplicação é capaz de fazer um Graceful Shutdown&lt;/li&gt;
&lt;li&gt;Garantir que a aplicação está recebendo os sinais de desligamento corretamente, ou mantendo a aplicação como sendo o primeiro processo dentro do container, ou utilizando alguma ferramenta como o supervisord que propaga os sinais que ela recebe.&lt;/li&gt;
&lt;li&gt;Garantir que os processos estão sendo iniciados e desligados na ordem correta, caso o container rode mais de um processo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tomado esses cuidados estamos prontos para ter um deploy sem Downtime.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>deploy</category>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Batemos a meta do NPS! Como foi?</title>
      <dc:creator>Anderson Poli</dc:creator>
      <pubDate>Thu, 16 Sep 2021 18:34:01 +0000</pubDate>
      <link>https://dev.to/convenia/batemos-a-meta-do-nps-e-agora-4cnk</link>
      <guid>https://dev.to/convenia/batemos-a-meta-do-nps-e-agora-4cnk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Antes de mais nada o que é NPS?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O Net Promoter Score (NPS) é uma métrica de lealdade do cliente criada por Fred Heichheld, com o objetivo de medir o grau de lealdade dos clientes das empresas de qualquer segmento, trazendo reflexos da experiência e satisfação dos clientes.&lt;/p&gt;

&lt;p&gt;Resumidamente é uma pesquisa feita com os clientes perguntando de 0 a 10 qual seria a probabilidade deles recomendarem o seu produto para outras pessoas.&lt;/p&gt;

&lt;p&gt;As notas são divididas da seguinte maneira.&lt;/p&gt;

&lt;p&gt;0 - 6: Detratores&lt;br&gt;
7 - 8: Neutros&lt;br&gt;
9 - 10: Promotores&lt;/p&gt;

&lt;p&gt;Imaginem um grupo de amigos em uma mesa de bar, quando o assunto do momento é relacionado a algum produto que resolva determinado problema, e o seu produto é levantado como opção.&lt;/p&gt;

&lt;p&gt;Detratores são aqueles que não irão recomendar por N motivos, ou por um pequeno motivo mas que para ele é importante.&lt;/p&gt;

&lt;p&gt;Neutros ficarão em cima do muro.&lt;/p&gt;

&lt;p&gt;Promotores recomendarão fortemente o produto, dando exemplos de problemas solucionados.&lt;/p&gt;

&lt;p&gt;Acho NPS uma forma de medir muito ingrata, a conta para saber se você está em uma zona de excelência não é ter mais promotores do que detratores somente. Um detrator pesa bem mais que um promotor.&lt;/p&gt;

&lt;p&gt;Por exemplo: em uma pesquisa com 50 pessoas respostas, 25 deram notas 9 e 10 (promotores), 20 deram notas 7 ou 8 (neutros) e 5 deram notas de 0 a 6 (detratores). O cálculo de NPS deve ser: 25 (promotores) – 5 (detratores) ÷ 50 (número total de pessoas que responderam) = 40%&lt;/p&gt;

&lt;p&gt;Seu produto só começa a entrar na zona de excelência após ultrapassar a barreira de 50.&lt;/p&gt;

&lt;p&gt;E aqui começa o nosso post =)&lt;/p&gt;

&lt;p&gt;Aqui na Convenia, alinhamos como meta do time de produto atingir o NPS acima da zona de excelência. E sabíamos que não seria tarefa fácil, por ser um SAAS, com diversos tipos de clientes, setores etc..&lt;/p&gt;

&lt;p&gt;Pelo título do post, já temos um spoiler que conseguimos alcançar nosso objetivo durante o ano, mas o que quero passar aqui é, quais foram as principais ações para que isso se tornasse realidade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 - Alinhamento com time de vendas&lt;/strong&gt;&lt;br&gt;
Sabemos que um vendedor quer vender a qualquer custo, não está errado, mas uma mudança clara foi saber vender a qualquer custo sabendo das limitações e das qualidades do produto. Normal em um time em crescimento ter desalinhamento em relação ao que o produto é capaz de fazer. Por conta disso foi importantíssimo reuniões de alinhamento com o time de vendas e produto constantes, para sanar dúvidas ou sugerir evoluções.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2 - Alinhamento com o time de CS&lt;/strong&gt;&lt;br&gt;
CS tem papel fundamental de fazer com que o cliente chegue no sucesso esperado utilizando o sistema. E como fazer isso? &lt;br&gt;
Pensando fora da caixa, e porque não sugerir melhorias no produto, seja no processo de implantação para reduzir tempo gasto em alguma tarefa entregando valor mais rápido, ajudando a realizar pesquisas com clientes para entender quais são as principais dúvidas e demandas. Afinal CS é quem mais passa o tempo se relacionando com os clientes. Ter um time de CS integrado com o time de produto foi essencial, onde cada um entendeu a limitação de cada área.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3 - Produto atacando o que realmente importa&lt;/strong&gt;&lt;br&gt;
Aqui na Convenia temos um processo bem definido de priorização, escrevi sobre o tema a um tempo atrás: &lt;a href="https://dev.to/convenia/o-que-atacar-em-produto-user-impact-score-pode-te-ajudar-a-comecar-5a8j"&gt;https://dev.to/convenia/o-que-atacar-em-produto-user-impact-score-pode-te-ajudar-a-comecar-5a8j&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tendo um processo alinhado com a estratégia da empresa, o que precisa ser feito é executar!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No momento que adiciono como tag do post a palavra alinhamento&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Por que esse foi o principal motivo da chegada a meta.&lt;/p&gt;

&lt;p&gt;Time de design pensando na melhor usabilidade, como resolver um problema da maneira mais fácil e ágil possível. &lt;/p&gt;

&lt;p&gt;Time de engenharia focado em entregar valor rápido, não menosprezando qualidade e segurança.&lt;/p&gt;

&lt;p&gt;Mais e ai, qual foi o NPS alcançado?&lt;br&gt;
Durante todo o ano batíamos na trave, 45, 48, 43, até 49, lembra quando falei que NPS era ingrato, teve um mês que no último dia o sonho foi postergado, o time sofreu! E isso é muito legal, fomos mais fortes para a próxima rodada, até que alcançamos o 62.2. BOOOM!&lt;/p&gt;

&lt;p&gt;Foi hora de comemorar, e entender que o trabalho apenas começou, pois chegar é difícil, se manter é muito mais. Sabemos que no próximo mês o resultado pode não ser tão bom, mas confiar no processo é essencial para isso se tornar um padrão.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>startup</category>
      <category>nps</category>
      <category>alinhamento</category>
    </item>
    <item>
      <title>O Desenvolvimento do Desenvolvedor no Século 21</title>
      <dc:creator>StefanoDucciConvenia</dc:creator>
      <pubDate>Thu, 08 Jul 2021 20:09:11 +0000</pubDate>
      <link>https://dev.to/convenia/o-desenvolvimento-do-desenvolvedor-no-seculo-21-150j</link>
      <guid>https://dev.to/convenia/o-desenvolvimento-do-desenvolvedor-no-seculo-21-150j</guid>
      <description>&lt;p&gt;Olá, meu nome é Stefano e sou Líder em treinamento do time de SRE aqui na Convenia. Venho aqui hoje contar para vocês como está sendo o desafio de treinar novos Desenvolvedores nesse mundo cada vez mais complexo e avançado da programação e também sobre um case de sucesso de uma Desenvolvedora que se mostrou excepcional nesses seis meses que faz parte do meu time.&lt;/p&gt;

&lt;p&gt;Antes de começar a falar sobre como está sendo hoje, convido vocês a uma viagem no tempo comigo, não muito longe, só três anos atrás quando entrei aqui na Convenia como um Desenvolvedor Backend Júnior, naquela época a Empresa estava terminando de passar por uma migração de tecnologia, indo de um modelo MVC usando Codeigniter e indo para um Monolito em Laravel. Ou seja, para conseguir desenvolver eu só precisava saber PHP e MYSQL, e no máximo, um pouco de HTML para ajustar alguma coisa no que se mostra ser sempre um pesadelo na vida de qualquer desenvolvedor novo em uma instituição, o famigerado “Sistema Legado”.&lt;/p&gt;

&lt;p&gt;Nesses últimos anos, a Convenia passou por diversas mudanças e modernizações, agora, um Desenvolvedor Junior cai direto em um sistema distribuído com micro serviços, bancos não relacionais, SPA’s, BFF, Graphql e mensageria. Com tudo isso, fica fácil de ver como a curva de aprendizado de alguém novo vem se tornando cada vez mais íngreme ao longo do tempo.&lt;/p&gt;

&lt;p&gt;Esse cenário atual nos leva à seguinte questão: o que podemos fazer para que essa curva de aprendizado seja suavizada o máximo possível para que todos consigam escalar até o topo? Para conseguir chegar a uma resposta para isso, trabalhei em uma metodologia de treinamento e acompanhamento junto a essa Desenvolvedora que iniciou no meu time, e para chegar nesse resultado, nada melhor do que trazer todos os exemplos que tive das minhas lideranças ao longo desses anos.&lt;/p&gt;

&lt;p&gt;É um fato de que ao longo do seu desenvolvimento existem marcos e divisores de água que te mostram uma nova realidade na qual você se sente cada vez mais motivado a continuar evoluindo, comigo por exemplo, o primeiro contato que tive com esse sentimento foi quando eu já estava a quase três horas tentando corrigir um código de produção, mas ele estava complexo demais, foi quando meu primeiro líder aqui na Convenia chegou do meu lado e me perguntou: “Você sabe o que esse código deveria fazer?”, eu respondi: “Sim, deveria fazer isso, isso e isso”, o que fez ele simplesmente selecionar todo aquele código, apagar e dizer: “Então escreve o que ele deveria fazer ao invés de tentar entender o que ele fazia antes, já que estava errado”.&lt;br&gt;
Esse pode até parecer um caso sem importância à primeira vista, mas isso para um cara inseguro como eu era, começando a programar e se imaginando incapaz de dar conta do que estava enfrentando, aquilo mudou meu mundo. Nos próximos 20 minutos aquele código já estava sendo usado pelo cliente impactado por aquele bug, foi quando percebi que “de repente” eu realmente comecei a entender o que estava fazendo.&lt;/p&gt;

&lt;p&gt;O segundo ponto, e talvez o mais importante, anda muito próximo a esse: a confiança, essa palavra expande os horizontes de  qualquer desenvolvedor júnior, então precisamos trabalhar tanto a confiança que ele deve ter no seu próprio código e no produto em que ele trabalha, bem como a confiança que passamos pra ele como líder. Se tem uma coisa que aprendi com isso, foi que codar é muito fácil, mas só se você sabe o que é esperado daquele código, uma vez que você entende a regra de negócio, coda-la é um mero detalhe, e esse ensinamento eu devo totalmente ao CTO da Convenia, o cara que discute e estressa a regra de negócio junto com você, sempre ouvindo seus pontos para trazer o máximo desse conforto tão importante na hora de desenvolver.&lt;/p&gt;

&lt;p&gt;Foram essas lições que me ajudaram a pavimentar o caminho que essa Desenvolvedora iria trilhar ao meu lado, incluindo essa última que aprendi com meu líder atual, nenhum time deve seguir uma liderança, todos devem caminhar juntos para o objetivo em comum que pode ser uma entrega importante, a resolução de um problema grave ou até mesmo no aprendizado do dia a dia.&lt;/p&gt;

&lt;p&gt;Agora sem mais delongas, vamos ao passo a passo que desenvolvi, começando pelo passo mais importante: ‘Acompanhamento diário do aprendizado’, que consiste em diariamente tirar entre cinco e dez minutos para ouvir tudo o que o desenvolvedor aprendeu nas últimas vinte e quatro horas, estendendo para até vinte minutos no fim da semana para repassarem um resumão de quais foram os maiores desafios, aprendizados  e dúvidas que surgiram nesse período. Isso vai te ajudar a entender a melhor forma de se comunicar com essa pessoa, a quantidade de detalhes que você deverá dar na próxima vez que passar uma tarefa ou dar uma explicação, além de te aproximar muito do seu liderado e permitir que você meça diariamente seu nível. Mas o mais importante nesse passo é garantir a concretização do conhecimento, garantindo que nenhuma dúvida ficou em aberto e nenhuma lição passou em branco.&lt;/p&gt;

&lt;p&gt;O segundo passo: ‘Uma hora de estudos por dia’, foi algo que roubei de um ex-funcionário e líder do time considerado de maior desempenho, o  BPO, que nem é de desenvolvimento, mas acredito que bons exemplos podem muito bem ser buscados de fora de nossas bolhas também. Nessa uma hora, o ideal é que os estudos sejam focados nas tecnologias da empresa, aqui no nosso caso, disponibilizamos uma lista de cursos sobre protocolo AMQP, MongoDB, PHP e Laravel para que na hora de desenvolver, eles tenham um estranhamento menor ao trabalhar nessas tecnologias.&lt;/p&gt;

&lt;p&gt;Como aqui estamos falando do exemplo de um time que também faz a sustentação do produto, o terceiro passo: ‘Integrar às resoluções de bugs’, e o quarto passo: ‘Tratativa de bugs já resolvidos em ambiente local desatualizado’, se fizeram bem necessários, e em suma, se resumem a trazer essa nova pessoa junto à tratativa de um problema, mostrando sua forma de pensar, explicando o background que você tem sobre essa parte do sistema antes de começar a investigar e explicar por onde você começa e porque. Já o quarto passo existe por que com a correria do dia a dia, as vezes você acaba resolvendo um problema em produção durante uma outra reunião ou durante o tempo de estudo do seu liderado, e esses são os casos perfeitos para você deixar ele explorar o problema dentro do seu ambiente local, sem se preocupar com a pressão envolvida em querer resolver um problema o mais rápido possível, já que sempre existe um ou mais clientes impactados em um problema, e nesse setor, trabalhar o psicológico é tão importante quanto trabalhar a confiança.&lt;/p&gt;

&lt;p&gt;O que nos leva diretamente ao passo cinco: ‘Entrega de pequenas features’, muitas vezes vocês verão desenvolvedores com medo de começar a codar, aquele receio de querer sempre fazer tudo da melhor forma desde o começo, mesmo a gente sabendo que é impossível. Dar entregas pequenas para um junior ajuda a melhorar a sua confiança, além de ajudá-lo a organizar melhor suas ideias, entender seu próprio processo criativo, limitações e medos.&lt;/p&gt;

&lt;p&gt;O sexto e último passo: ‘Passar a autoria de um serviço’ -  trata do sentimento de dono que todo desenvolvedor tem pelo seu código -  nesse caso, como a Convenia trabalha nesse modelo distribuído, eu ajudei minha Desenvolvedora desde o começo na criação de um serviço que viria a ser  mantido, melhorado e cuidado por ela. Esse sentimento é transformador, durante o  desenvolvimento desse serviço ela veio mostrando sinais claros de amadurecimento, evolução e senioridade que não é comum em um profissional no começo da sua carreira.&lt;/p&gt;

&lt;p&gt;Agora, uma constante entre esses passos é o passo oculto: ‘Introduzir o máximo de regras de negócio possível’. Como falei anteriormente, às vezes ensinar a regra de negócio é mais importante do que ensinar a forma de se fazer uma tarefa, então sempre que possível aproveite para ensinar, ensine durante uma call com um cliente, ensine durante a reunião diária com o time, ensine durante o code review, ensine durante um deploy, ensine durante a explicação da tarefa, ensine durante a resolução de um problema e quando você perceber, será você que estará aprendendo com seus liderados.&lt;/p&gt;

&lt;p&gt;Não existem fórmulas mágicas quando falamos de pessoas, cada um terá seu próprio tempo de desenvolvimento, sua própria maneira de absorver as coisas, uma hora no dia que consegue aprender melhor e aquela que já não consegue tanto, vai de cada líder saber enxergar isso em cada liderado e ter  tato para tratar cada um de acordo com suas peculiaridades. Essa foi a fórmula que encontrei para ajudar essa Desenvolvedora em particular, mas é com muito orgulho que digo que os resultados foram incríveis, em apenas seis meses, uma desenvolvedora júnior que chegou com três meses de experiência já é considerada de nível pleno por profissionais com mais tempo de carreira no PHP do que ela tem de vida.&lt;/p&gt;

&lt;p&gt;Vou concluir esse artigo deixando a seguinte lição: trabalhe a confiança de seus liderados, dê a eles um motivo para melhorar todos os dias, os desafie e mostre como eles são capazes de evoluir, ensine, nunca perca essa oportunidade e sempre mostre para eles como essas lições fizeram diferença ao longo de um code review ou de um feedback. E nunca se esqueça do mais importante: eles são pessoas como você, irão cometer erros, mas esses erros jamais deverão ser passivos de punição ou vergonha e sim ser a melhor oportunidade de evoluir, aprender e repetir tudo de novo, afinal, esse é o ciclo de desenvolvimento de um desenvolvedor.&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>Arquitetura Event Driven, quando da errado</title>
      <dc:creator>Leonardo Lemos</dc:creator>
      <pubDate>Mon, 21 Jun 2021 14:15:40 +0000</pubDate>
      <link>https://dev.to/convenia/arquitetura-event-driven-quando-da-errado-1bjf</link>
      <guid>https://dev.to/convenia/arquitetura-event-driven-quando-da-errado-1bjf</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;No &lt;a href="https://dev.to/convenia/event-driven-com-laravel-pigeon-2753"&gt;post anterior&lt;/a&gt; expliquei um pouco como funciona uma arquitetura orientada a eventos e como implementamos essa arquitetura na &lt;a href="https://convenia.com.br/" rel="noopener noreferrer"&gt;Convenia&lt;/a&gt;. Comentei um pouco sobre o nosso tratamento de erros e hoje pretendo me aprofundar mais nesse assunto.&lt;/p&gt;

&lt;p&gt;Assim como no post anterior gostaria de enfatizar que as escolhas de arquitetura e stack fazem sentido para o nosso tamanho e previsão de crescimento. Possivelmente para você não faça sentido fazer tudo da mesma forma como fazemos uma vez que cada projeto é único com as suas particularidades, mesmo assim é provável que você consiga tirar algo de bom desse post.&lt;/p&gt;

&lt;p&gt;Nesse post as palavras "mensagem" e "evento" representam a mesma coisa mas em contextos diferentes, a grosso modo "mensagem" é o nome dado a informação em transito através de um &lt;a href="https://en.wikipedia.org/wiki/Message_broker" rel="noopener noreferrer"&gt;message broker&lt;/a&gt; e evento é o nome dado para a mensagem em um contexto "orientado a eventos", "listener" é o nome dado ao processo responsável por "ouvir" eventos. &lt;/p&gt;

&lt;h2&gt;
  
  
  Como os serviços se comunicam?
&lt;/h2&gt;

&lt;p&gt;A seguir vamos analisar um exemplo simples utilizando o &lt;a href="https://convenia.github.io/Pigeon/#/" rel="noopener noreferrer"&gt;Pigeon&lt;/a&gt; bem parecido com o do post anterior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Pigeon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'employee.created'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Scooby Doo'&lt;/span&gt; 
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo acima estamos emitindo o evento &lt;code&gt;employee.created&lt;/code&gt; que tem como body o nome do colaborador, para ouvir esse evento em outro serviço com o Pigeon temos esse código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Pigeon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'employee.created'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;ResolverContract&lt;/span&gt; &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//doing nice things&lt;/span&gt;

            &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ack&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="nf"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//send to sentry&lt;/span&gt;

            &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reject&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código acima faz algumas coisas&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configura o Pigeon para ouvir o evento &lt;code&gt;employee.created&lt;/code&gt; em outro serviço, com a chamada &lt;code&gt;Pigeon::events('employee.created')&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Define um callback para "lidar" com o evento passando uma &lt;a href="https://www.php.net/manual/en/class.closure.php" rel="noopener noreferrer"&gt;Closure&lt;/a&gt; através do método &lt;code&gt;-&amp;gt;callback()&lt;/code&gt;, essa Closure será executada cada vez que o evento &lt;code&gt;employee.created&lt;/code&gt; for "ouvido".&lt;/li&gt;
&lt;li&gt;Define um fallback através do método &lt;code&gt;-&amp;gt;fallback()&lt;/code&gt;, essa closure será executada sempre que acontecer uma exception dentro do callback.&lt;/li&gt;
&lt;li&gt;O método &lt;code&gt;-&amp;gt;consume()&lt;/code&gt; começa a consumir a fila de fato.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O Pigeon utiliza &lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt; para intermediar a comunicação entre os dois serviços, se tentarmos mostrar isso em um diagrama teremos o seguinte:&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%2Fenp81dxveq6e8ryrhogi.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%2Fenp81dxveq6e8ryrhogi.png" alt="diagrama de evento comsumido com sucesso"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No momento em que o serviço lê a mensagem do RabbitMQ a mensagem fica em um estado "unacked", isso significa que o Rabbit está esperando a confirmação dessa mensagem por parte de quem a leu. O RabbitMQ não entregará essa mensagem a mais ninguem até receber a confirmação de que algo deu certo ou a confirmação de que algo deu errado(rejeição) com a mensagem. No passo 4 retratado no diagrama acima fazemos uma confirmação na mensagem para o RabbitMQ saber que ela foi processada corretamente, apenas depois de receber essa confirmação o RabbitMQ remove a mensagem da fila.&lt;/p&gt;

&lt;p&gt;O diagrama acima mostra um caminho muito feliz mas vamos imaginar que logo após ler a mensagem, o serviço ouvinte "morre" devido a algum problema de hardware antes de confirmar a mensagem:&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%2Fvy0kfc9l5s1o45agjdnu.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%2Fvy0kfc9l5s1o45agjdnu.png" alt="diagrama mostrando erro fatal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;De forma similar ao exemplo anterior, após a leitura da mensagem o Rabbit coloca a mensagem no estado "unacked", ao processar a mensagem um erro muito inesperado acontece e o Listener(processo) morre no passo 3, nesse momento o Rabbit sabe que deve voltar a mensagem para o estado de "ready", assim outro listener pode tentar processar essa mesma mensagem, isso é possível porque os listeners mantém uma conexão aberta com o Rabbit e quando o processo do listener morre a conexão com o Rabbit é "cortada", nesse momento ele sabe que deve "liberar" todas as mensagens que aquele listener leu mas não confirmou.&lt;/p&gt;

&lt;p&gt;Até o momento mostramos fluxos saudáveis e falhas de terceiros que podem acontecer esporadicamente mas e quando nosso próprio código que consome a mensagem está quebrado? E quando a própria mensagem está quebrada?&lt;/p&gt;

&lt;h2&gt;
  
  
  Dead Letter Exchange para o Resgate
&lt;/h2&gt;

&lt;p&gt;Vamos tentar imaginar a seguinte situação onde o código do nosso próprio listener está quebrado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Pigeon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'employee.created'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;ResolverContract&lt;/span&gt; &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doesNotExists&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;ack&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="nf"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código acima repare a chamada para a função &lt;code&gt;doesNotExists()&lt;/code&gt;, como o próprio nome já diz essa função não existe e quando esse listener tentar consumir uma mensagem ele vai entrar no fluxo retratado na imagem 2. O grande problema é que normalmente utilizamos algum recurso  como o &lt;a href="http://supervisord.org/" rel="noopener noreferrer"&gt;supervisord&lt;/a&gt; para "reviver" os processos que morrem e quando esse listener "voltar a vida" ele vai entrar no fluxo da imagem 2 novamente entrando em um looping.&lt;/p&gt;

&lt;p&gt;Temos uma mensagem sendo consumida em looping, ela será consumida corretamente apenas se o código do listener for corrigido, isso causa vários problemas como mostrado no &lt;a href="https://dev.to/convenia/event-driven-com-laravel-pigeon-2753"&gt;post anterior&lt;/a&gt;. O RabbitMQ, não por acaso, tem um recurso chamado &lt;a href="https://www.rabbitmq.com/dlx.html" rel="noopener noreferrer"&gt;dead letter exchange&lt;/a&gt; que serve para esse tipo de situação e com esse recurso a mensagem pode ser enviada em uma exchange separada para ser tratada posteriormente, como mostra o fluxo a seguir:&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%2Fvvyzooaniyh4rmofcane.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%2Fvvyzooaniyh4rmofcane.png" alt="diagrama mostrando fluxo de um erro previsível"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para esse fluxo acontecer precisamos "rejeitar" explicitamente a mensagem através do método &lt;code&gt;fallback&lt;/code&gt; mostrado no inicio do artigo e retratado novamente a seguir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//send to sentry&lt;/span&gt;

    &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reject&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código acima a chamada &lt;code&gt;$resolver-&amp;gt;reject(false);&lt;/code&gt; é a chamada que rejeita explicitamente a mensagem, caso você não defina um fallback, o Pigeon tem um fallback padrão que rejeitará a mensagem caso a env &lt;code&gt;PIGEON_ON_FAILURE&lt;/code&gt; esteja presente com o valor &lt;code&gt;reject&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  LetterThief
&lt;/h2&gt;

&lt;p&gt;Após rejeitar a mensagem, ela irá para uma dead letter exchange de onde podemos armazenar essa mensagem problemática em uma fila, avaliar mais tarde ou dar um tratamento digno para ela ali mesmo. No caso da &lt;a href="//convenia.com.br"&gt;Convenia&lt;/a&gt; desenvolvemos um serviço chamado "LetterThief" que é responsável por gerenciar as mensagens que foram rejeitadas e avisar o time quando ocorre uma rejeição:&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%2Fn9mroe7jjke7gvdr2yh9.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%2Fn9mroe7jjke7gvdr2yh9.png" alt="listagem de mensagens rejeitadas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Acima está retratada a listagem das mensagens rejeitadas, nesse serviço conseguimos filtrar as mensagens pela suas propriedades, Toda rejeição ocorre em uma fila e exchange específicas e em um certo momento. Os filtros são capazes de trazer rejeições que ocorreram em uma determinada fila ou em um determinado momento.&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%2F8fajcrbdbyot6ahqf7k3.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%2F8fajcrbdbyot6ahqf7k3.png" alt="página de detalhes da mensagem rejeitada"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ná página de detalhes da mensagem rejeitada temos todas as informações da mensagem, sabemos de que serviço ela veio, sabemos qual foi o listener que a rejeitou e o mais importante, temos o &lt;code&gt;correlation_id&lt;/code&gt; que será utilizado para confrontar o erro com as exceptions que cairem no &lt;a href="https://sentry.io" rel="noopener noreferrer"&gt;sentry&lt;/a&gt;. Com essas informações sabemos exatamente o porque uma mensagem foi rejeitada e o envio para o sentry é feito pelo listener logo antes de rejeitar a mensagem:&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%2Fr1lkiqj224y43bx97o0d.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%2Fr1lkiqj224y43bx97o0d.png" alt="mensagem de erro no sentry"&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%2Fpul5vsye1pc5swp0t3yj.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%2Fpul5vsye1pc5swp0t3yj.png" alt="Tags no sentry"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As imagens acima mostram um erro real que ocorreu no ambiente de produção e a parte de tags contendo o &lt;code&gt;correlation_id&lt;/code&gt;, infelizmente não posso mostrar a exception com mais detalhes para não expor dados sensíveis :/&lt;/p&gt;

&lt;p&gt;Legal, o serviço traz bastante visibilidade para os erros que ocorreram mas como os desenvolvedores são avisados sobre o ocorrido? O LetterThief tem uma integração com o slack assim toda a equipe é notificada quando um erro ocorre e pode agir imediatamente para resolver o problema.&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%2F763qcx7uuf9kd7hkr64r.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%2F763qcx7uuf9kd7hkr64r.png" alt="notificação no slack enviada pelo letter thief"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima vemos a notificação que chega no slack, ela contém a fila onde ocorreu o problema e o link para a mensagem no serviço do LetterThief, dessa forma o desenvolvedor responsável já sabe que deve corrigir o problema o quanto antes.&lt;/p&gt;

&lt;p&gt;Você deve estar se perguntando o que acontece com a mensagem após a correção do problema já que muito provavelmente ela deveria causar algum efeito no sistema mas acabou não causando devido ao erro ocorrido, após resolver o erro o desenvolvedor tem a capacidade de reenviar a mensagem através do LetterThief.&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%2F77ir3me8wi8jztgg1e8o.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%2F77ir3me8wi8jztgg1e8o.png" alt="modal de confirmação para reenviar a mensagem"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem acima é possível ver o botão "TRY MESSAGE AGAIN" que resulta nessa confirmação que está sendo exibida, após a confirmação, a mensagem será reenviada diretamente para a fila de onde o erro foi causado, dessa forma o processamento deve ocorrer normalmente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuidados adicionais
&lt;/h2&gt;

&lt;p&gt;Você deve estar se deparando com algumas questões após ter chego até aqui, a verdade é que para tudo isso funcionar corretamente temos que ter alguns cuidados que são garantidos em um fluxo rígido de &lt;a href="https://www.youtube.com/watch?v=_7W9pqWPyfc" rel="noopener noreferrer"&gt;code review&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Os listeners devem ser &lt;a href="https://developer.mozilla.org/pt-BR/docs/Glossary/Idempotent" rel="noopener noreferrer"&gt;idempotentes&lt;/a&gt;, como pode ocorrer um erro durante o processamento, no caso de uma criação no banco de dados por exemplo, não podem haver registros duplicados, devemos fazer a opção por uma função de &lt;code&gt;upsert&lt;/code&gt; ao invés de um &lt;code&gt;create&lt;/code&gt;, isso vai evitar que dois registros sejam criados quando a mensagem for reenviada, lembrando que a mensagem pode ser reenviada mais de uma vez.&lt;/li&gt;
&lt;li&gt;O listener deve obrigatoriamente enviar a mensagem para o sentry e logo em seguida rejeitar a mensagem no fallback, muita lógica não é bem vinda aqui pois não podem haver falhas dentro do fallback, isso causaria a devolução da mansagem para a fila e o problema de reprocessamento infinito apresentado no inicio do post.&lt;/li&gt;
&lt;li&gt;Devemos ser cuidadosos ao avaliar datas dentro do listener, não devemos nunca avaliar o momento em que a mensagem chega no listener, sempre devemos avaliar a data em que o evento foi emitido, isso chega obrigatoriamente com todo o evento, dessa forma evitamos de processar uma data errada devido ao delay da mensagem.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Toda arquitetura distribuída tem uma complexidade mais elevada, observabilidade e tratamento de erros são pautas de muitas talks e donos da preocupação de várias equipes. Sem dúvidas em uma arquitetura orientada a eventos precisamos de uma forma de lidar com erros no processamento de mensagens assíncronas. No caso específico da Convenia a melhor saída foi fazer nosso próprio serviço que atende exatamente ao que precisamos. Existem outras opções de message broker como &lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;kafka&lt;/a&gt; que podem trazer soluções já prontas para esse problema, o que te economizará o trabalho de desenvolver e manter a solução, de qualquer forma é muito importante ter uma solução similar a essa para auxiliar a equipe no dia a dia.&lt;/p&gt;

&lt;p&gt;O LetterThief foi desenvolvido com a premissa da segurança em relação a perda de mensagens, se reparar cuidadosamente vai ver que utilizando o LetterThief é impossível perder uma mensagem no meio do caminho, ou ela foi processada corretamente ou foi parar no LetterThief, caso o desenvolvedor do listener tenha sido muito transgressor ao implementar o listener, a mensagem voltará para a fila, independente da opção que adotarmos acho essa premissa de "nunca perder a mensagem" importante para se levar em consideração.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>microservices</category>
      <category>pigeon</category>
    </item>
    <item>
      <title>O dia-a-dia da engenharia na Convenia</title>
      <dc:creator>Anderson Casimiro</dc:creator>
      <pubDate>Fri, 30 Apr 2021 17:32:41 +0000</pubDate>
      <link>https://dev.to/convenia/o-dia-a-dia-da-engenharia-na-convenia-57g4</link>
      <guid>https://dev.to/convenia/o-dia-a-dia-da-engenharia-na-convenia-57g4</guid>
      <description>&lt;p&gt;Salve pessoal! Toda área de desenvolvimento tem suas particularidades. Aqui na Convenia não é diferente. A seguir vou comentar algumas coisas do nosso dia a dia. Como e com o quê trabalhamos, quais processos utilizamos, entre outras coisas. &lt;/p&gt;




&lt;h2&gt;
  
  
  Tecnologia
&lt;/h2&gt;

&lt;p&gt;Direto ao ponto: O nosso produto é dividido em vários serviços, cada um responsável por um domínio de negócio. São diversos backends, cada um servindo sua API REST em PHP usando o framework &lt;a href="https://laravel.com"&gt;Laravel&lt;/a&gt;, usando MySQL para persistência.&lt;/p&gt;

&lt;p&gt;Nossas interfaces para os clientes são disponibilizadas como SPAs, desenvolvidas com &lt;a href="https://vuejs.org"&gt;Vue.JS&lt;/a&gt; e WebComponents confeccionados por nós. Usamos &lt;a href="https://rscss.io"&gt;RSCSS&lt;/a&gt; como metodologia de estilo. Estes SPAs comunicam-se via GraphQL com um &lt;a href="https://samnewman.io/patterns/architectural/bff/"&gt;Backend For Frontend&lt;/a&gt; em Node.JS, que comunica-se com o MongoDB para queries e com as APIs REST para as mutations. Sim, os dados são sincronizados entre os bancos das aplicações com este NoSQL, na direção de uma arquitetura baseada em &lt;a href="https://martinfowler.com/bliki/CQRS.html"&gt;CQRS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Como toda empresa que já colocou algum projeto de software no mercado, temos uma aplicação legada. Estamos trabalhando para a desativarmos ainda este ano, seguindo uma evolução sustentável nesse processo de refatoração.&lt;/p&gt;

&lt;p&gt;Estruturalmente organizamos tudo isso com Docker e Docker-Compose, desde o desenvolvimento local, passando por nossos pipelines Jenkins em todos os ambientes até produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agilidade
&lt;/h2&gt;

&lt;p&gt;Metodologias ágeis têm como objetivos priorizar as interações, ter mais coisas prontas antes e responder rápido a mudanças. Aqui na Convenia não é diferente e usamos a mentalidade ágil para organizar nossos processos.&lt;/p&gt;

&lt;p&gt;Nossos times realizam entregas em ciclos. No último ano adotamos o Scrum para a entrega de valor nos times de produto. Evoluímos o modelo ao longo do tempo e estamos entrando em um processo mais próximo ao &lt;a href="https://pt.wikipedia.org/wiki/Feature_Driven_Development"&gt;FDD&lt;/a&gt; (Feature Driven Development). &lt;/p&gt;

&lt;p&gt;Também usamos o Kanban para o time de &lt;a href="https://pt.wikipedia.org/wiki/Site_Reliability_Engineering"&gt;SRE&lt;/a&gt; (Site Reliability Engineering) seja nas demandas de correções ou mesmo no desenvolvimento de sistemas para nossa estrutura de experiência de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Também trouxemos do ágil a prática de Code Review, o Pair Programming, a reunião diária com todo o time (ainda mais útil em tempos de trabalho remoto) além da transparência com relação ao progresso do trabalho entre os times. Também estamos adotando o &lt;a href="https://12factor.net/pt_br/"&gt;12 factor apps&lt;/a&gt; em nossos sistemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qualidade
&lt;/h2&gt;

&lt;p&gt;Nós prezamos pela qualidade de nossas entregas. Seguimos a premissa de "Qualidade não é discutível". Estabelecemos nosso processo de maneira a não ser engessado para quem desenvolve e garantir que novas versões serão, no mínimo, tão boas quanto as anteriores.&lt;/p&gt;

&lt;p&gt;Nossos serviços de backend passam por vários passos de análise estática (Padrão de código, adequação a boas práticas, code smell e controle de vulnerabilidades) ao longo do ciclo de desenvolvimento. Nossa cobertura de testes está acima de 95% em todos os nossos serviços. Só a cobertura não garante muita coisa, por isso nosso time explora quantos cenários forem conhecidos para cada parte do nosso software e os atualiza conforme evoluímos.&lt;/p&gt;

&lt;p&gt;Do lado do frontend temos uma organização bem flexível para nossos layouts e componentes, desenvolvendo com regras do ESLint além de somente a formatação. Também adotamos a metodologia &lt;strong&gt;RSCSS&lt;/strong&gt; para padronização de estilos e temos uma validação forte quanto a fidelidade visual junto ao time de Design e Usabilidade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autonomia
&lt;/h2&gt;

&lt;p&gt;A Convenia tem como base de sua cultura a Autonomia, abordada sob diversos aspectos. É uma empresa que preza pela Transparência e Colaboração por toda a organização. O foco de nossas ações é o cliente e isso significa muito olhar para nós mesmos.&lt;/p&gt;

&lt;p&gt;Quando falamos de Autonomia Intelectual, respeitamos o conhecimento de todos, seja alguém que está começando na área ou com décadas de experiência. Todas as pessoas envolvidas têm voz ativa. Promovemos também que todos saibam escutar e compreender as ideias dos outros. Quanto mais conhecimento investido em algo, menores as chances de avançarmos por um caminho ruim.&lt;/p&gt;

&lt;p&gt;Valorizamos tanto a diversidade de conhecimento que a incorporamos ao nosso processo. Temos um canal aberto a todos na empresa para a sugestão de mudanças para o nosso produto. Falando da engenharia todos são encorajados a sugerir novas e melhores maneiras de trabalhar e desenvolver. E fazemos isso como a própria internet evolui: com um sistema de &lt;a href="https://pt.wikipedia.org/wiki/Request_for_Comments"&gt;RFC&lt;/a&gt; (Request for Comments)&lt;/p&gt;

&lt;h2&gt;
  
  
  Identidade
&lt;/h2&gt;

&lt;p&gt;Cada pessoa é muito importante no nosso time. E valorizamos as características individuais e trabalhamos na organização do time para que cada pessoa tenha a melhor experiência de codar e se desenvolver.&lt;/p&gt;

&lt;p&gt;Realizamos mensalmente reuniões 1:1 (um a um) com todos os membros do time. Essas cerimônias têm o objetivo de deixar cada pessoa a par sobre o que aconteceu (ou não) de um mês para o outro, além de cuidar da sua evolução profissional. &lt;/p&gt;

&lt;p&gt;Falando em evolução profissional: temos a premissa de dar as mesmas oportunidades e preparação a todos para que cresçam no nosso time. E as regras estão claras para todo mundo. E cada um sabe como está com relação a sua carreira por um sistema baseado em dados, com forte influência da nossa cultura e do que esperamos individualmente de cada um, muito além do código. Isso eu conto em outro artigo com mais detalhes ;).&lt;/p&gt;




&lt;p&gt;Somos a Engenharia da Convenia. Não somos uma empresa que está na bolsa, não somos o próximo unicórnio, não somos uma empresa que acredita que o lucro vem antes das relações humanas. Estamos aqui para fazer a melhor solução de RH, desenvolvida da melhor maneira, pelas melhores pessoas. &lt;/p&gt;

&lt;p&gt;Bora fazer parte?&lt;/p&gt;

</description>
      <category>culture</category>
      <category>php</category>
      <category>javascript</category>
      <category>remotework</category>
    </item>
  </channel>
</rss>
