Como fiz para corrigir dados na casa dos 20000k de forma assíncrona com JS

Gustavo S. Rodrigues
3 min readFeb 9, 2018

--

Nesse artigo abordarei a forma que eu resolvi um problema de correção de massa de dados num volume estratosférico durante o voo.

É importante lembrar que não é recomendável fazer operações desse tipo sem uma interrupção ainda que parcial da aplicação, mas, nem sempre temos uma janela para isso, então temos que por a mão na massa e cruzar os dedos.

Antes de chegar nessa solução, houveram duas tentativas de scripts de banco para resolver tamanho volume de dados, mas em ambas eu cai no problema de memória do banco ou em um script muito complexo que não podia ser paralelizado ou que se tivesse algum deadlock e pra piorar, ele não era capaz de reexecutar automaticamente, então pensei, já que o banco tem limite de alocação de memória para processar cada processo, por que não fazer com que ele trabalhe em um fluxo keep alive com processamento assíncrono, e assim eu fiz

Antes de qualquer mistificação, essa rotina não foi finalizada em 10 min, ou segundos, mas foi muito mais rápida do que qualquer outra tentada por mim e pela equipe (cerca de 3h).

O Problema

Temos 5 tabelas relacionais que possuem registros que se relacionam, e mais, temos alguns parâmetros extras de índices, que nem sempre eram respeitados, tornando a consulta cada vez mais custosa, o que me obrigou a fazer uma correção top down usando a tabela pai para replicar dados para as filhas, e assim corrigir a relação. Então, eu tinha uma tabela com cerca de mais de dois milhões de registros com filhas que chegavam a 20 milhões cada.

A Solução

Sabendo que eu tenho x = 4*(x*2), onde num processo tradicional eu só poderia rodar uma tabela por vez sem estourar a memória do banco ou ter deadLock, o que me levou a uma conta rápida, que era: quantos registros eu consigo fazer por transação e quantas transações eu consigo fazer em paralelo, e isso me levou de volta a um calculo onde seria possível fazer lotes de até 10.000 registros por transação e até 4 transações em simultâneo para tabelas distintas. Mas ainda assim, eu tinha um problema, e se travar?, como eu posso fazer o banco continuar executando de onde parou, então cheguei a conclusão, isso pode ser feito com js via bash e de quebra com um script simplista mas extremamente eficaz.

Requisitos:

  1. Preciso saber quantos registros eu quero rodar por transação
  2. Quantos dados eu tenho a registrar
  3. Quantos registros já foram corrigidos
  4. Em caso de falha, preciso retomar a execução do script de onde ele parou
  5. cada rotina deve ser isolado por seu próprio domínio

Então, chegamos a esse domain de base:

Então para cada correção eu tenho um mini modulo que resolve uma única rotina, onde eu convencionei seguindo a seguinte estrutura:

app/

— /domain/

— — /database/

— — — /routineDescription.js

— /controllers

— — /DomainControllerScript.js

— config.js

— datasource.js

— index.js

Com essa estrutura eu poderia chama-la por http ou usar um processo de chamada por bash, como optei por bash usando o Commander e então fiz o controller usando o Commander e cada controller tinha seus de comandos ao invés de rotas, e a index eu fazia apenas as chamadas dos módulos e controllers.

Desse modo cada comando era uma espécie de rota, e bastava eu executar cada rota em janelas diferentes acompanhando o trafego do banco.

Nota final

Acredito que independente de ser uma rotina de banco, ou uma rotina de correção de arquivos, ou dados em geral, essa estrutura para bash, com controladores com camadas de domínios pode te ajudar a montar soluções cada vez mais modularizadas. Assim como definir um processo com limites de execução paralelizável.

--

--

Gustavo S. Rodrigues

Sou um arquiteto de soluções apaixonado por linhas de códigos e por problemas não convencionais