Monitorando o Delayed Job com Bluepill e Capistrano

Então você já fez a feliz escolha de tratar seu processamento em background com Delayed Job, ótimo! Mas como ter certeza que esse processamento vai continuar acontecendo enquanto você estiver dormindo? E se o o processo do Delayed Job cair, você vai acordar de madrugada e levantá-lo na mão? Eu não faria isso, gosto do meu sono. Qual a solução então?

Não é nenhuma novidade para nós, rubyistas e railers, que existem soluções como o God para fazerem o trabalho de monitoramento de processos. No entanto, existem outras soluções, como o Bluepill. O Bluepill é uma ferramenta de monitoramento de processos assim como o God, mas diferente dele, não tem memory leak, segundo seus autores.

Bem, como não quero acordar de madrugada para levantar meu processo do Delayed Job na mão, e também não quero ficar restartando um processo do God por causa de memory leak, resolvi usar o Bluepill. Mas como uso o Bluepill para monitorar o Delayed Job?

Para configurar o Bluepill para monitorar o Delayed Job, e usar o Capistrano para automatizar algumas tarefas, temos basicamente 4 passos:

  1. Instalar e configurar o Delayed job
  2. Instalar e configurar o Bluepill
  3. Escrever a receita de capistrano para o Bluepill
  4. Setar algumas coisas do arquivo /etc/sudoers

Vamos dar uma olhada em detalhes em cada passo.

Instalação e configuração do Delayed Job

Instalar e configurar o Delayed Job é super simples, basta ler o README do projeto, que está bem claro. Recomendo também assistir ao RailsCast sobre o Delayed Job. Foi de lá que tirei a informação de usar o fork do Delayed Job da Collective Idea ao invés da versão do repositório original.

Instalação e configuração do Bluepill

Instalar o Bluepill também não tem muito segredo, basta você ler o README do projeto e seguir os passos que estão descritos lá.

Na parte da configuração, você pode ver as opções também no README do projeto. No meu caso, esse arquivo está em RAILS_ROOT/config/production.pill.

Bluepill.application("my_app") do |app|
  app.process("delayed_job") do |process|
    process.working_dir = "/home/deploy/my_app/current"

    process.start_grace_time    = 10.seconds
    process.stop_grace_time     = 10.seconds
    process.restart_grace_time  = 10.seconds

    process.start_command = "ruby script/delayed_job -e production start"
    process.stop_command  = "ruby script/delayed_job -e production stop"

    process.pid_file = "/home/deploy/my_app/shared/pids/delayed_job.pid"
    process.uid = "deploy"
    process.gid = "deploy"
  end
end

No entanto, eu tive um pequeno problema com a interação do Bluepill e o Delayed Job. Ao passar a flag -e production para o Delayed Job, ele não a estava interpretando direito. Você pode ver mais detalhes sobre isso numa issue que abri no repo do Delayed Job.

A primeira solução que pensei, foi usar RAILS_ENV=production ruby script/delayed_job start, no entanto por algum motivo que ainda desconheço, isso não funcionou.

A solução que cheguei então para resolver esse problema, foi modificar o arquivo que está em RAILS_ROOT/script/delayed_job para o seguinte:

#!/usr/bin/env ruby

# TODO improve the line of code below
# The line below is just a hack while we wait the delayed job guys answer the following issue
# http://github.com/collectiveidea/delayed_job/issues#issue/38
ENV['RAILS_ENV'] ||= "production"
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require 'delayed/command'
Delayed::Command.new(ARGV).daemonize

Como a flag -e production não estava sendo interpretada direito no Delayed Job, estou setando na mão o RAILS_ENV para production (linha 6), portanto estou supondo que você só está usando o Bluepill para monitorar processos do Delayed Job em environment igual a production.

Receita do Capistrano para o Bluepill

Para automatizar as tarefas de ligar e desligar o Bluepill, escrevi a seguinte receita de capistrano:

# deploy credentials
set :user, "deploy"
set :deploy_to, "/home/deploy/#{application}"
set :use_sudo, false
set :rails_env, "production"

# Bluepill related tasks
after "deploy:update", "bluepill:quit", "bluepill:start"
namespace :bluepill do
  desc "Stop processes that bluepill is monitoring and quit bluepill"
  task :quit, :roles => [:app] do
    sudo "bluepill stop"
    sudo "bluepill quit"
  end

  desc "Load bluepill configuration and start it"
  task :start, :roles =>[:app] do
    sudo "bluepill load /home/deploy/my_app/current/config/production.pill"
  end

  desc "Prints bluepills monitored processes statuses"
  task :status, :roles => [:app] do
    sudo "bluepill status"
  end
end

Note que ao invés de usar o método run do capistrano, estou usando o método sudo. Isso porque o comando bluepill deve ser rodado como root. Isso nos leva para o próximo tópico.

/etc/sudoers

Já que eu preciso rodar o comando bluepill como root, vou ter que mudar o meu set :user, "deploy" para set :user, "root"? Acho melhor não, não gostamos de dar acesso root para qualquer coisa, mesmo para deployment. Então, como fazer? Simples, basta editar seu arquivo de sudoers.

Para isso, você precisa usar o comando visudo para abrir e editar o arquivo /etc/sudoers. Uma vez com o arquivo aberto, adicione a seguinte linha no final do arquivo:

deploy ALL=(ALL) NOPASSWD: /usr/local/bin/bluepill

Pronto, agora o usuário deploy já pode fazer sudo bluepill sem precisar de senha. Problema resolvido sem colocar a segurança da sua máquina em risco. ;)

Depois de ter feito esses 4 passos, você está pronto para dormir a noite sem se preocupar com seu processo do Delayed Job. E quando quando quiser saber como está o status dos seus processos monitorados, basta usar a seguinte task do capistrano na sua máquina local:

cap bluepill:status

E você? Quais soluções você usa para dormir em paz?

Update: Se você está tendo problemas em restartar o Bluepill com o capistrano, dê uma olhada aqui.

Comments are closed.