Skip to main content

Filas de Promises e processamento em lotes de tarefas concorrentes no Deno

Escrito por
snyk code featured

25 de setembro de 2024

0 minutos de leitura

O que é Deno?

Deno é um ambiente de execução seguro para JavaScript e TypeScript, criado com o mesmo mecanismo JavaScript V8 do Node.js, mas com melhorias significativas. Foi desenvolvido por Ryan Dahl, criador original do Node.js, para resolver alguns dos principais problemas e limitações que ele identificou no Node.js ao longo do tempo. Deno foi projetado para reforçar a segurança, simplificar o gerenciamento de módulos e oferecer suporte a TypeScript desde o início.

js
import { serve } from "https://deno.land/std/http/server.ts";

serve((req) => new Response("Hello World\n"), { port: 8000 });
console.log("Server running on http://localhost:8000/");

Veja como o servidor responde às solicitações com a string "Hello World." A instrução import busca o método serve diretamente de uma URL, no módulo de servidor HTTP da biblioteca padrão do Deno. Esse é um dos aspectos únicos do Deno: ele busca e armazena em cache os módulos importados de URLs da web, eliminando a necessidade de um gerenciador de pacotes como o npm.

Como lidar com tarefas concorrentes no Deno

Lidar com tarefas concorrentes é essencial em qualquer framework ou runtime moderno para web, como o Deno. Em JavaScript, operações assíncronas são comuns, seja para buscar dados em um banco de dados, fazer solicitações HTTP ou ler arquivos do disco.

Como JavaScript é uma linguagem de thread única, ele depende de sua natureza orientada a eventos para gerenciar essas tarefas simultaneamente sem bloquear a thread principal.

js
let promises = [promise1, promise2, promise3];
let results = await Promise.all(promises);

O exemplo acima mostra como JavaScript lida com tarefas concorrentes usando Promise.all(). Ao executar várias promises simultaneamente, Promise.all() aguarda a conclusão de todas e, então, retorna os resultados. Isso é ótimo para otimizar o desempenho, mas tem desvantagens. Se uma promise falhar, todas as outras também serão rejeitadas, o que pode levar a um alto consumo de memória quando há muitas tarefas.

No Deno, podemos usar filas de Promises e processamento de tarefas em lotes para gerenciar a concorrência com mais eficiência. Assim, é possível lidar melhor com um grande número de tarefas sem sobrecarregar a memória nem correr o risco de uma falha total se uma única tarefa apresentar erro.

Vamos explicar como essas técnicas de filas e processamento de tarefas em lotes podem ajudar você a escrever código mais eficiente, robusto e com melhor desempenho.

Entenda as filas de Promises e as tarefas concorrentes


As filas de Promises são essenciais na programação assíncrona em JavaScript. Entender as filas de Promises e a concorrência pode aumentar significativamente a eficiência e o desempenho das suas aplicações. 

Uma abordagem sequencial para tarefas assíncronas

Uma fila de Promises é uma lista de objetos Promise aguardando para serem resolvidos ou rejeitados. Em JavaScript, uma "Promise" é um objeto que representa a conclusão ou falha futura de uma operação assíncrona.

Uma fila de Promises ajuda a gerenciar várias promises que precisam ser executadas em uma ordem específica. Ela garante que as promises sejam resolvidas sequencialmente, evitando possíveis problemas causados pela execução de código assíncrono. 

Veja um exemplo de uma fila simples de Promises em ação:

javascript
let promiseQueue = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];

Promise.all(promiseQueue)
  .then(values => {
    console.log(values); // logs [1, 2, 3]
  });

No exemplo acima, Promise.all recebe um iterável de promises e retorna uma nova promise que é cumprida com um array dos valores cumpridos das promises recebidas, na mesma ordem. Se alguma promise for rejeitada, a promise retornada também será rejeitada com o motivo da primeira rejeição.

O que é concorrência em JavaScript?

No contexto do JavaScript, concorrência é a capacidade do mecanismo JavaScript de executar vários trechos de código (tarefas) sem bloquear a execução de outras tarefas. Vale lembrar que JavaScript é principalmente uma linguagem de thread única, ou seja, só pode realizar uma operação por vez no código executado pelo usuário. No entanto, com a ajuda da programação assíncrona, como promises, JavaScript pode agendar tarefas para serem executadas simultaneamente.

