Sidekiq ou Delay jobs as vantagens e desvantagens e implementação no Ruby on Rails com TDD
Ao iniciar uma das minhas primeiras experiências como desenvolvedor pleno, me deparei com um cenário desafiador, repleto de novos conceitos para assimilar. Entre eles, os jobs, especialmente com Sidekiq e Delayed Job, representaram um desafio inicialmente complexo. Recordo-me das dificuldades que enfrentei ao tentar depurar uma aplicação que utilizava jobs. No entanto, essa fase foi crucial para o meu desenvolvimento profissional. Após mudar de empresa, tive a oportunidade de aprender significativamente com mentores que contribuíram imensamente para o meu crescimento na área.
Se você está começando sua jornada no desenvolvimento, entender e saber como utilizar Jobs com Sidekiq ou Delayed Job é essencial para sua carreira. E se você já possui experiência na área mas ainda tem dúvidas sobre quando e como aplicar essas ferramentas, este overview é para você. Vamos mergulhar no mundo dos jobs e explorar como eles podem otimizar e enriquecer seus projetos em Ruby on Rails.
No desenvolvimento de aplicações web com Ruby on Rails, frequentemente nos deparamos com a necessidade de executar tarefas demoradas, como o envio de e-mails, de forma assíncrona. Duas das soluções mais populares para isso são o Sidekiq e o Delayed Job.
Sidekiq
Vantagens:
- Performance: Sidekiq é conhecido por sua alta performance, pois utiliza threads em vez de processos, o que é mais eficiente em termos de uso de memória e tempo de inicialização.
- Confiabilidade: Possui um sistema robusto de re-tentativas e um painel de controle para monitorar e gerenciar tarefas.
- Comunidade e Suporte: Tem uma comunidade ativa e uma ampla gama de documentação disponível.
Desvantagens:
- Complexidade: Pode ser mais complexo de configurar e gerenciar, especialmente em sistemas maiores.
- Dependência do Redis: Requer Redis, o que pode ser uma desvantagem se você não quiser adicionar outra tecnologia ao seu stack.
Delayed Job
Vantagens:
- Simplicidade: Mais simples de configurar e usar, especialmente para aplicações menores ou para equipes com menos experiência.
- Armazenamento Flexível: Pode usar o Active Record para armazenar tarefas, o que pode ser conveniente se você já estiver usando o Rails.
Desvantagens:
- Performance: Geralmente é mais lento que o Sidekiq, pois cria um novo processo para cada tarefa.
- Menos Funcionalidades: Não possui tantas funcionalidades avançadas quanto o Sidekiq, como um painel de controle robusto.
Implementando Envio de E-mails Assíncrono com Sidekiq e TDD
Configuração do Ambiente
-
Adicione o Sidekiq ao seu Gemfile:
gem 'sidekiq'
-
Configure o Sidekiq como o adaptador de fila:
Emconfig/application.rb
, adicione:config.active_job.queue_adapter = :sidekiq
-
Instale e configure o Redis:
O Sidekiq depende do Redis. Certifique-se de que ele esteja instalado e configurado corretamente.
Para configurar o Redis no seu projeto Ruby on Rails e utilizá-lo com Sidekiq, você precisará seguir alguns passos. A configuração do Redis geralmente envolve definir a URL do servidor Redis, que pode ser especificada através de uma variável de ambiente. Aqui está um guia passo a passo:
-
Instale o Redis:
Certifique-se de que o Redis esteja instalado em seu ambiente de desenvolvimento. Se estiver usando um sistema baseado em Unix, você pode instalá-lo usando um gerenciador de pacotes comoapt
oubrew
. Por exemplo:brew install redis
-
Inicie o Servidor Redis:
Após a instalação, inicie o servidor Redis. Em um terminal, execute:redis-server
-
Adicione o Sidekiq ao seu Gemfile:
No seu projeto Rails, adicione o Sidekiq aoGemfile
:gem 'sidekiq'
-
Instale as Gems:
Executebundle install
para instalar as gems necessárias, incluindo o Sidekiq. -
Configure as Variáveis de Ambiente:
Defina a URL do Redis em suas variáveis de ambiente. Você pode fazer isso de várias maneiras, mas uma abordagem comum é usar a gemdotenv
para gerenciar variáveis de ambiente em desenvolvimento.- Adicione
dotenv-rails
ao seu Gemfile:gem 'dotenv-rails', groups: [:development, :test]
- Crie um arquivo
.env
na raiz do seu projeto e adicione a URL do Redis:REDIS_URL=redis://localhost:6379/0
- Adicione
-
Configure o Sidekiq para Usar o Redis:
Configure o Sidekiq para usar o Redis como seu sistema de armazenamento de fila. Crie um arquivo de inicialização para o Sidekiq emconfig/initializers/sidekiq.rb
e adicione o seguinte código:Sidekiq.configure_server do |config| config.redis = { url: ENV['REDIS_URL'] } end Sidekiq.configure_client do |config| config.redis = { url: ENV['REDIS_URL'] } end
-
Inicie o Sidekiq:
Com o Redis em execução, você pode iniciar o Sidekiq. Em um terminal, execute:bundle exec sidekiq
-
Verifique se Tudo Está Funcionando:
Para verificar se o Sidekiq está conectado ao Redis, você pode usar o painel do Sidekiq. Adicione o seguinte ao seuroutes.rb
:require 'sidekiq/web' mount Sidekiq::Web => '/sidekiq'
Agora, você pode acessar
http://localhost:3000/sidekiq
para ver o painel do Sidekiq.
Lembre-se de que, em um ambiente de produção, você precisará configurar o Redis e as variáveis de ambiente de acordo com seu provedor de hospedagem ou ambiente de implantação.
Criando o Service Object para Envio de E-mails
-
Crie um Service Object:
# app/services/email_sender_service.rb class EmailSenderService def initialize(user, message) @user = user @message = message end def call UserMailer.welcome_email(@user, @message).deliver_now end end
-
Crie um Mailer:
# app/mailers/user_mailer.rb class UserMailer < ApplicationMailer def welcome_email(user, message) @user = user @message = message mail(to: @user.email, subject: 'Welcome!') end end
Escrevendo Testes com RSpec
-
Configure o RSpec para testar o Sidekiq:
Adicione a seguinte configuração aospec/rails_helper.rb
:require 'sidekiq/testing' Sidekiq::Testing.fake!
-
Escreva o teste para o Service Object:
# spec/services/email_sender_service_spec.rb RSpec.describe EmailSenderService do let(:user) { create(:user) } let(:message) { 'Welcome to our service!' } it 'sends an email to the user' do expect { EmailSenderService.new(user, message).call }.to change { ActionMailer::Base.deliveries.count }.by(1) end end
A diferença entre usar
{}
(chaves) e()
(parênteses) noexpect
do RSpec está relacionada à maneira como o Ruby avalia blocos de código e argumentos de métodos. Vamos explorar isso detalhadamente, especialmente no contexto dochange
matcher do RSpec.
Uso de {}
e ()
no expect
-
Chaves
{}
: São usadas para passar um bloco de código. No RSpec, isso é comumente utilizado quando você quer avaliar o efeito de um bloco de código sobre algum estado ou objeto. Por exemplo, quando você quer testar se a execução de um método altera o valor de alguma variável ou o estado de um objeto. -
Parênteses
()
: São usados para passar argumentos para métodos. No contexto do RSpec, você os usaria para passar um valor ou objeto diretamente para oexpect
, sem a necessidade de avaliar o efeito de um bloco de código.
O change
Matcher
O change
matcher do RSpec é usado para verificar se um determinado bloco de código altera um valor específico. A sintaxe geral é:
expect { ... }.to change { ... }.by(...)
O primeiro par de chaves {}
após o expect
contém o bloco de código cujo efeito você quer testar. O segundo par de chaves {}
dentro do change
contém o valor que você espera que seja alterado.
Exemplo Detalhado
No seu exemplo:
expect {
EmailSenderService.new(user, message).call
}.to change { ActionMailer::Base.deliveries.count }.by(1)
-
expect { EmailSenderService.new(user, message).call }
: Aqui, você está passando um bloco de código que executa o métodocall
doEmailSenderService
. O RSpec vai avaliar o estado antes e depois da execução desse bloco. -
.to change { ActionMailer::Base.deliveries.count }
: Este é o estado que você espera que seja alterado pelo bloco de código. Neste caso, você está verificando a contagem de e-mails entregues peloActionMailer
. -
.by(1)
: Isso especifica como você espera que o estado mude. Neste caso, você espera que a contagem de e-mails entregues aumente em 1.
Por Que Usar Dessa Forma?
O uso de chaves {}
para passar blocos de código é crucial aqui porque permite ao RSpec avaliar o estado antes e depois da execução do bloco. Isso é fundamental para o change
matcher, pois ele precisa dessa comparação para determinar se houve a mudança esperada.
Em resumo, o uso de {}
para blocos de código no expect
e no change
permite que o RSpec avalie corretamente o efeito de um bloco de código sobre um estado específico, o que é essencial para testes que verificam mudanças de estado ou comportamento.
Criando um Job para o Sidekiq
-
Crie um Job:
# app/jobs/email_sender_job.rb class EmailSenderJob < ApplicationJob queue_as :default def perform(user, message) EmailSenderService.new(user, message).call end end
-
Teste o Job:
# spec/jobs/email_sender_job_spec.rb RSpec.describe EmailSenderJob do let(:user) { create(:user) } let(:message) { 'Welcome to our service!' } it 'enqueues the job' do expect { EmailSenderJob.perform_later(user, message) }.to have_enqueued_job end end
Você aprendeu as diferenças entre Sidekiq e Delayed Job, suas vantagens e desvantagens, e como implementar um sistema de envio de e-mails assíncrono usando Sidekiq e TDD em Ruby on Rails. O Sidekiq é uma excelente escolha para aplicações que exigem alta performance e confiabilidade em tarefas assíncronas.