Browse files

Massive changes for 1.0. Scheduler no longer runs as part of the rail…

…s app, now part of the scheduler daemon gem.

Also scheduled tasks folder has moved to RAILS_ROOT/lib/scheduled_tasks/
  • Loading branch information...
1 parent 600d233 commit 4d7d94ec5a2adf48f2c3507ac5263b33724cb4f3 @ssoroka committed Oct 29, 2009
View
10 CHANGES
@@ -1,10 +0,0 @@
-Version 0.3.0
-
-add a default task to delete old AR sessions
-
-Version 0.2.0
-
-- syntax to load up only selected tasks for testing, by partial name:
-
- ruby daemons/bin/task_runner.rb run -- --only=toadcamp,newsfeed
-
View
82 README.markdown
@@ -1,7 +1,7 @@
Scheduler Daemon
================
-Rails 2.3.2 compatible scheduler daemon. Replaces cron/rake pattern of periodically running rake tasks
+Rails 2.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.
@@ -10,30 +10,39 @@ What's so great about it? Well, I'm glad you asked!
- Only loads your Rails environment once on daemon start, not every time a task is run
- Allows you to easily deploy the scheduled tasks with your Rails app instead of depending on an
administrator to update crontab
+- Can be installed as a gem or a plugin (I suggest gem)
- It doesn't use rake or cron!
- Gets you up and running with your own daemon in under 2 minutes
+- Specially designed to work with your rails app!
Setup
=====
-Install the plugin
+Install as a gem or plugin.
- script/plugin install git://github.com/ssoroka/scheduler_daemon.git
+As a gem, the old-fashioned way:
-Install required gems
+ gem install scheduler_daemon -s http://gemcutter.org
- gem sources -a http://gems.github.com # if you haven't already...
+As a gem with bundler, add to your ./Gemfile:
- sudo gem install daemons rufus-scheduler eventmachine chronic
+ source "http://gemcutter.org"
+ gem 'scheduler_daemon', :only => :bundle
-You'll need the chronic gem if you want to be able to use english time descriptions in your scheduled tasks, like:
+As a plugin: (might be awkward to call the binary to start up the daemon...)
- every '3h', :first_at => Chronic.parse('midnight')
+ script/plugin install git://github.com/ssoroka/scheduler_daemon.git
+ # Install required gems
+ gem install daemons rufus-scheduler eventmachine chronic -s http://gemcutter.org
-generate the scheduler daemon files in your rails app:
+Optionally generate the default scheduler daemon task for your rails app:
script/generate scheduler
+which will create an excellent example task named:
+
+ lib/scheduled_tasks/session_cleaner_task.rb
+
Usage
=====
@@ -45,36 +54,63 @@ generate a new scheduled task:
Tasks support their own special DSL; commands are:
environments :production, :staging # run only in environments listed. (:all by default)
- every '1d' # run once a day
- every '1d', :first_at => Chronic.parse("2 am") # run once a day, starting at 2 am
- at Cronic.parse('5 pm') # run once at 5 pm, today (today would be relative to scheduler start/restart)
- cron '* 4 * * *' # cron style (the example is run at 4 am, I do believe)
+ every '1d' # run every day
+ every '1d', :first_at => Chronic.parse("2 am") # run every day, starting at 2 am (see caveat below)
+ at Cronic.parse('5 pm') # run *once* at 5 pm today
+ # (relative to scheduler start/restart time )
+ # (happens every time scheduler starts/restarts)
+ # (see caveat below )
+ cron '* 4 * * *' # cron style (run every 4 am)
in '30s' # run once, 30 seconds from scheduler start/restart
fire up the daemon in console mode to test it out
- ruby scheduler/bin/scheduler_daemon.rb run
+ scheduler_daemon run
-When you're done, get your system admin (or switch hats) to add the daemon to the system start-up, and
+For production environments, add the daemon to the system start-up, and
capistrano deploy scripts, etc. Something like:
- RAILS_ENV=production ruby scheduler/bin/scheduler_daemon.rb start
+ RAILS_ENV=production scheduler_daemon start
-Run individual tasks like so:
+Selectively run tasks like so:
- ruby daemons/bin/task_runner.rb run -- --only=task_name1,task_name2
+ scheduler_daemon start -- --only=task_name1,task_name2 --except=not_me
Specs
=====
-There are some default specs supplied, you are encouraged to write more specs for your tasks as you create them. Use the existing spec as a template.
-
-See spec/README for more information
+See the spec for session cleaner for an idea on how to write specs for your tasks
To Do
=====
-- dynamically add and remove tasks while daemon is running (? anyone want this?) Perhaps a web interface?
+Looking for suggestions!
+
+Send requests to ssoroka78@gmail.com or on twitter, @ssoroka
+
+Bugs
+====
+
+Submit bugs here http://github.com/ssoroka/scheduler_daemon/issues
+
+I'd especially like to hear about success/failures with Rails versions outside of 2.2.x to 2.3.x
+
+Caveats
+=======
+
+When using the cronic gem to parse dates, be careful of how it interprets your date,
+for example:
+
+ every '24h', :first_at => Chronic.parse('noon')
+
+will be once a day at noon, but the first time the server starts up (or restarts), noon
+is relative to the current time of day. Before lunch, and it's in the future. If the
+daemon starts up after lunch, the date is in the past, *and the task is immediately run*
+because it thinks it missed its last execution time. Depending on what your task is,
+this may or may not be a problem. If you always want the date to resolve in the future
+with terms like "noon", "3 am" and "midnight", prepend "next" to it. ie:
+
+ every '24h', :first_at => Chronic.parse('next noon')
Author
======
@@ -88,4 +124,4 @@ Steven Soroka
Thanks
======
-Special thanks to [Goldstar](http://www.goldstar.com) for sponsoring the plugin and promoting open-sourcesness.
+Special thanks to [Goldstar](http://www.goldstar.com) for promoting open-source in the workplace.
View
6 Rakefile
@@ -24,6 +24,12 @@ begin
gem.add_dependency('daemons', '>= 1.0.10')
gem.add_dependency('rufus-scheduler', '>= 2.0.1')
gem.add_dependency('chronic', '>= 0.2.0')
+
+ gem.default_executable('bin/scheduler_daemon')
+
+ everything_from_dirs = %w(bin generators lib spec)
+ gem.files = everything_from_dirs.map{|d| Dir["#{d}/**/*"] }.flatten
+ gem.files += Dir['*'] - (everything_from_dirs + ['pkg'])
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
end
View
51 bin/scheduler_daemon
@@ -0,0 +1,51 @@
+#!/usr/bin/env ruby
+# This file launches the scheduler as a daemon.
+# USAGE:
+#
+# scheduler_daemon run # start the daemon and stay on top
+# scheduler_daemon start # start the daemon and stay on top
+# scheduler_daemon stop # stop all instances of the application
+# scheduler_daemon restart # stop all instances and restart them afterwards
+#
+# options can be passed to the scheduler like so:
+#
+# scheduler_daemon start -- --except=session_cleaner
+#
+# options can be passed to the daemon:
+#
+# scheduler_daemon start --dir=/my/rails/root/
+#
+# see README for more info
+require 'rubygems'
+require 'daemons'
+require File.expand_path(File.join(File.dirname(__FILE__), %w(.. lib loader find_rails_root)))
+
+def launch_args(options = {})
+ params = options.map{|k,v| "--#{k}=#{v}"}
+ if params.empty?
+ ARGV
+ else
+ args = ARGV.dup
+ args << '--' unless args.include?('--')
+ args + params
+ end
+end
+
+rails_root = FindRailsRoot.locate
+pid_dir = File.expand_path(File.join(rails_root, 'log'))
+scheduler = File.join(File.dirname(__FILE__), %w(.. lib loader scheduler_loader.rb))
+
+raise "#{pid_dir} does not exist" unless File.exist?(pid_dir)
+
+app_options = {
+ :app_name => 'scheduler_daemon',
+ :ARGV => launch_args(:dir => rails_root),
+ :dir_mode => :normal,
+ :dir => pid_dir,
+ :multiple => false,
+ :backtrace => true,
+ :log_output => true,
+ :monitor => true
+}
+
+Daemons.run(scheduler, app_options)
View
15 generators/scheduler/scheduler_generator.rb
@@ -5,19 +5,10 @@ def banner
def manifest
record do |m|
- m.directory File.join('scheduler', 'bin')
- m.directory File.join('scheduler', 'lib', 'scheduled_tasks')
- m.directory File.join('scheduler', 'lib', 'scheduler')
+ m.directory File.join('lib', 'scheduled_tasks')
- m.template 'bin/scheduler_daemon.rb', 'scheduler/bin/scheduler_daemon.rb'
- m.template 'bin/boot.rb', 'scheduler/bin/boot.rb'
-
- m.template 'lib/scheduler.rb', 'scheduler/lib/scheduler.rb'
- m.template 'lib/scheduler/scheduler_task.rb', 'scheduler/lib/scheduler/scheduler_task.rb'
- m.template 'lib/scheduler/hijack_puts.rb', 'scheduler/lib/scheduler/hijack_puts.rb'
- m.template 'lib/scheduler/exception_handler.rb', 'scheduler/lib/scheduler/exception_handler.rb'
-
- m.template 'lib/scheduled_tasks/session_cleaner_task.rb', 'scheduler/lib/scheduled_tasks/session_cleaner_task.rb'
+ m.template 'lib/scheduled_tasks/session_cleaner_task.rb',
+ 'lib/scheduled_tasks/session_cleaner_task.rb'
m.readme('README')
end
View
9 generators/scheduler/templates/README
@@ -1,8 +1,11 @@
GREAT!
-Now that you've generated the scheduler daemon, try:
+Now that you've generated the scheduler daemon and a default task,
+you can take a look at the new task:
- script/generate scheduler_task Example
+ lib/scheduled_tasks/session_cleaner_task.rb
-and lets take a look at an example task!
+or make your own:
+
+ script/generate scheduler_task MyTaskName
View
10 generators/scheduler/templates/bin/boot.rb
@@ -1,10 +0,0 @@
-# load the environment, just once. yay!
-rails_root = File.expand_path(File.join(File.dirname(__FILE__), %w(.. ..)))
-daemons_lib_dir = File.expand_path(File.join(File.dirname(__FILE__), %w(.. lib)))
-
-Dir.chdir(rails_root)
-
-require 'config/environment'
-require File.join(daemons_lib_dir, 'scheduler')
-
-Scheduler::Base.new(ARGV)
View
25 generators/scheduler/templates/bin/scheduler_daemon.rb
@@ -1,25 +0,0 @@
-#!/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'
-
-boot_scheduler = File.join(File.dirname(__FILE__), 'boot.rb')
-pid_dir = File.expand_path(File.join(File.dirname(__FILE__), %w(.. .. log)))
-
-FileUtils.mkdir_p(pid_dir) unless File.exist?(pid_dir)
-
-app_options = {
- :dir_mode => :normal,
- :dir => pid_dir,
- :multiple => false,
- :backtrace => true,
- :log_output => true
-}
-
-Daemons.run(boot_scheduler, app_options)
View
18 generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb
@@ -1,20 +1,28 @@
class SessionCleanerTask < Scheduler::SchedulerTask
environments :all
- every '1d', :first_at => Chronic.parse('2 am')
+ every '1d', :first_at => Chronic.parse('next 2 am')
def run
- puts "running the session cleaner"
remove_old_sessions
- puts "old sessions are gone!"
end
def remove_old_sessions
- if ActionController::Base.session_store == ActiveRecord::SessionStore
+ log "running the session cleaner"
+ if ActionController::Base.session_store == session_store_class
ActiveRecord::Base.connection.execute("DELETE FROM #{session_table_name} WHERE updated_at < '#{7.days.ago.to_s(:db)}'")
+ log "old sessions are gone!"
+ else
+ log "sessions are not stored in the database; nothing to do."
end
end
-
+
+ def session_store_class
+ return ActiveRecord::SessionStore if defined?(ActiveRecord::SessionStore)
+ # pre rails 2.3 support...
+ return CGI::Session::ActiveRecordStore if defined?(CGI::Session::ActiveRecordStore)
+ end
+
def session_table_name
ActiveRecord::Base.pluralize_table_names ? :sessions : :session
end
View
90 generators/scheduler/templates/lib/scheduler.rb
@@ -1,90 +0,0 @@
-require 'eventmachine'
-require 'rufus/scheduler'
-require File.join(File.dirname(__FILE__), 'scheduler', 'hijack_puts')
-require File.join(File.dirname(__FILE__), 'scheduler', 'scheduler_task')
-require File.join(File.dirname(__FILE__), 'scheduler', 'exception_handler')
-
-module Scheduler
- class Base
- attr_reader :load_only, :load_except, :tasks
-
- def initialize(*command_line_args)
- @load_only = []
- @load_except = []
- @tasks = []
- @rufus_scheduler = nil
-
- decide_what_to_run(command_line_args)
- load_tasks
- run_scheduler
- end
-
- def run_scheduler
- puts "Starting Scheduler in #{RAILS_ENV}"
-
- EventMachine::run {
- @rufus_scheduler = Rufus::Scheduler::EmScheduler.start_new
-
- def @rufus_scheduler.handle_exception(job, exception)
- msg = "[#{RAILS_ENV}] scheduler job #{job.job_id} (#{job.tags * ' '}) caught exception #{exception.inspect}"
- puts msg
- puts exception.backtrace.join("\n")
- Scheduler::ExceptionHandler.handle_exception(exception, job, message)
- end
-
- # This is where the magic happens. tasks in scheduled_tasks/*.rb are loaded up.
- tasks.each do |task|
- if task.should_run_in_current_environment?
- task.add_to(@rufus_scheduler)
- else
- puts "#{task} configured not to run in #{RAILS_ENV} environment; skipping."
- end
- end
- }
- end
-
- def load_tasks
- tasks_to_run.each{|f|
- begin
- unless load_only.any? && load_only.all?{|m| f !~ Regexp.new(Regexp.escape(m)) }
- require f
- filename = f.split('/').last.split('.').first
- puts "Loading task #{filename}..."
- tasks << filename.camelcase.constantize # path/newsfeed_task.rb => NewsfeedTask
- end
- rescue Exception => e
- msg = "Error loading task #{filename}: #{e.class.name}: #{e.message}"
- puts msg
- puts e.backtrace.join("\n")
- Railsbot.say "#{msg}, see log for backtrace" if Rails.env.production? || Rails.env.staging?
- end
- }
- end
-
- def tasks_to_run
- task_files = Dir[File.join(File.dirname(__FILE__), %w(scheduled_tasks *.rb))]
-
- if load_only.any?
- task_files.reject!{|f| load_only.all?{|m| f !~ Regexp.new(Regexp.escape(m))}}
- end
-
- if load_except.any?
- task_files.reject!{|f| load_except.any?{|m| f =~ Regexp.new(Regexp.escape(m))}}
- end
- task_files
- end
-
- # takes input from command line to later modify list of tasks to run
- def decide_what_to_run(command_line_args)
- # allow ruby daemons/bin/task_runner.rb run -- --only=toadcamp,newsfeed
- if only_arg = command_line_args.detect{|arg| arg =~ /^--only/}
- @load_only = only_arg.split('=').last.split(',')
- end
-
- # allow ruby daemons/bin/task_runner.rb run -- --except=toadcamp
- if except_arg = command_line_args.detect{|arg| arg =~ /^--except/}
- @load_except = except_arg.split('=').last.split(',')
- end
- end
- end
-end
View
12 generators/scheduler/templates/lib/scheduler/exception_handler.rb
@@ -1,12 +0,0 @@
-module Scheduler
- class ExceptionHandler
- # Change me to do something meaningful
- def self.handle_exception(exception, job, message)
- # If your team all hangs out in Campfire, you might want to make a
- # Campfire class that makes use of the tinder gem to write these errors there.
- #
- # eg:
- # Campfire.say "#{msg}, see log for backtrace" if Rails.env.production? || Rails.env.staging?
- end
- end
-end
View
8 generators/scheduler/templates/lib/scheduler/hijack_puts.rb
@@ -1,8 +0,0 @@
-# hijack puts to log with a timestamp, since any output is going to be logged anyway.
-module Kernel
- def puts_with_timestamp(*args)
- time = Time.respond_to?(:zone) ? Time.zone.now.to_s : Time.now.to_s
- puts_without_timestamp(%([#{time}] #{args.join("\n")}))
- end
- alias_method_chain :puts, :timestamp
-end
View
4 generators/scheduler_task/scheduler_task_generator.rb
@@ -1,9 +1,9 @@
class SchedulerTaskGenerator < Rails::Generator::NamedBase
def manifest
record do |m|
- m.directory File.join('scheduler', 'lib', 'scheduled_tasks')
+ m.directory File.join('lib', 'scheduled_tasks')
- m.template 'scheduled_tasks/example_task.rb', "scheduler/lib/scheduled_tasks/#{file_name}_task.rb", :assigns => { :class_name => class_name }
+ m.template 'scheduled_tasks/example_task.rb', "lib/scheduled_tasks/#{file_name}_task.rb", :assigns => { :class_name => class_name }
m.readme('README')
end
View
2 generators/scheduler_task/templates/scheduled_tasks/example_task.rb
@@ -5,6 +5,6 @@ class <%= class_name %>Task < Scheduler::SchedulerTask
def run
# Your code here, eg: User.send_due_invoices!
- # use puts for writing to log, eg: puts "I've sent invoices!"
+ # use log() for writing to scheduler daemon log, eg: log("I've sent invoices!")
end
end
View
27 lib/loader/find_rails_root.rb
@@ -0,0 +1,27 @@
+class FindRailsRoot
+ class << self
+ def locate
+ dir_arg = ARGV.detect{|arg| arg =~ /^#{Regexp.escape("--dir=")}/ }
+ return dir_arg.split('=').last if dir_arg
+ return RAILS_ROOT if defined?(RAILS_ROOT)
+ return Dir.pwd if current_dir_is_a_rails_project?
+ missing_rails_root
+ end
+
+ def missing_rails_root
+ msg = %(
+ Couldn't find rails project. Looked in:
+ 1. environment variable RAILS_ROOT
+ 2. --dir=/my/rails/root parameter
+ 3. current directory (#{Dir.pwd})
+ Don't know where to look for tasks.
+ )
+ raise msg
+ end
+
+ def current_dir_is_a_rails_project?
+ expected_dirs = %w(app vendor script config public)
+ expected_dirs.all?{|dir| Dir[dir].any? }
+ end
+ end
+end
View
15 lib/loader/scheduler_loader.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+# This file loads the rails environment and starts the scheduler.
+# do not use it directly unless you don't intend for the scheduler to run as a daemon.
+require File.join(File.dirname(__FILE__), 'find_rails_root')
+
+rails_root = FindRailsRoot.locate
+daemons_lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+# puts %(Changing to directory "#{rails_root}" and loading environment...)
+Dir.chdir(rails_root)
+
+require 'config/environment'
+require File.join(daemons_lib_dir, 'scheduler')
+
+Scheduler::Base.new(rails_root, ARGV)
View
114 lib/scheduler.rb
@@ -1,2 +1,112 @@
-# You probably want to look in generators/, most of the code is there.
-# In the future I may move some of it here; maybe.
+require 'eventmachine'
+require 'rufus/scheduler'
+require File.join(File.dirname(__FILE__), 'scheduler', 'scheduler_task')
+require File.join(File.dirname(__FILE__), 'scheduler', 'exception_handler')
+
+module Scheduler
+ class Base
+ attr_reader :load_only, :load_except, :tasks
+
+ def initialize(rails_root, *command_line_args)
+ @rails_root = rails_root
+ @load_only = []
+ @load_except = []
+ @tasks = []
+ @rufus_scheduler = nil
+
+ unless command_line_args.flatten.first == '--do-nothing'
+ decide_what_to_run(command_line_args.flatten)
+ load_tasks
+ run_scheduler
+ end
+ end
+
+ def time
+ if Time.respond_to?(:zone) && Time.zone
+ self.class.send(:define_method, :time) { Time.zone.now.to_s }
+ else
+ self.class.send(:define_method, :time) { Time.now.to_s }
+ end
+ time
+ end
+
+ def log(*args)
+ Kernel::puts(%([#{time}] #{args.join("\n")}))
+ end
+ alias :puts :log
+
+ def run_scheduler
+ puts "Starting Scheduler in #{RAILS_ENV}"
+
+ $daemon_scheduler = self
+
+ EventMachine::run {
+ @rufus_scheduler = Rufus::Scheduler::EmScheduler.start_new
+
+ def @rufus_scheduler.handle_exception(job, exception)
+ msg = "[#{RAILS_ENV}] scheduler job #{job.job_id} (#{job.tags * ' '}) caught exception #{exception.inspect}"
+ puts msg
+ puts exception.backtrace.join("\n")
+ Scheduler::ExceptionHandler.handle_exception(exception, job, message)
+ end
+
+ def @rufus_scheduler.daemon_scheduler
+ $daemon_scheduler
+ end
+
+ # This is where the magic happens. tasks in scheduled_tasks/*.rb are loaded up.
+ tasks.each do |task|
+ if task.should_run_in_current_environment?
+ task.add_to(@rufus_scheduler)
+ else
+ puts "#{task} configured not to run in #{RAILS_ENV} environment; skipping."
+ end
+ end
+ }
+ end
+
+ def load_tasks
+ tasks_to_run.each{|f|
+ begin
+ unless load_only.any? && load_only.all?{|m| f !~ Regexp.new(Regexp.escape(m)) }
+ require f
+ filename = f.split('/').last.split('.').first
+ puts "Loading task #{filename}..."
+ tasks << filename.camelcase.constantize # path/newsfeed_task.rb => NewsfeedTask
+ end
+ rescue Exception => e
+ msg = "Error loading task #{filename}: #{e.class.name}: #{e.message}"
+ puts msg
+ puts e.backtrace.join("\n")
+ Railsbot.say "#{msg}, see log for backtrace" if Rails.env.production? || Rails.env.staging?
+ end
+ }
+ end
+
+ def tasks_to_run
+ task_files = Dir[File.join(%w(lib scheduled_tasks *.rb))]
+
+ if load_only.any?
+ task_files.reject!{|f| load_only.all?{|m| f !~ Regexp.new(Regexp.escape(m))}}
+ end
+
+ if load_except.any?
+ task_files.reject!{|f| load_except.any?{|m| f =~ Regexp.new(Regexp.escape(m))}}
+ end
+ task_files
+ end
+
+ # takes input from command line to later modify list of tasks to run
+ def decide_what_to_run(command_line_args)
+ # allow ruby daemons/bin/task_runner.rb run -- --only=toadcamp,newsfeed
+ if only_arg = command_line_args.detect{|arg| arg =~ /^--only/}
+ @load_only = only_arg.split('=').last.split(',')
+ end
+
+ # allow ruby daemons/bin/task_runner.rb run -- --except=toadcamp
+ if except_arg = command_line_args.detect{|arg| arg =~ /^--except/}
+ @load_except = except_arg.split('=').last.split(',')
+ end
+ end
+ end
+end
View
30 lib/scheduler/exception_handler.rb
@@ -0,0 +1,30 @@
+# override this in your app to do something meaningful,
+# like post to campfire or hoptoad.
+#
+# Example campfire code below, using 'tinder' gem:
+module Scheduler
+ class ExceptionHandler
+ # @@campfire_subdomain = ''
+ # @@campfire_username = ''
+ # @@campfire_password = ''
+ # @@campfire_room_name = ''
+ # @@campfire_room = nil
+
+ def self.handle_exception(exception, job, message)
+ # If your team all hangs out in Campfire, you might want to try
+ # something like Tinder here to write these messages out to campfire,
+ # Such as:
+ #
+ # if Rails.env.production? || Rails.env.staging?
+ # msg = "#{message}, see log for backtrace"
+ #
+ # unless @@campfire_room
+ # campfire = Tinder::Campfire.new(@@campfire_subdomain, :ssl => true)
+ # campfire.login(@@campfire_username, @@campfire_password)
+ # @@campfire_room = campfire.find_room_by_name(@@campfire_room_name)
+ # end
+ # @@campfire_room.speak(msg)
+ # end
+ end
+ end
+end
View
14 ...templates/lib/scheduler/scheduler_task.rb → lib/scheduler/scheduler_task.rb
@@ -1,5 +1,6 @@
module Scheduler
class SchedulerTask
+ attr_accessor :daemon_scheduler, :rufus_scheduler
class <<self
def add_to(schedule)
%w(every in at cron).each{|time|
@@ -12,7 +13,10 @@ def add_to(schedule)
schedule.send(time, *args) do
begin
- new.run
+ a_task = new
+ a_task.daemon_scheduler = schedule.daemon_scheduler
+ a_task.rufus_scheduler = schedule
+ a_task.run
ensure
# Note: AR's ActiveRecord::Base.connection_pool.with_connection(&block) seems broken;
# it doesn't release the connection properly.
@@ -64,6 +68,12 @@ def should_run_in_current_environment?
def run
nil
end
+
+ def log(*args)
+ daemon_scheduler.log(*args)
+ end
+ alias :puts :log
end
end
-SchedulerTask = Scheduler::SchedulerTask # alias this for backwards compatability
+# alias this for backwards compatability
+SchedulerTask = Scheduler::SchedulerTask unless defined?(::SchedulerTask)
View
30 scheduler_daemon.gemspec
@@ -1,48 +1,56 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE
+# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{scheduler_daemon}
- s.version = "0.4.1"
+ s.version = "1.0.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Steven Soroka"]
- s.date = %q{2009-09-10}
+ s.date = %q{2009-10-29}
+ s.default_executable = %q{scheduler_daemon}
s.email = %q{ssoroka78@gmail.com}
+ s.executables = ["scheduler_daemon"]
s.extra_rdoc_files = [
"README.markdown"
]
s.files = [
- ".gitignore",
- "CHANGES",
- "MIT-LICENSE",
+ "MIT-LICENSE",
"README.markdown",
"Rakefile",
"VERSION",
+ "bin/scheduler_daemon",
"generators/scheduler/USAGE",
"generators/scheduler/scheduler_generator.rb",
"generators/scheduler/templates/README",
- "generators/scheduler/templates/bin/scheduler_daemon.rb",
"generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb",
- "generators/scheduler/templates/lib/scheduler.rb",
- "generators/scheduler/templates/lib/scheduler_task.rb",
"generators/scheduler_task/scheduler_task_generator.rb",
"generators/scheduler_task/templates/README",
"generators/scheduler_task/templates/scheduled_tasks/example_task.rb",
"init.rb",
"install.rb",
+ "lib/loader/find_rails_root.rb",
+ "lib/loader/scheduler_loader.rb",
"lib/scheduler.rb",
+ "lib/scheduler/exception_handler.rb",
+ "lib/scheduler/scheduler_task.rb",
"scheduler_daemon.gemspec",
- "spec/daemon_spec.rb",
+ "spec/README",
+ "spec/scheduled_tasks/session_cleaner_task_spec.rb",
+ "spec/scheduler_spec.rb",
"spec/spec_helper.rb",
"uninstall.rb"
]
s.homepage = %q{http://github.com/ssoroka/scheduler_daemon}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
- s.rubygems_version = %q{1.3.3}
+ s.rubygems_version = %q{1.3.5}
s.summary = %q{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. What's so great about it? Well, I'm glad you asked! - Only loads your Rails environment once on daemon start, not every time a task is run - Allows you to easily deploy the scheduled tasks with your Rails app instead of depending on an administrator to update crontab - It doesn't use rake or cron! - Gets you up and running with your own daemon in under 2 minutes}
s.test_files = [
- "spec/daemon_spec.rb",
+ "spec/scheduled_tasks/session_cleaner_task_spec.rb",
+ "spec/scheduler_spec.rb",
"spec/spec_helper.rb"
]
View
1 spec/README
@@ -1 +0,0 @@
-To install the specs for the scheduler daemon, copy this "spec" folder to one called "scheduler_daemon" in your project's spec folder.
View
12 spec/scheduled_tasks/session_cleaner_task_spec.rb
@@ -1,14 +1,14 @@
# copy this spec to your project after installing the plugin if you want to run the specs.
# suggested file name for this file: spec/scheduler_daemon/scheduled_tasks/session_cleaner_task_spec.rb
-require File.dirname(__FILE__) + '/../../spec_helper'
-require 'daemons/lib/scheduler_task'
-require 'daemons/lib/scheduled_tasks/remove_old_sessions_task'
+require File.join(File.dirname(__FILE__), %w(.. spec_helper))
+require 'scheduler/scheduler_task'
+require File.join(File.dirname(__FILE__), %w(.. .. generators scheduler templates lib scheduled_tasks session_cleaner_task))
-describe RemoveOldSessionsTask do
+describe SessionCleanerTask do
before(:each) do
- @task = RemoveOldSessionsTask.new
- @task.stub!(:puts)
+ @task = SessionCleanerTask.new
+ @task.stub!(:log)
end
it "should remove old sessions" do
View
26 spec/scheduler_spec.rb
@@ -1,10 +1,30 @@
-require File.dirname(__FILE__) + '/../spec_helper'
+require File.dirname(__FILE__) + '/spec_helper'
+require 'scheduler'
describe Scheduler::Base do
+ before(:each) do
+ command_line_args = ['--do-nothing']
+ @scheduler = Scheduler::Base.new(*command_line_args)
+ @scheduler.stub!(:log)
+ end
+
it "should load tasks without errors"
+
+ describe 'decide_what_to_run' do
+ it "should support --only" do
+ @scheduler.decide_what_to_run(%w(--only=alphabets))
+ @scheduler.instance_variable_get("@load_only").should == ['alphabets']
+ end
+
+ it "should support --except" do
+ @scheduler.decide_what_to_run(%w(--except=balloons,monkeys))
+ @scheduler.instance_variable_get("@load_except").should == ['balloons', 'monkeys']
+ end
+ end
+
it "should decide which tasks to run"
- it "should support --only"
- it "should support --except"
+
it "should set up exception handling"
+
it "should add each task to the scheduler"
end
View
8 spec/spec_helper.rb
@@ -0,0 +1,8 @@
+require 'rubygems'
+require 'spec'
+require 'chronic'
+
+RAILS_ENV = 'test'
+
+Spec::Runner.configure do |config|
+end
View
2 uninstall.rb
@@ -1 +1 @@
-puts "Nooooooooo! but we were so good together!"
+puts "Files in lib/scheduled_tasks will be left alone."

0 comments on commit 4d7d94e

Please sign in to comment.