scheduler_daemon 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGES +10 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +91 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/generators/scheduler/USAGE +6 -0
- data/generators/scheduler/scheduler_generator.rb +25 -0
- data/generators/scheduler/templates/README +8 -0
- data/generators/scheduler/templates/bin/boot.rb +10 -0
- data/generators/scheduler/templates/bin/scheduler_daemon.rb +25 -0
- data/generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb +21 -0
- data/generators/scheduler/templates/lib/scheduler.rb +90 -0
- data/generators/scheduler/templates/lib/scheduler/exception_handler.rb +12 -0
- data/generators/scheduler/templates/lib/scheduler/hijack_puts.rb +8 -0
- data/generators/scheduler/templates/lib/scheduler/scheduler_task.rb +69 -0
- data/generators/scheduler_task/scheduler_task_generator.rb +11 -0
- data/generators/scheduler_task/templates/README +14 -0
- data/generators/scheduler_task/templates/scheduled_tasks/example_task.rb +10 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/lib/scheduler.rb +2 -0
- data/scheduler_daemon.gemspec +74 -0
- data/spec/README +1 -0
- data/spec/scheduled_tasks/session_cleaner_task_spec.rb +31 -0
- data/spec/scheduler_spec.rb +10 -0
- data/uninstall.rb +1 -0
- metadata +121 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/CHANGES
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Steven Soroka
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
Scheduler Daemon
|
2
|
+
================
|
3
|
+
|
4
|
+
Rails 2.3.2 compatible scheduler daemon. Replaces cron/rake pattern of periodically running rake tasks
|
5
|
+
to perform maintenance tasks in Rails apps. Scheduler Daemon is made specifically for your Rails app,
|
6
|
+
and only loads the environment once, no matter how many tasks run.
|
7
|
+
|
8
|
+
What's so great about it? Well, I'm glad you asked!
|
9
|
+
|
10
|
+
- Only loads your Rails environment once on daemon start, not every time a task is run
|
11
|
+
- Allows you to easily deploy the scheduled tasks with your Rails app instead of depending on an
|
12
|
+
administrator to update crontab
|
13
|
+
- It doesn't use rake or cron!
|
14
|
+
- Gets you up and running with your own daemon in under 2 minutes
|
15
|
+
|
16
|
+
Setup
|
17
|
+
=====
|
18
|
+
|
19
|
+
Install the plugin
|
20
|
+
|
21
|
+
script/plugin install git://github.com/ssoroka/scheduler_daemon.git
|
22
|
+
|
23
|
+
Install required gems
|
24
|
+
|
25
|
+
gem sources -a http://gems.github.com # if you haven't already...
|
26
|
+
|
27
|
+
sudo gem install daemons rufus-scheduler eventmachine chronic
|
28
|
+
|
29
|
+
You'll need the chronic gem if you want to be able to use english time descriptions in your scheduled tasks, like:
|
30
|
+
|
31
|
+
every '3h', :first_at => Chronic.parse('midnight')
|
32
|
+
|
33
|
+
generate the scheduler daemon files in your rails app:
|
34
|
+
|
35
|
+
script/generate scheduler
|
36
|
+
|
37
|
+
Usage
|
38
|
+
=====
|
39
|
+
|
40
|
+
generate a new scheduled task:
|
41
|
+
|
42
|
+
script/generate scheduler_task MyTaskName
|
43
|
+
|
44
|
+
|
45
|
+
Tasks support their own special DSL; commands are:
|
46
|
+
|
47
|
+
environments :production, :staging # run only in environments listed. (:all by default)
|
48
|
+
every '1d' # run once a day
|
49
|
+
every '1d', :first_at => Chronic.parse("2 am") # run once a day, starting at 2 am
|
50
|
+
at Cronic.parse('5 pm') # run once at 5 pm, today (today would be relative to scheduler start/restart)
|
51
|
+
cron '* 4 * * *' # cron style (the example is run at 4 am, I do believe)
|
52
|
+
in '30s' # run once, 30 seconds from scheduler start/restart
|
53
|
+
|
54
|
+
fire up the daemon in console mode to test it out
|
55
|
+
|
56
|
+
ruby scheduler/bin/scheduler_daemon.rb run
|
57
|
+
|
58
|
+
When you're done, get your system admin (or switch hats) to add the daemon to the system start-up, and
|
59
|
+
capistrano deploy scripts, etc. Something like:
|
60
|
+
|
61
|
+
RAILS_ENV=production ruby scheduler/bin/scheduler_daemon.rb start
|
62
|
+
|
63
|
+
Run individual tasks like so:
|
64
|
+
|
65
|
+
ruby daemons/bin/task_runner.rb run -- --only=task_name1,task_name2
|
66
|
+
|
67
|
+
Specs
|
68
|
+
=====
|
69
|
+
|
70
|
+
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.
|
71
|
+
|
72
|
+
See spec/README for more information
|
73
|
+
|
74
|
+
To Do
|
75
|
+
=====
|
76
|
+
|
77
|
+
- dynamically add and remove tasks while daemon is running (? anyone want this?) Perhaps a web interface?
|
78
|
+
|
79
|
+
Author
|
80
|
+
======
|
81
|
+
|
82
|
+
Steven Soroka
|
83
|
+
|
84
|
+
* [@ssoroka](http://twitter.com/ssoroka)
|
85
|
+
* [My Github repo](http://github.com/ssoroka)
|
86
|
+
* [My blog](http://blog.stevensoroka.ca)
|
87
|
+
|
88
|
+
Thanks
|
89
|
+
======
|
90
|
+
|
91
|
+
Special thanks to [Goldstar](http://www.goldstar.com) for sponsoring the plugin and promoting open-sourcesness.
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "scheduler_daemon"
|
8
|
+
gem.summary = %Q{Rails 2.3.2 compatible scheduler daemon. Replaces cron/rake pattern of periodically running rake tasks
|
9
|
+
to perform maintenance tasks in Rails apps. Scheduler Daemon is made specifically for your Rails app,
|
10
|
+
and only loads the environment once, no matter how many tasks run.
|
11
|
+
|
12
|
+
What's so great about it? Well, I'm glad you asked!
|
13
|
+
|
14
|
+
- Only loads your Rails environment once on daemon start, not every time a task is run
|
15
|
+
- Allows you to easily deploy the scheduled tasks with your Rails app instead of depending on an
|
16
|
+
administrator to update crontab
|
17
|
+
- It doesn't use rake or cron!
|
18
|
+
- Gets you up and running with your own daemon in under 2 minutes
|
19
|
+
}
|
20
|
+
gem.email = "ssoroka78@gmail.com"
|
21
|
+
gem.homepage = "http://github.com/ssoroka/scheduler_daemon"
|
22
|
+
gem.authors = ["Steven Soroka"]
|
23
|
+
gem.add_dependency('eventmachine', '>= 0.12.8')
|
24
|
+
gem.add_dependency('daemons', '>= 1.0.10')
|
25
|
+
gem.add_dependency('rufus-scheduler', '>= 2.0.1')
|
26
|
+
gem.add_dependency('chronic', '>= 0.2.0')
|
27
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
28
|
+
end
|
29
|
+
|
30
|
+
rescue LoadError
|
31
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'spec/rake/spectask'
|
35
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
36
|
+
spec.libs << 'lib' << 'spec'
|
37
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
38
|
+
end
|
39
|
+
|
40
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
41
|
+
spec.libs << 'lib' << 'spec'
|
42
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
43
|
+
spec.rcov = true
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
task :default => :spec
|
48
|
+
|
49
|
+
require 'rake/rdoctask'
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
51
|
+
if File.exist?('VERSION.yml')
|
52
|
+
config = YAML.load(File.read('VERSION.yml'))
|
53
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
54
|
+
else
|
55
|
+
version = ""
|
56
|
+
end
|
57
|
+
|
58
|
+
rdoc.rdoc_dir = 'rdoc'
|
59
|
+
rdoc.title = "scheduler_daemon #{version}"
|
60
|
+
rdoc.rdoc_files.include('README*')
|
61
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
62
|
+
end
|
63
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.5.1
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class SchedulerGenerator < Rails::Generator::Base
|
2
|
+
def banner
|
3
|
+
"Usage: #{$0} #{spec.name}"
|
4
|
+
end
|
5
|
+
|
6
|
+
def manifest
|
7
|
+
record do |m|
|
8
|
+
m.directory File.join('scheduler', 'bin')
|
9
|
+
m.directory File.join('scheduler', 'lib', 'scheduled_tasks')
|
10
|
+
m.directory File.join('scheduler', 'lib', 'scheduler')
|
11
|
+
|
12
|
+
m.template 'bin/scheduler_daemon.rb', 'scheduler/bin/scheduler_daemon.rb'
|
13
|
+
m.template 'bin/boot.rb', 'scheduler/bin/boot.rb'
|
14
|
+
|
15
|
+
m.template 'lib/scheduler.rb', 'scheduler/lib/scheduler.rb'
|
16
|
+
m.template 'lib/scheduler/scheduler_task.rb', 'scheduler/lib/scheduler/scheduler_task.rb'
|
17
|
+
m.template 'lib/scheduler/hijack_puts.rb', 'scheduler/lib/scheduler/hijack_puts.rb'
|
18
|
+
m.template 'lib/scheduler/exception_handler.rb', 'scheduler/lib/scheduler/exception_handler.rb'
|
19
|
+
|
20
|
+
m.template 'lib/scheduled_tasks/session_cleaner_task.rb', 'scheduler/lib/scheduled_tasks/session_cleaner_task.rb'
|
21
|
+
|
22
|
+
m.readme('README')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# load the environment, just once. yay!
|
2
|
+
rails_root = File.expand_path(File.join(File.dirname(__FILE__), %w(.. ..)))
|
3
|
+
daemons_lib_dir = File.expand_path(File.join(File.dirname(__FILE__), %w(.. lib)))
|
4
|
+
|
5
|
+
Dir.chdir(rails_root)
|
6
|
+
|
7
|
+
require 'config/environment'
|
8
|
+
require File.join(daemons_lib_dir, 'scheduler')
|
9
|
+
|
10
|
+
Scheduler::Base.new(ARGV)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# USAGE:
|
3
|
+
#
|
4
|
+
# ruby scheduler/bin/scheduler_daemon.rb run -- start the daemon and stay on top
|
5
|
+
# ruby scheduler/bin/scheduler_daemon.rb start -- start the daemon and stay on top
|
6
|
+
# ruby scheduler/bin/scheduler_daemon.rb stop -- stop the daemon
|
7
|
+
# ruby scheduler/bin/scheduler_daemon.rb restart -- stop the daemon and restart it afterwards
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'daemons'
|
11
|
+
|
12
|
+
boot_scheduler = File.join(File.dirname(__FILE__), 'boot.rb')
|
13
|
+
pid_dir = File.expand_path(File.join(File.dirname(__FILE__), %w(.. .. log)))
|
14
|
+
|
15
|
+
FileUtils.mkdir_p(pid_dir) unless File.exist?(pid_dir)
|
16
|
+
|
17
|
+
app_options = {
|
18
|
+
:dir_mode => :normal,
|
19
|
+
:dir => pid_dir,
|
20
|
+
:multiple => false,
|
21
|
+
:backtrace => true,
|
22
|
+
:log_output => true
|
23
|
+
}
|
24
|
+
|
25
|
+
Daemons.run(boot_scheduler, app_options)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class SessionCleanerTask < Scheduler::SchedulerTask
|
2
|
+
environments :all
|
3
|
+
|
4
|
+
every '1d', :first_at => Chronic.parse('2 am')
|
5
|
+
|
6
|
+
def run
|
7
|
+
puts "running the session cleaner"
|
8
|
+
remove_old_sessions
|
9
|
+
puts "old sessions are gone!"
|
10
|
+
end
|
11
|
+
|
12
|
+
def remove_old_sessions
|
13
|
+
if ActionController::Base.session_store == ActiveRecord::SessionStore
|
14
|
+
ActiveRecord::Base.connection.execute("DELETE FROM #{session_table_name} WHERE updated_at < '#{7.days.ago.to_s(:db)}'")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def session_table_name
|
19
|
+
ActiveRecord::Base.pluralize_table_names ? :sessions : :session
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'rufus/scheduler'
|
3
|
+
require File.join(File.dirname(__FILE__), 'scheduler', 'hijack_puts')
|
4
|
+
require File.join(File.dirname(__FILE__), 'scheduler', 'scheduler_task')
|
5
|
+
require File.join(File.dirname(__FILE__), 'scheduler', 'exception_handler')
|
6
|
+
|
7
|
+
module Scheduler
|
8
|
+
class Base
|
9
|
+
attr_reader :load_only, :load_except, :tasks
|
10
|
+
|
11
|
+
def initialize(*command_line_args)
|
12
|
+
@load_only = []
|
13
|
+
@load_except = []
|
14
|
+
@tasks = []
|
15
|
+
@rufus_scheduler = nil
|
16
|
+
|
17
|
+
decide_what_to_run(command_line_args)
|
18
|
+
load_tasks
|
19
|
+
run_scheduler
|
20
|
+
end
|
21
|
+
|
22
|
+
def run_scheduler
|
23
|
+
puts "Starting Scheduler in #{RAILS_ENV}"
|
24
|
+
|
25
|
+
EventMachine::run {
|
26
|
+
@rufus_scheduler = Rufus::Scheduler::EmScheduler.start_new
|
27
|
+
|
28
|
+
def @rufus_scheduler.handle_exception(job, exception)
|
29
|
+
msg = "[#{RAILS_ENV}] scheduler job #{job.job_id} (#{job.tags * ' '}) caught exception #{exception.inspect}"
|
30
|
+
puts msg
|
31
|
+
puts exception.backtrace.join("\n")
|
32
|
+
Scheduler::ExceptionHandler.handle_exception(exception, job, message)
|
33
|
+
end
|
34
|
+
|
35
|
+
# This is where the magic happens. tasks in scheduled_tasks/*.rb are loaded up.
|
36
|
+
tasks.each do |task|
|
37
|
+
if task.should_run_in_current_environment?
|
38
|
+
task.add_to(@rufus_scheduler)
|
39
|
+
else
|
40
|
+
puts "#{task} configured not to run in #{RAILS_ENV} environment; skipping."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_tasks
|
47
|
+
tasks_to_run.each{|f|
|
48
|
+
begin
|
49
|
+
unless load_only.any? && load_only.all?{|m| f !~ Regexp.new(Regexp.escape(m)) }
|
50
|
+
require f
|
51
|
+
filename = f.split('/').last.split('.').first
|
52
|
+
puts "Loading task #{filename}..."
|
53
|
+
tasks << filename.camelcase.constantize # path/newsfeed_task.rb => NewsfeedTask
|
54
|
+
end
|
55
|
+
rescue Exception => e
|
56
|
+
msg = "Error loading task #{filename}: #{e.class.name}: #{e.message}"
|
57
|
+
puts msg
|
58
|
+
puts e.backtrace.join("\n")
|
59
|
+
Railsbot.say "#{msg}, see log for backtrace" if Rails.env.production? || Rails.env.staging?
|
60
|
+
end
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def tasks_to_run
|
65
|
+
task_files = Dir[File.join(File.dirname(__FILE__), %w(scheduled_tasks *.rb))]
|
66
|
+
|
67
|
+
if load_only.any?
|
68
|
+
task_files.reject!{|f| load_only.all?{|m| f !~ Regexp.new(Regexp.escape(m))}}
|
69
|
+
end
|
70
|
+
|
71
|
+
if load_except.any?
|
72
|
+
task_files.reject!{|f| load_except.any?{|m| f =~ Regexp.new(Regexp.escape(m))}}
|
73
|
+
end
|
74
|
+
task_files
|
75
|
+
end
|
76
|
+
|
77
|
+
# takes input from command line to later modify list of tasks to run
|
78
|
+
def decide_what_to_run(command_line_args)
|
79
|
+
# allow ruby daemons/bin/task_runner.rb run -- --only=toadcamp,newsfeed
|
80
|
+
if only_arg = command_line_args.detect{|arg| arg =~ /^--only/}
|
81
|
+
@load_only = only_arg.split('=').last.split(',')
|
82
|
+
end
|
83
|
+
|
84
|
+
# allow ruby daemons/bin/task_runner.rb run -- --except=toadcamp
|
85
|
+
if except_arg = command_line_args.detect{|arg| arg =~ /^--except/}
|
86
|
+
@load_except = except_arg.split('=').last.split(',')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Scheduler
|
2
|
+
class ExceptionHandler
|
3
|
+
# Change me to do something meaningful
|
4
|
+
def self.handle_exception(exception, job, message)
|
5
|
+
# If your team all hangs out in Campfire, you might want to make a
|
6
|
+
# Campfire class that makes use of the tinder gem to write these errors there.
|
7
|
+
#
|
8
|
+
# eg:
|
9
|
+
# Campfire.say "#{msg}, see log for backtrace" if Rails.env.production? || Rails.env.staging?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# hijack puts to log with a timestamp, since any output is going to be logged anyway.
|
2
|
+
module Kernel
|
3
|
+
def puts_with_timestamp(*args)
|
4
|
+
time = Time.respond_to?(:zone) ? Time.zone.now.to_s : Time.now.to_s
|
5
|
+
puts_without_timestamp(%([#{time}] #{args.join("\n")}))
|
6
|
+
end
|
7
|
+
alias_method_chain :puts, :timestamp
|
8
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Scheduler
|
2
|
+
class SchedulerTask
|
3
|
+
class <<self
|
4
|
+
def add_to(schedule)
|
5
|
+
%w(every in at cron).each{|time|
|
6
|
+
if args = self.instance_variable_get("@#{time}")
|
7
|
+
# add a default tag to the arguments so we know which task was running
|
8
|
+
options = args.extract_options!
|
9
|
+
options.merge!(:tags => [name])
|
10
|
+
# args = ['5s'] if Rails.env.development? # just for testing. :)
|
11
|
+
args << options
|
12
|
+
|
13
|
+
schedule.send(time, *args) do
|
14
|
+
begin
|
15
|
+
new.run
|
16
|
+
ensure
|
17
|
+
# Note: AR's ActiveRecord::Base.connection_pool.with_connection(&block) seems broken;
|
18
|
+
# it doesn't release the connection properly.
|
19
|
+
ActiveRecord::Base.connection_pool.release_connection
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
# run the task every... '5m', etc. see rufus-scheduler docs
|
27
|
+
def every(*args)
|
28
|
+
@every = args
|
29
|
+
end
|
30
|
+
|
31
|
+
# run the task in '30s', etc. see rufus-scheduler docs
|
32
|
+
def in(*args)
|
33
|
+
@in = args
|
34
|
+
end
|
35
|
+
|
36
|
+
# run the task at... Cronic.parse('5 pm'), etc. see rufus-scheduler docs
|
37
|
+
def at(*args)
|
38
|
+
@at = args
|
39
|
+
end
|
40
|
+
|
41
|
+
# run the task cron '* 4 * * *', etc. see rufus-scheduler docs
|
42
|
+
def cron(*args)
|
43
|
+
@cron = args
|
44
|
+
end
|
45
|
+
|
46
|
+
# what environments should this task run in?
|
47
|
+
# accepts the usual :development, :production, as well as :all
|
48
|
+
#
|
49
|
+
# examples:
|
50
|
+
# environments :all
|
51
|
+
# environments :staging, :production
|
52
|
+
# environments :development
|
53
|
+
#
|
54
|
+
def environments(*args)
|
55
|
+
@environments = args.map{|arg| arg.to_sym }
|
56
|
+
end
|
57
|
+
|
58
|
+
def should_run_in_current_environment?
|
59
|
+
@environments.nil? || @environments == [:all] || @environments.include?(RAILS_ENV.to_sym)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# override me to do stuff
|
64
|
+
def run
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
SchedulerTask = Scheduler::SchedulerTask # alias this for backwards compatability
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class SchedulerTaskGenerator < Rails::Generator::NamedBase
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
m.directory File.join('scheduler', 'lib', 'scheduled_tasks')
|
5
|
+
|
6
|
+
m.template 'scheduled_tasks/example_task.rb', "scheduler/lib/scheduled_tasks/#{file_name}_task.rb", :assigns => { :class_name => class_name }
|
7
|
+
|
8
|
+
m.readme('README')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
Awesome! Now that you've created a scheduler, you can test it out with:
|
3
|
+
|
4
|
+
ruby scheduler/bin/scheduler_daemon.rb run
|
5
|
+
|
6
|
+
to run it in the background (a la system start-up):
|
7
|
+
|
8
|
+
ruby /path/to/rails/app/scheduler/bin/scheduler_daemon.rb start
|
9
|
+
|
10
|
+
|
11
|
+
You'll probably want to add tests or specs for your new task.
|
12
|
+
You can find existing specs for plugin in the scheduler_daemon/spec folder.
|
13
|
+
|
14
|
+
Be sure to copy them to your spec folder if you're using rspec.
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'scheduler'
|
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
puts File.read(File.join(File.dirname(__FILE__), 'README.markdown'))
|
data/lib/scheduler.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{scheduler_daemon}
|
5
|
+
s.version = "0.5.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Steven Soroka"]
|
9
|
+
s.date = %q{2009-10-16}
|
10
|
+
s.email = %q{ssoroka78@gmail.com}
|
11
|
+
s.extra_rdoc_files = [
|
12
|
+
"README.markdown"
|
13
|
+
]
|
14
|
+
s.files = [
|
15
|
+
".gitignore",
|
16
|
+
"CHANGES",
|
17
|
+
"MIT-LICENSE",
|
18
|
+
"README.markdown",
|
19
|
+
"Rakefile",
|
20
|
+
"VERSION",
|
21
|
+
"generators/scheduler/USAGE",
|
22
|
+
"generators/scheduler/scheduler_generator.rb",
|
23
|
+
"generators/scheduler/templates/README",
|
24
|
+
"generators/scheduler/templates/bin/boot.rb",
|
25
|
+
"generators/scheduler/templates/bin/scheduler_daemon.rb",
|
26
|
+
"generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb",
|
27
|
+
"generators/scheduler/templates/lib/scheduler.rb",
|
28
|
+
"generators/scheduler/templates/lib/scheduler/exception_handler.rb",
|
29
|
+
"generators/scheduler/templates/lib/scheduler/hijack_puts.rb",
|
30
|
+
"generators/scheduler/templates/lib/scheduler/scheduler_task.rb",
|
31
|
+
"generators/scheduler_task/scheduler_task_generator.rb",
|
32
|
+
"generators/scheduler_task/templates/README",
|
33
|
+
"generators/scheduler_task/templates/scheduled_tasks/example_task.rb",
|
34
|
+
"init.rb",
|
35
|
+
"install.rb",
|
36
|
+
"lib/scheduler.rb",
|
37
|
+
"scheduler_daemon.gemspec",
|
38
|
+
"spec/README",
|
39
|
+
"spec/scheduled_tasks/session_cleaner_task_spec.rb",
|
40
|
+
"spec/scheduler_spec.rb",
|
41
|
+
"uninstall.rb"
|
42
|
+
]
|
43
|
+
s.homepage = %q{http://github.com/ssoroka/scheduler_daemon}
|
44
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
45
|
+
s.require_paths = ["lib"]
|
46
|
+
s.rubygems_version = %q{1.3.5}
|
47
|
+
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}
|
48
|
+
s.test_files = [
|
49
|
+
"spec/scheduled_tasks/session_cleaner_task_spec.rb",
|
50
|
+
"spec/scheduler_spec.rb"
|
51
|
+
]
|
52
|
+
|
53
|
+
if s.respond_to? :specification_version then
|
54
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
55
|
+
s.specification_version = 3
|
56
|
+
|
57
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
58
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.8"])
|
59
|
+
s.add_runtime_dependency(%q<daemons>, [">= 1.0.10"])
|
60
|
+
s.add_runtime_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
|
61
|
+
s.add_runtime_dependency(%q<chronic>, [">= 0.2.0"])
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
|
64
|
+
s.add_dependency(%q<daemons>, [">= 1.0.10"])
|
65
|
+
s.add_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
|
66
|
+
s.add_dependency(%q<chronic>, [">= 0.2.0"])
|
67
|
+
end
|
68
|
+
else
|
69
|
+
s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
|
70
|
+
s.add_dependency(%q<daemons>, [">= 1.0.10"])
|
71
|
+
s.add_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
|
72
|
+
s.add_dependency(%q<chronic>, [">= 0.2.0"])
|
73
|
+
end
|
74
|
+
end
|
data/spec/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
To install the specs for the scheduler daemon, copy this "spec" folder to one called "scheduler_daemon" in your project's spec folder.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# copy this spec to your project after installing the plugin if you want to run the specs.
|
2
|
+
# suggested file name for this file: spec/scheduler_daemon/scheduled_tasks/session_cleaner_task_spec.rb
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
5
|
+
require 'daemons/lib/scheduler_task'
|
6
|
+
require 'daemons/lib/scheduled_tasks/remove_old_sessions_task'
|
7
|
+
|
8
|
+
describe RemoveOldSessionsTask do
|
9
|
+
before(:each) do
|
10
|
+
@task = RemoveOldSessionsTask.new
|
11
|
+
@task.stub!(:puts)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should remove old sessions" do
|
15
|
+
# this test only matters if we're using AR's session store.
|
16
|
+
if ActionController::Base.session_store == ActiveRecord::SessionStore
|
17
|
+
|
18
|
+
# insert old session
|
19
|
+
ActiveRecord::Base.connection.execute(%(delete from #{@task.session_table_name} where session_id = 'abc123'))
|
20
|
+
ActiveRecord::Base.connection.execute(%(insert into #{@task.session_table_name} (session_id, updated_at) values ('abc123', '#{2.years.ago.to_s(:db)}')))
|
21
|
+
|
22
|
+
get_session_count = lambda {
|
23
|
+
ActiveRecord::Base.connection.select_one(%(select count(*) as count from #{@task.session_table_name}))['count'].to_i
|
24
|
+
}
|
25
|
+
|
26
|
+
lambda {
|
27
|
+
@task.run
|
28
|
+
}.should change(get_session_count, :call).by_at_most(-1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Scheduler::Base do
|
4
|
+
it "should load tasks without errors"
|
5
|
+
it "should decide which tasks to run"
|
6
|
+
it "should support --only"
|
7
|
+
it "should support --except"
|
8
|
+
it "should set up exception handling"
|
9
|
+
it "should add each task to the scheduler"
|
10
|
+
end
|
data/uninstall.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
puts "Nooooooooo! but we were so good together!"
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scheduler_daemon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steven Soroka
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-16 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: eventmachine
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.12.8
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: daemons
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.10
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rufus-scheduler
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.0.1
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: chronic
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.2.0
|
54
|
+
version:
|
55
|
+
description:
|
56
|
+
email: ssoroka78@gmail.com
|
57
|
+
executables: []
|
58
|
+
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files:
|
62
|
+
- README.markdown
|
63
|
+
files:
|
64
|
+
- .gitignore
|
65
|
+
- CHANGES
|
66
|
+
- MIT-LICENSE
|
67
|
+
- README.markdown
|
68
|
+
- Rakefile
|
69
|
+
- VERSION
|
70
|
+
- generators/scheduler/USAGE
|
71
|
+
- generators/scheduler/scheduler_generator.rb
|
72
|
+
- generators/scheduler/templates/README
|
73
|
+
- generators/scheduler/templates/bin/boot.rb
|
74
|
+
- generators/scheduler/templates/bin/scheduler_daemon.rb
|
75
|
+
- generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb
|
76
|
+
- generators/scheduler/templates/lib/scheduler.rb
|
77
|
+
- generators/scheduler/templates/lib/scheduler/exception_handler.rb
|
78
|
+
- generators/scheduler/templates/lib/scheduler/hijack_puts.rb
|
79
|
+
- generators/scheduler/templates/lib/scheduler/scheduler_task.rb
|
80
|
+
- generators/scheduler_task/scheduler_task_generator.rb
|
81
|
+
- generators/scheduler_task/templates/README
|
82
|
+
- generators/scheduler_task/templates/scheduled_tasks/example_task.rb
|
83
|
+
- init.rb
|
84
|
+
- install.rb
|
85
|
+
- lib/scheduler.rb
|
86
|
+
- scheduler_daemon.gemspec
|
87
|
+
- spec/README
|
88
|
+
- spec/scheduled_tasks/session_cleaner_task_spec.rb
|
89
|
+
- spec/scheduler_spec.rb
|
90
|
+
- uninstall.rb
|
91
|
+
has_rdoc: true
|
92
|
+
homepage: http://github.com/ssoroka/scheduler_daemon
|
93
|
+
licenses: []
|
94
|
+
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options:
|
97
|
+
- --charset=UTF-8
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: "0"
|
105
|
+
version:
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: "0"
|
111
|
+
version:
|
112
|
+
requirements: []
|
113
|
+
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.3.5
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: 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
|
119
|
+
test_files:
|
120
|
+
- spec/scheduled_tasks/session_cleaner_task_spec.rb
|
121
|
+
- spec/scheduler_spec.rb
|