A concorrência em JavaScript pode melhorar significativamente o desempenho, especialmente em operações de E/S, como solicitações de rede, operações no sistema de arquivos ou qualquer operação que exija algum tempo de espera.

Veja um exemplo de tarefas concorrentes em JavaScript:

javascript
let promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'task1');
});

let promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'task2');
});

Promise.all([promise1, promise2])
  .then(values => {
    console.log(values); // logs ['task1', 'task2']
  });

Neste exemplo, task1 e task2 são executadas simultaneamente. Embora task1 leve mais tempo para terminar, ela não bloqueia a execução de task2.

Este exemplo de código pode parecer semelhante ao anterior, mas, nos exemplos anteriores de código JavaScript, usamos Promise.resolve(1), que era resolvida imediatamente e retornava o número inteiro como valor. Este exemplo de execução concorrente mostra como as tarefas podem ser agendadas para serem executadas simultaneamente em uma thread em segundo plano.

Situações reais em que filas de Promises e concorrência são essenciais

Filas de Promises e concorrência estão presentes em toda parte no JavaScript. Por exemplo, em uma aplicação web, talvez seja necessário buscar dados de vários endpoints simultaneamente e, em seguida, processá-los sequencialmente, em uma ordem específica. Esse é um exemplo perfeito do uso de filas de Promises e concorrência.

Considere um sistema online de compra de ingressos de cinema. Quando alguém faz uma reserva, o sistema pode precisar executar várias tarefas, como verificar a disponibilidade de assentos, reservar o assento, processar o pagamento e enviar um e-mail de confirmação. As filas de Promises podem gerenciar essas tarefas e garantir que sejam executadas na ordem correta. Já algumas tarefas, como enviar e-mails de confirmação para várias pessoas, podem ser realizadas simultaneamente para aumentar a eficiência.

Entender e aplicar os conceitos de filas de Promises e concorrência em JavaScript pode melhorar muito o desempenho e a eficiência das suas aplicações. À medida que você se aprofunda em JavaScript, esses conceitos serão cada vez mais úteis no desenvolvimento de aplicações complexas e de alto desempenho.

Criando uma aplicação Deno para executar solicitações HTTP com fetch

Vamos ver como criar uma aplicação básica em Deno capaz de enviar várias solicitações HTTP com fetch em lote. Para isso, usaremos o método Promise.allSettled(). Nossa aplicação buscará dados de pacotes no endpoint JSON do registro npm. 

Você pode acompanhar este tutorial passo a passo. Se precisar consultar o código-fonte completo para reproduzir os detalhes da aplicação Deno apresentados neste artigo, acesse o repositório do GitHub: https://github.com/snyk-snippets/deno-promise-queues-batch-queue

Configurando o ambiente Deno

O primeiro passo para criar nossa aplicação é configurar o ambiente Deno. Deno é um runtime seguro para JavaScript e TypeScript, baseado no mecanismo JavaScript V8 e na linguagem de programação Rust. Para instalar o Deno, use o seguinte comando:

bash
curl -fsSL https://deno.land/x/install/install.sh | sh

Quando a instalação terminar, verifique se tudo deu certo executando o seguinte comando:

bash
deno --version

Esse comando exibirá a versão instalada do Deno.

Escrevendo um programa simples em Deno

Nosso programa em Deno enviará várias solicitações fetch em lote usando o método Promise.allSettled().

Promise.allSettled() é um método que retorna uma promise resolvida depois que todas as promises fornecidas forem resolvidas ou rejeitadas. O resultado é um array de objetos, cada um descrevendo o desfecho de uma promise. Esse método é especialmente útil quando a ordem em que as promises são concluídas não importa e você só precisa saber quando todas tiverem terminado.

Qual é a diferença entre Promise.all() e Promise.allSettled() ?


Promise.all() é adequado quando você precisa que todas as promises sejam cumpridas e quer interromper a operação assim que uma delas for rejeitada. Já Promise.allSettled() é útil quando você quer aguardar a conclusão de todas as promises, independentemente do resultado.

Buscando dados de pacotes npm no endpoint JSON do registro npm

