Trabalhando com Multithreading e Streaming no NodeJs – Parte 1

O Node.js é uma das tecnologias que mais chama a atenção por ser rápido, leve e poderoso, além de permitir o desenvolvimento de aplicações escaláveis e tolerantes a falhas. Contudo, em alguns cenários um pouco mais substanciais devemos olhar com mais atenção para a maneira como se trabalha com essa tecnologia.
Imagine que você como desenvolvedor, precisa construir um serviço de importação de arquivos e nele ainda precisa ter alguns endpoints específicos, considerando esse cenário vamos imaginar que o serviço precisa ter 2 endpoints. O primeiro é para solicitar a importação de um arquivo e o segundo é para reportar o status da importação de algum arquivo. Isto é, além de baixar e ler o arquivo, o serviço ainda precisa responder requests que podem vir com certa frequência.
Agora imagine que esse serviço foi desenvolvido da maneira “tradicional” sem nenhuma preocupação com performance e disponibilidade, em determinado dia o serviço que desenvolvemos recebeu uma solicitação para baixar e ler um arquivo csv grande e digamos que ele tenha pelo menos 7 GB, até aqui tudo bem, o serviço foi feito para realizar a importação independente do tamanho, porém, neste mesmo momento, os usuários começam a reportar que o serviço parou de responder e ninguém está conseguindo importar outro arquivo ou consultar o status das suas importações. Isso aconteceu porque o Node é orientado a eventos e utiliza o conceito de thread única para gerenciar a pilha de eventos ou pilha de chamada (Call Stack), ou seja, todas as solicitações são processadas uma a uma, através de uma camada de processamento enquanto o arquivo de 7GB está sendo importado, nenhuma outra solicitação ao nosso serviço vai ser respondida.
É em cenários assim que nós como desenvolvedores devemos começar a pensar em trabalhar com multi-threading, isto é, criar threads secundárias e paralelas a thread principal que vão executar serviços que deixem a threads principal livre para responder a outras solicitações. Essas threads secundárias são chamadas de workers, que são processos em background de I/O assíncrono não bloqueastes gerenciados pela libuv, uma biblioteca open source multiplataforma escrita em linguagem C, a qual utiliza um thread-pool para gerenciar operações paralelas. Pensando nisso, vamos ver como trabalhar com multi-threading no node.
Primeiramente, vamos precisar trabalhar com a API nativa do node chamada worker_threads, conforme o exemplo abaixo:
const { Worker } = require("worker_threads");
Em seguida, devemos criar um arquivo javascript com a lógica que queremos implementar para realizar a importação do arquivo. Por enquanto vamos deixar a lógica e a regra para um próximo artigo, onde aprenderemos a trabalhar com streaming de arquivos.
~ worker.js const { workerData } = require("worker_threads"); const importFile = (file) => { // Lógica de importação console.log(file); return true; } importFile(workerData.file);
Em seguida, voltamos ao arquivo anterior, onde criamos a instância do worker, passando o arquivo que acabamos de criar:
//Criando um novo worker const worker = new Worker("./worker.js", { workerData: { file }}); //Listeners worker.once("message", result => { console.log(result); }); worker.on("error", error => { console.log(error); }); worker.on("exit", exitCode => { console.log(exitCode); });
Já configuramos também alguns listeners que vamos usar para capturar as mensagens que podem vir do nosso processo rodando em threads secundárias. Usaremos para receber mensagens de erro e atualização de progresso de importação.
Com esses três trechos de código bem simples, já conseguimos separar os processos em várias threads, deixando a thread principal livre para responder a outras solicitações e assim evitamos problemas de disponibilidade do nosso serviço.
No próximo artigo veremos como realizar a importação do arquivo usando stream e como reportar as mensagens de erro e progresso da importação para a thread principal.
A Seguir:
- Trabalhando com multithreading e streaming no NodeJs – Parte 2
- Design Patterns: Strategy
Deixe um comentário