Criando daemons em Ruby on Rails (com script para Gentoo)
ruby on rails+daemon gem+daemon plugin+capistrano+gentoo linux
Eu estava utilizando o RailsCron para envio de email em batch e segundo plano, porém tive muitos problemas com este plugin. Ele não reiniciava bem, era necessário reiniciá-lo manualmente toda vez que o servidor web fosse reiniciado. Isso era um grande problema!
Quando estava buscando uma solução, li que o RailsCron está depreciado e que no lugar poderíamos uilizar o Daemons Generator com o Daemons Gem.
Resolvi então aproveitar meu trabalho e disponibilizar um passo-a-passo de instalaçao e utilização do daemons generator.
Primeiro Passo: Instalação do gem e do plugin
[c]
sudo gem install daemons
cd /path/da/sua/aplicacao
./script/plugin install http://svn.kylemaxwell.com/rails_plugins/daemon_generator/trunk
mv vendor/plugins/trunk vendor/plugins/daemon_generator
[/c]
Segundo Passo: Criação de um daemon
Em meu caso utilizei um daemon para enviar e-mails pendente em série a cada minuto.
[c]
./script/generate daemon email_queue
[/c]
Rodando a linha de comando acima, serão criados os seguintes arquivos:
script/daemons – este arquivo é criado apenas no primeiro daemon, ele server para iniciar e parar todos os daemons do projeto.
lib/daemons/email_queue.rb – este arquivo que será o daemon em si.
lib/daemons/email_queue_ctl – este script serve para iniciar e parar este daemon especificamente.
config/daemons.yml – Este arquivo também será gerado apenas na primeiraz vez, ele contém algumas configurações do daemon generator.
Terceiro Passo: Programação do seu daemon
Você precisa editar o arquivo do seu daemon para colocar a programação desejada. No meu caso editei o lib/daemons/email_queue.rb e coloquei o seguinte conteúdo:
[ruby]
#!/usr/bin/env ruby
# You might want to change this
ENV["RAILS_ENV"] ||= “production”
require File.dirname(__FILE__) + “/../../config/environment”
$running = true;
Signal.trap(“TERM”) do
$running = false
end
while($running) do
ActiveRecord::Base.logger < < "#{Time.now} - DAEMON: Processing invite queue.\n"
QueueInvite.find(:all, :conditions => ['sent_at is ? and send_at < = ?',nil,Time.now.utc]).each { |e| e.deliver }
sleep 60
end
[/ruby]
As linhas que serão executadas pelo daemon ficam dentro do while($running).
Atenção: o daemon fica rodando direto em um loop infinito então cuidado com o que você coloca aí dentro!
No meu caso a primeira linha server para criar uma entrada no log dizendo a data e hora que a rotina foi executada a segunda linha é a rotina em si e a última é um sleep que fará com que a rotina só seja executada a cada minuto.
Não vou explicar o QueueInvite, por que já faz parte da minha aplicação, mas resumidamente a cada 60 segundos este daemon busca no banco de dados os convites pendentes e manda enviá-los pelo método deliver.
Quarto Passo: Atualização da receita do Capistrano (se aplicável)
Se você usa o capistrano para automatizar o processo de deploy de sua aplicação (e deveria usar!), é necessário alterar o arquivo de receita para ele inciar e parar nosso daemon a cada deploy.
Para tal, coloque o seguinte código no arquivo config/deploy.rb
[ruby]
desc “Stop daemons before deploying”
task :before_deploy do
run “#{current_path}/script/daemons stop”
end
desc “Start daemons after deploying”
task :after_deploy do
run “#{current_path}/script/daemons start”
end
[/ruby]
Atenção: Verifique antes se as tarefas before_deploy e after_deploy já existem no seu arquivo. Caso existam, copie apenas o conteúdo da terefa.
Quinto Passo: Criar um daemon do sistema operacional
A princípio tudo está funcionando, mas e quando reiniciarmos o servidor? Bem o daemon tem que voltar a rodar! Eu utilizo o Gentoo Linux e disponibilizei aqui o script que eu criei para cuidar deste problema.
script/gentoo_daemons
[c]
#!/sbin/runscript
# Gentoo users: add this script to ‘default’ run level.
# ==================================================
#
# rails_daemons This shell script takes care of starting and stopping
# the daemons plugin of one rails project.
#
# Copyright (c) by Rafael Lima (http://rafael.adm.br)
project_name=”Your project name”
project_path=”/path/of/your/project”
depend() {
need localmount cron
}
checkconfig() {
if [ ! -d ${project_path} ] ; then
eerror “The project directory does not exists! Please, check your configuration.”
fi
}
start() {
checkconfig || return 1
ebegin “Starting ${project_name} daemons”
${project_path}/script/daemons start
eend $?
}
stop () {
ebegin “Stopping ${project_name} daemons”
${project_path}/script/daemons stop
eend $?
}
[/c]
É isso pessoal, espero que este artigo seja útil para muita gente! Em caso de dúvidas sintam-se a vontade para deixar um comentário!
Abraços.








Caro Rafael,
Eu sou um dos administradores do site GentooBR.org, usuário/colaborador do Gentoo e também entusiasta de Ruby.
Estou entrando em contato pois gostaria de publicar, ou fazer referência ao seu artigo em nosso site mantendo os seus direitos.
Caso esteja de acordo, me envie um email indiox at gentoobr.org, confirmando.
Obrigado,
[ ]s
–
Claudio Pereira aka IndioX
GentooBR – http://gentoobr.org
mailto: indiox@gentoobr.org
———————————————
Gentoo Documentation Member
http://gdp.gentoo.org
Olá Claudio,
Fique a vontade para publicar ou fazer referência a este meu artigo.
Será um prazer tê-lo publicado em seu site.
Abraços
Muito bom! Esse seu artigo me ajudou muito, o quarto passo foi a resolucao dos meus problemas.
Muito Obrigada!
Muito bem explicado.