Nossa aplicação buscará dados de pacotes no endpoint JSON do registro npm. O registro npm é um grande banco de dados de pacotes JavaScript e disponibiliza uma API pública que permite buscar dados de pacotes em formato JSON. Isso atende às nossas necessidades, pois facilita o processamento dos dados obtidos.

Exemplo de código do programa Deno

Veja um exemplo de como escrever um programa em Deno que envia várias solicitações HTTP em lote usando Promise.allSettled().

javascript
const urls = [
  'https://registry.npmjs.org/package1',
  'https://registry.npmjs.org/package2',
  'https://registry.npmjs.org/package3'
];

async function fetchPackageData() {
  const promises = urls.map(url => fetch(url));

  const results = await Promise.allSettled(promises);

  for (const result of results) {
    if (result.status === 'fulfilled') {
      const data = await result.value.json();
      console.log(data);
    } else {
      console.error(result.reason);
    }
  }
}

fetchPackageData();

Neste exemplo, criamos um array de URLs que queremos acessar. Em seguida, percorremos esse array e enviamos uma solicitação fetch para cada URL. Usamos Promise.allSettled() para aguardar a conclusão de todas as solicitações fetch e, então, processamos os resultados.

Uma resposta parcial do programa Deno acima:

json
{
  _id: "package1",
  _rev: "8-591c2789a67390636bd11cdacd69d197",
  name: "package1",
  "dist-tags": { latest: "0.0.0" },
  versions: {
    "0.0.0": {
      name: "package1",
      version: "0.0.0",
      main: "index.js",
      scripts: { test: 'echo "Error: no test specified" && exit 1' },
      author: "",
      license: "ISC",
      _id: "package1@0.0.0",
      dist: {
        shasum: "2c1e73fbc7351131b2f657417e50c2f1330450a8",
        tarball: "https://registry.npmjs.org/package1/-/package1-0.0.0.tgz",
        integrity: "sha512-U4a0VTa026SElK/J6JbW7/pzFZHddrAQ3OEbgCHFwXV/Ytt+Ece37GppLjP+GBRBqge7dZS9qlEOOou8m/1Fiw==",
        signatures: [ [Object] ]
      },
      _from: ".",
      _npmVersion: "1.4.3",
      _npmUser: { name: "zhoutj", email: "zhoutianjia@126.com" },
      maintainers: [ { name: "zhoutj", email: "zhoutianjia@126.com" } ]
    }
  },
  readme: "ERROR: No README data found!",
  maintainers: [ { name: "zhoutj", email: "zhoutianjia@126.com" } ],
  time: {
    modified: "2022-06-23T06:46:19.731Z",
    created: "2014-05-05T02:51:24.933Z",
    "0.0.0": "2014-05-05T02:51:24.933Z",
    "0.0.1": "2014-05-05T02:52:51.624Z"
  },
  license: "ISC",
  readmeFilename: ""
}

Aprimorando a aplicação Deno com o módulo BatchQueue

O módulo BatchQueue no Deno oferece um mecanismo para gerenciar e controlar a execução de tarefas na sua aplicação Deno. É uma ferramenta poderosa que permite limitar o número de tarefas executadas simultaneamente. Isso pode ser útil ao trabalhar com recursos sujeitos a limites de uso ou ao lidar com tarefas que exigem muito da CPU ou da memória.

Em solicitações HTTP, é melhor agir com responsabilidade e limitar o número de solicitações simultâneas enviadas a um serviço remoto, como o registro npm, para evitar saturá-lo e sobrecarregá-lo. Limitar as solicitações simultâneas também ajuda a evitar que seu programa seja identificado como uma possível tentativa de negação de serviço.

O BatchQueue no Deno permite criar uma fila de promises e executá-las em lotes. Essa técnica pode melhorar significativamente o desempenho da sua aplicação Deno, evitando a sobrecarga dos recursos do sistema e aumentando a capacidade de processamento das tarefas.

Aprimorando o programa Deno para usar uma fila com baixa concorrência

Vamos considerar um programa Deno que faz várias solicitações HTTP simultaneamente. Por padrão, o Deno tentará executar todas essas tarefas ao mesmo tempo. No entanto, isso pode causar problemas se houver tarefas suficientes para consumir todos os recursos disponíveis do sistema ou se elas interagirem com sistemas externos que tenham limites de uso.

