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.