Sidekiq ou Delay jobs as vantagens e desvantagens e implementação no Ruby on Rails com TDD

Sidekiq ou Delay jobs as vantagens e desvantagens e implementação no Ruby on Rails com TDD
Photo by Christin Hume / Unsplash

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.png

Sidekiq

Vantagens:

  1. 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.
  2. Confiabilidade: Possui um sistema robusto de re-tentativas e um painel de controle para monitorar e gerenciar tarefas.
  3. Comunidade e Suporte: Tem uma comunidade ativa e uma ampla gama de documentação disponível.

Desvantagens:

  1. Complexidade: Pode ser mais complexo de configurar e gerenciar, especialmente em sistemas maiores.
  2. Dependência do Redis: Requer Redis, o que pode ser uma desvantagem se você não quiser adicionar outra tecnologia ao seu stack.

delayedjob.png

Delayed Job

Vantagens:

  1. Simplicidade: Mais simples de configurar e usar, especialmente para aplicações menores ou para equipes com menos experiência.
  2. Armazenamento Flexível: Pode usar o Active Record para armazenar tarefas, o que pode ser conveniente se você já estiver usando o Rails.

Desvantagens:

  1. Performance: Geralmente é mais lento que o Sidekiq, pois cria um novo processo para cada tarefa.
  2. 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

  1. Adicione o Sidekiq ao seu Gemfile:

    gem 'sidekiq'
    
  2. Configure o Sidekiq como o adaptador de fila:
    Em config/application.rb, adicione:

    config.active_job.queue_adapter = :sidekiq
    
  3. 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:

  1. 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 como apt ou brew. Por exemplo:

    brew install redis
    
  2. Inicie o Servidor Redis:
    Após a instalação, inicie o servidor Redis. Em um terminal, execute:

    redis-server
    
  3. Adicione o Sidekiq ao seu Gemfile:
    No seu projeto Rails, adicione o Sidekiq ao Gemfile:

    gem 'sidekiq'
    
  4. Instale as Gems:
    Execute bundle install para instalar as gems necessárias, incluindo o Sidekiq.

  5. 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 gem dotenv 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
      
  6. 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 em config/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
    
  7. Inicie o Sidekiq:
    Com o Redis em execução, você pode iniciar o Sidekiq. Em um terminal, execute:

    bundle exec sidekiq
    
  8. 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 seu routes.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

  1. 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
    
  2. 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

  1. Configure o RSpec para testar o Sidekiq:
    Adicione a seguinte configuração ao spec/rails_helper.rb:

    require 'sidekiq/testing'
    Sidekiq::Testing.fake!
    
  2. 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) no expect 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 do change matcher do RSpec.

Uso de {} e () no expect

  1. 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.

  2. 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 o expect, 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étodo call do EmailSenderService. 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 pelo ActionMailer.

  • .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

  1. 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
    
  2. 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.

Referências

Sidekiq
Delay Job

Read more