Com o módulo BatchQueue, podemos controlar o número de tarefas simultâneas. Veja um exemplo simplificado de como usar BatchQueue em um programa Deno:

javascript
import { BatchQueue } from "https://deno.land/x/batch_queue/mod.ts";

// URLs to make HTTP requests to
const urls = [
  'https://registry.npmjs.org/package1',
  'https://registry.npmjs.org/package2',
  'https://registry.npmjs.org/package3'
];

// Initialize the queue with a concurrency of 2
const q = new BatchQueue(2);

// Function to make HTTP request
async function makeHttpRequest(url) {
  try {
    const response = await fetch(url);
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error fetching URL:', url, error);
  }
}

for (const url of urls) {
  q.queue(() => makeHttpRequest(url));
}

await q.run()
await q.allSettled

Neste exemplo, o BatchQueue está configurado com uma concurrency de 5, o que significa que somente cinco tarefas poderão ser executadas simultaneamente.

Cada tarefa é adicionada à fila do BatchQueue, e a função makeHttpRequest é chamada quando a tarefa sai da fila para ser executada. O BatchQueue garante que apenas cinco tarefas sejam executadas ao mesmo tempo.

Fila de Promises versus Promise.all()

Ao comparar a versão aprimorada do programa Deno, que usa BatchQueue, com a versão inicial, você verá uma melhora significativa no uso dos recursos do sistema e no desempenho geral da sua aplicação Deno. 

O mecanismo BatchQueue garante que o programa Deno não esgote todos os recursos disponíveis do sistema, algo comum ao executar um grande número de tarefas simultaneamente. 

Com o módulo BatchQueue no Deno, você pode gerenciar com eficiência a execução das tarefas na sua aplicação e melhorar o desempenho e a capacidade de resposta dos seus programas Deno.

Adicionando ProgressBar à aplicação Deno

Adicionar feedback à sua aplicação Deno pode melhorar muito a experiência do usuário. Uma das maneiras mais intuitivas de mostrar esse feedback em uma CLI é usar uma barra de progresso.

Um desses módulos é o ProgressBar, que simplifica a adição de uma barra de progresso à sua aplicação Deno.

O módulo ProgressBar é um pacote leve e altamente personalizável que oferece uma barra de progresso fácil de integrar às suas aplicações. Ele conta com uma API simples, que facilita a implementação, além de opções de personalização para adaptar a aparência da barra à sua aplicação.

Para instalar o módulo ProgressBar, importe-o para a sua aplicação desta forma:

javascript
import ProgressBar from "https://deno.land/x/progress/mod.ts";

Adicionando ProgressBar para exibir o progresso das solicitações concluídas

Depois de importar o módulo ProgressBar, você pode usá-lo para mostrar visualmente o progresso das solicitações concluídas na sua aplicação Deno. 

Você pode criar uma nova instância de ProgressBar e especificar o número total de etapas que a barra deve representar. Depois, para cada solicitação concluída, chame o método .tick() para avançar a barra de progresso.

Veja um exemplo básico de como usar ProgressBar para acompanhar e exibir o progresso das solicitações concluídas:

javascript
import ProgressBar from "https://deno.land/x/progress/mod.ts";

const totalRequests = 100;
const progressBar = new ProgressBar({
  total: totalRequests,
  complete: '=',
  incomplete: ' ',
  display: ':bar :percent',
});

// Simulate a loop that represents a batch of requests
for (let i = 0; i < totalRequests; i++) {
  // Simulate a completed request
  progressBar.render(i);
  await new Promise((resolve) => setTimeout(resolve, 100)); // simulate async delay
}

Neste exemplo, a barra de progresso avançará uma etapa cada vez que uma solicitação for concluída. Você pode personalizar a aparência da barra ajustando as opções complete e incomplete ao criar a instância de ProgressBar.

Exemplo de código do programa Deno com ProgressBar

Por fim, vamos ver um exemplo mais elaborado de integração do ProgressBar em uma situação mais próxima do mundo real. Suponha que temos um lote de solicitações de API para enviar e queremos acompanhar o progresso.

javascript
import { BatchQueue } from "https://deno.land/x/batch_queue/mod.ts";
import ProgressBar from "https://deno.land/x/progress/mod.ts";

