Permalink
Browse files

Funky monkey goodness!!

  • Loading branch information...
0 parents commit 87ce1f90115df132d9a93b5ec3dc0982e8d96df5 @ssoroka committed May 29, 2009
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Steven Soroka
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,48 @@
+Scheduler Daemon
+================
+
+Rails 2.3.2 compatible scheduler daemon. Replaces cron/rake pattern of periodically running rake tasks
+to perform maintenance tasks in Rails apps. Scheduler Daemon is made specifically for your Rails app,
+and only loads the environment once, no matter how many tasks run.
+
+Get up and running with your own daemon in under 2 minutes!
+
+Setup
+=====
+
+1. Install the plugin
+
+ script/plugin install git://github.com/ssoroka/scheduler_daemon.git
+
+2. Install required gems
+
+ gem sources -a http://gems.github.com # if you haven't already...
+
+ sudo gem install daemons rufus-scheduler eventmachine
+
+3. Add the following line to your .gitignore (you have one, right?) since logs and pids get written there.
+
+ scheduler/log
+
+4. script/generate scheduler
+
+Usage
+=====
+
+5. generate a new scheduled task:
+
+ script/generate scheduler_task MyTaskName
+
+6. fire up the daemon in console mode to test it out
+
+ scheduler/bin/scheduler\_daemon run
+
+
+About
+=====
+
+Steven Soroka
+ [@ssoroka](http://twitter.com/ssoroka)
+ [My Github repo](http://github.com/ssoroka)
+ [My blog](http://blog.stevensoroka.ca)
+
@@ -0,0 +1,23 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the gamey plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the gamey plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'Gamey'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
@@ -0,0 +1,6 @@
+Description:
+ Creates the scheduler folder and basic scripts for it to run
+
+Example:
+ `./script/generate scheduler`
+
@@ -0,0 +1,18 @@
+class SchedulerGenerator < Rails::Generator::Base
+ def banner
+ "Usage: #{$0} #{spec.name}"
+ end
+
+ def manifest
+ record do |m|
+ m.directory File.join('scheduler', 'bin')
+ m.directory File.join('scheduler', 'lib', 'scheduled_tasks')
+ m.directory File.join('scheduler', 'log')
+
+ m.template 'bin/scheduler_daemon.rb', 'scheduler/bin/scheduler_daemon.rb'
+ m.template 'lib/scheduler.rb', 'scheduler/lib/scheduler.rb'
+
+ m.readme('README')
+ end
+ end
+end
@@ -0,0 +1,9 @@
+
+GREAT!
+
+Now that you've generated the scheduler daemon, try:
+
+ script/generate scheduler_task Example
+
+and lets take a look at an example task!
+
@@ -0,0 +1,24 @@
+#!/usr/bin/env ruby
+# USAGE:
+#
+# ruby scheduler/bin/scheduler_daemon.rb run -- start the daemon and stay on top
+# ruby scheduler/bin/scheduler_daemon.rb start -- start the daemon and stay on top
+# ruby scheduler/bin/scheduler_daemon.rb stop -- stop the daemon
+# ruby scheduler/bin/scheduler_daemon.rb restart -- stop the daemon and restart it afterwards
+
+require 'rubygems'
+require 'daemons'
+
+scheduler = File.join(File.dirname(__FILE__), %w(.. lib scheduler.rb))
+
+pid_dir = File.expand_path(File.join(File.dirname(__FILE__), %w(.. log)))
+
+app_options = {
+ :dir_mode => :normal,
+ :dir => pid_dir,
+ :multiple => false,
+ :backtrace => true,
+ :log_output => true
+}
+
+Daemons.run(scheduler, app_options)
@@ -0,0 +1,62 @@
+# load the environment, just once. yay!
+rails_root = File.expand_path(File.join(File.dirname(__FILE__), %w(.. ..)))
+
+Dir.chdir(rails_root) do
+ require File.join(rails_root, %w(config environment))
+ puts "Loaded #{Rails.env} environment"
+end
+
+require 'eventmachine'
+require 'rufus/scheduler'
+
+# hijack puts() to include a timestamp
+def puts(*args)
+ printf("[#{Time.zone.now.to_s}] ")
+ super(*args)
+end
+
+# load all custom tasks
+tasks = []
+Dir[File.join(File.dirname(__FILE__), %w(scheduled_tasks *.rb))].each{|f|
+ begin
+ require f
+ filename = f.split('/').last.split('.').first
+ puts "Loading task #{filename}..."
+ tasks << filename.camelcase.constantize # path/newsfeed_task.rb => NewsfeedTask
+ rescue
+ end
+}
+
+puts "Starting Scheduler at #{Time.now.to_s(:date_with_time)}"
+
+# tasks need to call ActiveRecord::Base.connection_pool.release_connection after running to
+# release the connection back to the connection pool, Rails wont handle it for us here.
+#
+# Note: AR's ActiveRecord::Base.connection_pool.with_connection(&block) seems broken in
+# that respect; it doesn't release the connection properly.
+EventMachine::run {
+ scheduler = Rufus::Scheduler::EmScheduler.start_new
+
+ # This is where the magic happens. tasks in scheduled_tasks/*.rb are loaded up.
+ tasks.each do |task|
+ task.add_to scheduler
+ end
+
+ def scheduler.handle_exception(job, exception)
+ puts "job #{job.job_id} caught exception '#{exception}'"
+ end
+}
+
+# # other examples:
+# scheduler.cron '0 22 * * 1-5' do
+# # every day of the week at 00:22
+# puts 'activate security system'
+# end
+#
+# scheduler.every '2d', :timeout => '40m' do
+# begin
+# run_backlog_cleaning()
+# rescue Rufus::Scheduler::TimeOutError => toe
+# # timeout occurred
+# end
+# end
@@ -0,0 +1,11 @@
+class SchedulerTaskGenerator < Rails::Generator::NamedBase
+ def manifest
+ record do |m|
+ m.directory File.join('scheduler', 'lib', 'scheduled_tasks')
+
+ m.template 'scheduled_tasks/example_task.rb', "scheduler/lib/scheduled_tasks/#{file_name}_task.rb", :assigns => { :class_name => class_name }
+
+ m.readme('README')
+ end
+ end
+end
@@ -0,0 +1,8 @@
+
+Awesome! Now that you've created a scheduler, you can test it out with:
+
+ ruby scheduler/bin/scheduler_daemon.rb run
+
+to run it in the background (a la system start-up):
+
+ ruby /path/to/rails/app/scheduler/bin/scheduler_daemon.rb start
@@ -0,0 +1,14 @@
+module <%= class_name %>Task
+ class <<self
+ def add_to(scheduler)
+ # see rufus-scheduler documentation for more information on what methods scheduler can handle
+ scheduler.every "10s" do
+ # Your code here, eg: User.send_due_invoices!
+ puts "I'm running every 10 seconds! #{Time.now.to_s(:db)}" # delete me, really. :D
+
+ # this is required to keep the tasks from eating all the free connections:
+ ActiveRecord::Base.connection_pool.release_connection
+ end
+ end
+ end
+end
@@ -0,0 +1 @@
+require File.join(File.dirname(__FILE__), 'lib', 'scheduler.rb')
@@ -0,0 +1 @@
+puts File.read(File.join(File.dirname(__FILE__), 'README.markdown'))
@@ -0,0 +1,2 @@
+# You probably want to look in generators/, most of the code is there.
+# In the future I may move some of it here; maybe.
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class DaemonTest < ActiveSupport::TestCase
+ test "" do
+ assert true
+ end
+end
@@ -0,0 +1,3 @@
+require 'rubygems'
+require 'active_support'
+require 'active_support/test_case'
@@ -0,0 +1 @@
+puts "Nooooooooo! but we were so good together!"

0 comments on commit 87ce1f9

Please sign in to comment.