O documento discute background jobs utilizando a ferramenta Sidekiq. Sidekiq é um processador de filas baseado em Redis que pode ser usado para executar tarefas em segundo plano, como envio de e-mails, geração de relatórios e inserção de dados no banco. O documento também fornece exemplos de uso de Sidekiq e boas práticas para trabalhar com jobs assíncronos.
11. Boas práticas
- Parâmetros dos jobs serem sempre pequenos e simples
- Não chamar workers dentro de transactions do banco de dados
- Idempotency
- Concorrência, benchmark e saber os limites
13. Envio de Email
- Emails devem sempre serem enviados em background
- Servidor de envio de emails ou servidor de email do cliente podem estar offline
- Caixa de entrada do usuário pode estar cheia
- deliver_later
- delay
14. Geração de Relatórios
- Processamento grande de dados
- Queries grandes no banco
- Salvar arquivos e enviar emails
Background job é, como o próprio nome já diz, o processamento de alguma tarefa, algum job, em background, sem precisar que a aplicação utilizada pelo usuário fique parada esperando essa tarefa ser realizada. Pegando de forma mais macro, pensando em tarefas macros, para o usuário final, o processamento da foto é algo feito em background, pois enquanto isso é realizado, o usuário pode continuar usando o app, inclusive mandar mais fotos. Pensando mais especificamente de sistemas, é por exemplo, o envio de email de confirmação para o usuário após um cadastro, ser executado de forma que não interfira no cadastro do usuário, o cadastro ter sido finalizado, e em paralelo, sem que o usuário mesmo saiba, o email está sendo processado para ser enviado
O rails é singlethreaded e por isso se torna mais necessário ainda a utilização de background jobs para permitir que mais processos possam ser executados em paralelo
Redis é um banco de dados em memória, que é muito utilizado para cache, pois é fácil de utilizar. Pode ser utilizado como banco de dados realmente, ou até message broker. No nosso caso, ele é o banco de dados que usaremos para guardar os nossos jobs e as filas de execução.
O sidekiq tem o redis como dependência, já vindo integrado com o mesmo para utilização.
Existem algumas alternativas de gems para serem utilizadas com o ruby para processamento de background jobs. O resque ainda é o mais utilizado, mas aqui eu vou focar no sidekiq e vou mostrar exemplos de como utilizar ele.
https://github.com/mperham/sidekiq#performance
Uma coisa curiosa que acho que vale a pena citar aqui, há alguns anos eu trabalhei em um projeto que usava o suckerpunch para background jobs. O curioso é que na verdade ele é um processador asíncrono, ele tem uma estrutura de worker, filas, etc, mas ele não usa processos em background, mas executa os processos só de forma asíncrona. Por exemplo, no heroku, se utilizarmos o sucker_punch em algum projeto, não seria preciso ter worker, bastaria ter os web dynos da aplicação rodando que o sucker_punch funcionaria. Por isso não vejo tanta vantagem nele, pois apesar dele permitir que o usuário receba o feedback da ação enquanto algum job que essa ação disparou é executado de forma asíncrona, ele continua ocupando bando do servidor da aplicação.
o delayed job persiste e utiliza o banco e dados para gerenciar os jobs. boa parte do motivo do sidekiq ser ráido, é por ele utilizar o redis para essa função
Mostrar exemplo do código que fiz de sample, mostrando como o worker é definido e executado, mostrando exemplos do perform_in, do perform_async, do perform_at, mostrando como e a instalação, como adicionar segurança para o acesso ao painel web do sidekiq, que necessita do sinatra instalado também, etc, falar que o delay pode ser chamado de qualquer classe na verdade.
Falar da API do sidekiq, mostrar exemplo de como pegar a fila, ver o job, etc.
Evitar sempre serializar objetos grandes, primeiro que eles podem acabar ocupando muita memória no redis, e segundo que o ideal é passar uma referência para o objeto, para que o job busque o objeto e use os dados mais atuais do objeto.
Essa foi uma adição pessoal minha, mas já tive alguns problemas de workers serem executados e darem erro de record not found. Como o worker roda em background, se você chamar ele a partir de uma transaction e ele for acessar algum objeto que vai ser criado ou modificado naquela transaction, existe o risco do worker executar antes da transaction acabar e com isso aquele objeto ainda não existir, ou os dados dele ainda não terem sido atualizados
Idempotency significa não ter problema se o seu job for executado mais de uma vez com os mesmos parâmetros. Por exemplo, se você tem um worker que ao final de um processamento precisa mandar um email, se o envio do email falhar, o work vai para o retry e vai ser executado novamente pelo sidekiq. Executar uma segunda vez o processamento feito pelo worker vai gerar algum problema? Se sim, o worker não foi implementado da forma correta. Algumas alternativas são usar transaction para workers que fazem inserção no banco de dados, pois assim qualquer exceção desfaz tudo que o worker tiver feito antes da exceção, ou colocar condicionais para as ações do worker, ou até ignorar certos erros que podem não ser tão importantes.
E a concorrência é realmente utilizar o background jobs ao máximo, colocando para vários jobs serem executados em paralelo, fazendo benchmark, metrificando os workers, para saber quanto de memória, cpu, etc, seu servidor onde os workers estarão rodando precisa. Não adianta jogar tudo para background e sobrecarregar a cpu ou a memória e o servidor não aguentar.
O envio de email, além da possibilidade de demora, pode ocasionar erros que não devem atrapalhar a conclusão da ação do usuário.
Painel da marca, que processa em background, gera xls, e manda por email, mas também retorna para download do usuário caso ele queira esperar.
Criação de grupos, podendo utilizar aluno e disciplina/aula como exemplo de inserção de dados dessa forma.