Estratégias de Paralelismo e Divisão de Responsabilidades em Sistemas

Mattheus Cassundé
gb.tech
Published in
4 min readJan 9, 2024

Paralelismo é extremamente funcional quando temos algumas responsabilidades bem definidas dentro do nosso sistema, a divisão de responsabilidade entendo que é o principal ponto de partida.

Escopo

Vamos imaginar um sistema que fará o fechamento da folha de pagamento dos funcionários.

Nesse fechamento hipotético precisamos identificar quantidade de horas extras dos funcionários, multiplicar o resultado pelo valor da hora do funcionário e adicionar o valor encontrado ao salário para assim chegarmos ao valor final a ser pago.

Quebrando responsabilidades

Como podemos dividir as responsabilidades nesse cenário? Existe uma ordem de acontecimento ?

Primeiro vamos pensar, nesse cenário não podemos fazer o fechamento sem as horas extras previamente calculadas, com isso entendido, fica claro que o cálculo de horas extras não depende de nada, mas o fechamento depende do cálculo das horas extras. Agora vamos pensar mais um pouco, vamos iniciar com a rotina de calcular as horas extras. Será que conseguimos quebrar essa rotina ? Será que a rotina precisa mesmo processar todos os funcionários de uma vez ?

Vamos imaginar que todos os meses esse sistema fará o cálculo de horas extras para 2mil funcionários, nessa nossa primeira implementação faremos um select na base de dados, pegaremos os 2mil funcionários e para cada funcionário encontrado calcularemos o valor de hora extra.

Um dos problemas com a abordagem acima é que caso um único funcionário falhe, faremos o reprocessamento de todos os funcionários pois tudo está acoplado dentro de uma única rotina.

Beleza, para mitigar esse problema, vamos dividir nosso problema em duas partes:
* Identificação de cada Funcionário.
* Execução do calculo de hora extra dado um funcionário.

Identificando todos os Funcionários

Abaixo temos um simples diagrama que representa a primeira parte da implementação, vamos identificar todos os funcionários que estão aptos e enfileirá-los.

Diagrama simplificado de cálculo de hora extra

Em nosso exemplo estamos utilizando o RabbitMQ para controlar nossas mensagens

Podemos implementar controles de status ou outro mecanismo que de alguma forma ajude a identificar se um Funcionário está ou não apto para ter suas horas extras calculas.

Quando lidamos com eventos temos o benefício do desacoplamento, mas temos que nos preocupar com outros fatores, como por exemplo, lidar com mensagens duplicadas, caso por qualquer motivo chegue uma mensagem que já foi processada, essa mensagem precisa ser descartada, isso para evitar sobrescrita ou desperdício de recursos.

Executando o cálculo de hora extra

Agora vamos implementar um Listener que receberá esse único funcionário e realizará todo o processo de cálculo de hora extra, com o RabbitMQ, conseguimos configurar a quantidade de Consumers que um determinado Listener produzirá, ou seja, podemos fazer com que processemos vários Funcionários ao mesmo tempo.

Vale observar que a nossa rotina de cálculo de hora extra é totalmente isolada entre os funcionários, podemos processar com segurança todos em paralelo, pois nesse momento não existe recurso em concorrência.

Com essa abordagem temos o processo de cálculo de hora extra sendo executado por funcionário e caso algum funcionário falhe conseguiremos reprocessar apenas o funcionário que falhou.

DLQ

Com nosso Listener implementado, agora podemos tirar proveito da DLQ (Dead Letter Queue), que nada mais é do que o local para onde as mensagem que não conseguiram ser processadas vão ser armazenadas, é indicado que sempre que uma mensagem for direcionada para DLQ, seja disparado algum tipo de alarme, isso para que a equipe responsável possa fazer suas análises, isso lembra um post que falo sobre "A importância dos logs".

O Processo de fechamento

Com o processo de fechamento conseguimos fazer da mesma forma, todos os processos serão por funcionário, quando o funcionário sair da fila de cálculo de hora extra ele irá para a fila de fechamento de folha de pagamento.

Diagrama da estrutura de fila

Nesse fluxo fica explicito, sempre que um funcionário chegar na Fila de Fechamento ele precisará passar na fila de Calculo de Hora Extra.

Conclusão

Para paralelizar e escalar com segurança, é crucial isolar adequadamente os processos, só isso já é bem difícil principalmente em sistemas monolíticos onde existe muito acoplamento, tolerância a falhas não é coisa de microservice e sim de qualquer arquitetura.

Temos cenários mais complexos, como por exemplo, receber mensagem para descontar valor de um saldo único, isso gera concorrência ou seja, dois processos querendo descontar do mesmo saldo, mas nesse post vou abordar a forma mais simples do paralelismo.

Espero que tenha ajudado a pensar em alternativas antes de tentar paralelizar um processo já existente ou no desenho de um novo processo, qualquer dúvida ou comentário é só chamar ;)

--

--