// URLs to make HTTP requests to
const urls = [
  'https://registry.npmjs.org/package1',
  'https://registry.npmjs.org/package2',
  'https://registry.npmjs.org/package3'
];

const totalRequests = urls.length;
let currentRequest = 0;
const progressBar = new ProgressBar({
  total: totalRequests,
  complete: '=',
  incomplete: ' ',
  display: ':bar :percent',
});

// Initialize the queue with a concurrency of 2
const q = new BatchQueue(2);

// Function to make HTTP request
async function makeHttpRequest(url) {
  progressBar.render(++currentRequest);
  const response = await fetch(url);
  const data = await response.json();
  // @TODO do something with the data...
}

for (const url of urls) {
	q.queue(() => makeHttpRequest(url));
}

await q.run()
await q.allSettled

Neste exemplo, simulamos o envio de solicitações de API e usamos o ProgressBar para acompanhar o progresso. Cada chamada a sendRequest() representa uma solicitação enviada e uma resposta aguardada. A cada solicitação concluída, avançamos a barra de progresso chamando progressBar.tick().

Ao executar nosso programa Deno completo, com os módulos Promises Batch Queue e ProgressBar, obtemos a seguinte saída na linha de comando:

bash
@lirantal ➜ /workspaces/project-app (main) $ deno run -A app.ts 
================================================== 100.00%

E pronto! Você adicionou uma barra de progresso ao seu aplicativo Deno para exibir o avanço das solicitações concluídas. O módulo ProgressBar é um ótimo complemento para seus aplicativos Deno, pois oferece uma maneira intuitiva de acompanhar o status de tarefas demoradas. Experimente no seu próximo projeto Deno!

Lembre-se: o aplicativo Deno completo deste exemplo de Promise Batch Queue está disponível em: https://github.com/snyk-snippets/deno-promise-queues-batch-queue

Segurança em aplicativos Deno: vulnerabilidade SSRF

A cibersegurança é uma preocupação fundamental em qualquer projeto de desenvolvimento de software. No ecossistema Deno, um possível risco de segurança ao qual os desenvolvedores precisam ficar atentos é a vulnerabilidade de falsificação de solicitação do lado do servidor (SSRF).

Esta seção explora a vulnerabilidade SSRF, os riscos que ela representa para aplicativos Deno e maneiras de mitigá-la. Também apresentaremos um exemplo prático de código para um programa Deno seguro.

O que é uma vulnerabilidade SSRF?

SSRF é um tipo de vulnerabilidade que permite a um invasor manipular um aplicativo do lado do servidor para realizar interações de rede não autorizadas. Ela representa um risco porque possibilita que o invasor interaja com sistemas internos, o que pode levar a acessos não autorizados ou vazamento de dados. Em essência, uma vulnerabilidade SSRF pode transformar o servidor em um proxy para as atividades maliciosas do invasor.

Vulnerabilidade SSRF em aplicativos Deno

O Deno foi projetado para ser seguro por padrão: todos os scripts são executados em uma sandbox segura, a menos que o usuário conceda permissões explicitamente. No entanto, quando as permissões necessárias são concedidas, os aplicativos Deno podem ficar expostos a vulnerabilidades SSRF.

Por exemplo, se um aplicativo Deno receber a permissão "allow-net", poderá fazer solicitações de rede a qualquer host. Um invasor pode explorar isso injetando um host malicioso na solicitação, causando uma vulnerabilidade SSRF.

Em geral, os desenvolvedores podem executar aplicativos Deno, como o programa de fila de Promises que escrevemos, da seguinte forma:


bash
$ deno run --allow-net app.ts

Como mitigar vulnerabilidades SSRF em aplicativos Deno

Para mitigar possíveis vulnerabilidades SSRF, os desenvolvedores precisam adotar práticas seguras de programação, incluindo:

  1. Princípio do menor privilégio: conceda apenas as permissões mínimas necessárias para que o aplicativo Deno funcione corretamente. Se o aplicativo não precisar fazer solicitações de rede, não conceda a permissão --allow-net (ou sua forma abreviada, a flag de linha de comando -A).

  2. Validação de entrada: valide corretamente todas as entradas do usuário e rejeite as suspeitas ou malformadas. Em geral, os usuários não devem fornecer URLs absolutas. Limite-os às URLs relativas hospedadas e permitidas pelo seu aplicativo.

