Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

19 May 10 Agendamento de tarefas muito fácil com com Ruby on Rails

Em um projeto pequeno, que precisava rodar em um desktop, eu precisei de um agendador de tarefas, o sistema precisava rodar em windows, linux ou mac, então utilizar o Cron para isto não era uma opção, e eu precisava de algo semelhante ao Cron, rodar algum código a cada X tempo não era o suficiente, ou pelo menos tornaria a minha vida muito mais difícil.

Eu também não queria ter que iniciar um processo separado da aplicação para cuidar disto pois eram tarefas simples, e depois de algumas pesquisas, encontrei o Rufus-Scheduler que resolve o problema que eu tinha, então resolvi escrever este post para que eu lembre dele caso precise novamente.

Sempre lembrando que aqui não serão mostrados todos do Rufus-Scheduler, apenas uma forma simples de usa-lo, se tiver dúvidas deixe um comentário que farei o melhor para esclarece-las.

Este exemplo vai começar com uma aplicação simples, um scaffold de uma entidade de nome SimpleTask com os seguintes parâmetros:

rails generate scaffold SampleTask name:string cron:string times:integer done:boolean job_id:string
rake db:migrate

A premissa para este exemplo é a seguinte:
Quando o sistema for iniciado as tarefas ainda não completas tem que ser agendadas novamente, e toda vez que eu criar uma tarefa nova esta tem que ser agendada automaticamente.

Então vamos a implementação com o Rufus-Scheduler.

  • Apagar o arquivo public/index.html
  • No arquivo routes.rb adicionar a linha ‘root :to => “sample_tasks#index”‘
  • No Gemfile adicionar a linha ‘gem “rufus-scheduler”‘
  • Criar um arquivo config/initializers/scheduler_initialization.rb com a seguinte linha: MySampleScheduler.update_schedules

No model criado adicionar o seguinte código:

class SampleTask < ActiveRecord::Base
	after_create :schedule_me
	after_destroy :unschedule_me
 
	def schedule_me
		MySampleScheduler.schedule read_attribute(:id)
	end
	def unschedule_me
		MySampleScheduler.unschedule read_attribute(:job_id)
	end
end

Criar o arquivo lib/my_sample_scheduler.rb com o seguinte conteúdo:

class MySampleScheduler
	@@scheduler = Rufus::Scheduler::PlainScheduler.start_new
	def self.update_schedules
		@@scheduler.in '1m' do #delay initialization because of problems acessing rails models during rails initialization
			jobs = @@scheduler.cron_jobs
			tasks = SampleTask.all
			tasks.each do |task|
				job = jobs[task.job_id] if task.job_id
				job.unschedule if job && (task.done || job.cron_line!=task.cron)
				if !task.done
					schedule(task)
				end
			end
		end
	end
	def self.unschedule(job_id)
		@@scheduler.unschedule(job_id)
	end
	def self.schedule(task_id)
		task = SampleTask.find task_id
		job = @@scheduler.cron task.cron do |j|
			task = SampleTask.find task_id
			if task
				puts "#{task.name} executing at #{Time.now} ---- #{task.times}"
				task.times = task.times - 1
				task.done = task.times==0
				task.save
				unschedule task.job_id if task.done
			else
				puts "Task deleted #{task_id}"
				unschedule j.job_id
			end
		end
		task.job_id = job.job_id
		task.save
	end
end

Rodar a aplicação e já deve ser possível cadastrar tarefas.
Quando a aplicação for finalizada e novamente inicializada, as tarefas pendentes terão um delay de 1 minuto para re-iniciarem, isto foi necessário porque se acessarmos os models diretamente durante a inicialização do rails, muitas coisas ruins podem acontecer.

Não se esqueça que para este exemplo funcionar você precisa ter o Rufus-Scheduler instalado. Se você seguiu todos os passos, um “bundle install” do diretório do projeto deve resolver o problema.

Se quiser o código da aplicação que eu escrevi, ele esta disponível neste endereço:http://github.com/urubatan/rails_schedule_samples

Se você já usa o GIT pode baixar o código com o comando: git clone git://github.com/urubatan/rails_schedule_samples.git

Você gostou deste post? Compartilhe:
Se você gostou deste post, talvez você queira assinar o feed RSS! Você também pode me seguir no Twitter.

Tags: , , , ,

Reader's Comments

  1. |

    Hehehe…

    Muito Facil ? Mais facil que o @Schedule do Java EE 6 não é…

    :)

    Não precisa de toda essa parafernalha… apenas um @Schedule em cima do metodo e PUFT… tudo pronto ;)