Exemplo de código de um programa Deno seguro

Vamos ver um aplicativo Deno básico com medidas de segurança para ajudar a mitigar vulnerabilidades SSRF.

javascript
import { serve } from "https://deno.land/std/http/server.ts";

console.log("Server running on http://localhost:8000/");

serve((req) => {
  const url = new URL(req.url, `http://${req.headers.get('host')}`);
  const host = url.hostname;

  if (host !== 'localhost' && host !== '127.0.0.1') {
    return new Response("Unauthorized host\n");
  } else {
    return new Response("Hello World\n");
  }
}, { port: 8000 });

Neste exemplo de código, servimos um servidor HTTP na porta 8000. Quando uma solicitação é recebida, verificamos o nome do host na URL da solicitação. Se não for 'localhost' nem '127.0.0.1', respondemos com a mensagem "Unauthorized host", impedindo assim solicitações a hosts externos.

Ao adotar práticas seguras de programação e ter cuidado com as permissões concedidas aos aplicativos Deno, podemos mitigar com eficácia o risco de vulnerabilidades SSRF.

A importância de gerenciar tarefas simultâneas com eficiência no Deno

Gerenciar tarefas simultâneas com eficiência é essencial para desenvolver aplicativos de alto desempenho. No Deno, isso é ainda mais importante, pois ele foi criado para lidar com código moderno em JavaScript e TypeScript, que costuma envolver muitas operações assíncronas.

Com filas de Promises e processamento em lotes, podemos gerenciar recursos com eficiência e evitar problemas como estouro de memória ou limitação da CPU. Isso melhora a confiabilidade e a capacidade de resposta do aplicativo, aprimorando a experiência geral do usuário.

Explore o Deno e seus módulos

O Deno oferece muito mais do que filas de Promises e processamento de tarefas simultâneas em lotes. É um runtime poderoso e flexível, com diversos recursos e módulos que ajudam a criar aplicativos robustos, seguros e eficientes.

Por exemplo, a biblioteca padrão do Deno oferece um conjunto de módulos de alta qualidade e revisados, compatíveis com o Deno. Ela inclui módulos para manipulação de datas e horas, hashing, servidores HTTP, testes e muito mais.

Com foco em segurança, o Deno também permite controlar de forma granular o que um aplicativo pode acessar, algo essencial diante das ameaças à cibersegurança. Ainda assim, muitas vulnerabilidades, como a SSRF, exigem intervenção específica e controles de segurança implementados pelos desenvolvedores.

Para entender melhor o Deno e como usá-lo, leia a documentação oficial do Deno. Lá, você encontrará informações sobre vários recursos e módulos do Deno, fundamentais para entender as filas de Promises e o processamento de tarefas simultâneas em lotes.

Para garantir a segurança do seu aplicativo, é fundamental entender as diferentes ameaças à segurança de aplicativos, incluindo as vulnerabilidades de falsificação de solicitação do lado do servidor (SSRF). Confira estes recursos adicionais para entender e mitigar vulnerabilidades SSRF:

Proteja seu código enquanto desenvolve

O Snyk analisa seu código em busca de problemas de qualidade e segurança e recomenda correções direto no seu IDE.

Leia mais

blog feature ai lilac
Blog

Transforme seu backlog de vulnerabilidades em pull requests com remediação agentiva

O Evo Remediation Agent está em Open Preview e traz a resolução automatizada de dependências para o Evo Agentic AppSec. Agora, as equipes de AppSec podem executar campanhas contínuas de remediação

AI Background min crop
Blog

A IA está acionando todos os riscos que você aceitou: sete insights do painel de segurança de IA sem filtros

A IA está tornando os ataques mais baratos e rápidos, expondo riscos que as organizações já carregam. Quatro líderes de segurança explicam por que a defesa na velocidade das máquinas e a correção mais rápida são essenciais.

blog feature ai violet
Blog

VulnBump: agentes de IA conseguem corrigir dependências vulneráveis sem quebrar o build?

O VulnBump testa agentes de IA em 307 atualizações reais de dependências. Uma correção só é considerada válida se eliminar a vulnerabilidade e mantiver o build e os testes passando.