scheduler_daemon 0.5.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/Gemfile +7 -0
  2. data/Gemfile.lock +36 -0
  3. data/README.markdown +83 -28
  4. data/Rakefile +39 -31
  5. data/VERSION +1 -1
  6. data/bin/scheduler_daemon +59 -0
  7. data/lib/loader/scheduler_loader.rb +12 -0
  8. data/lib/scheduler_daemon.rb +2 -0
  9. data/lib/scheduler_daemon/base.rb +149 -0
  10. data/lib/scheduler_daemon/command_line_args_to_hash.rb +47 -0
  11. data/lib/scheduler_daemon/exception_handler.rb +30 -0
  12. data/{generators → lib/scheduler_daemon/rails/generators}/scheduler/USAGE +0 -0
  13. data/lib/scheduler_daemon/rails/generators/scheduler/scheduler_generator.rb +16 -0
  14. data/lib/scheduler_daemon/rails/generators/scheduler/templates/README +11 -0
  15. data/lib/scheduler_daemon/rails/generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb +29 -0
  16. data/lib/scheduler_daemon/rails/generators/scheduler_task/scheduler_task_generator.rb +17 -0
  17. data/{generators → lib/scheduler_daemon/rails/generators}/scheduler_task/templates/README +1 -1
  18. data/lib/scheduler_daemon/rails/generators/scheduler_task/templates/scheduled_tasks/example_task.rb +19 -0
  19. data/lib/scheduler_daemon/rails/railtie.rb +9 -0
  20. data/{generators/scheduler/templates/lib/scheduler → lib/scheduler_daemon}/scheduler_task.rb +17 -8
  21. data/scheduler_daemon.gemspec +58 -35
  22. data/spec/command_line_args_to_hash_spec.rb +26 -0
  23. data/spec/scheduled_tasks/session_cleaner_task_spec.rb +11 -7
  24. data/spec/scheduler_spec.rb +18 -7
  25. data/spec/spec_helper.rb +16 -0
  26. metadata +177 -50
  27. data/.gitignore +0 -1
  28. data/CHANGES +0 -10
  29. data/generators/scheduler/scheduler_generator.rb +0 -25
  30. data/generators/scheduler/templates/README +0 -8
  31. data/generators/scheduler/templates/bin/boot.rb +0 -10
  32. data/generators/scheduler/templates/bin/scheduler_daemon.rb +0 -25
  33. data/generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb +0 -21
  34. data/generators/scheduler/templates/lib/scheduler.rb +0 -90
  35. data/generators/scheduler/templates/lib/scheduler/exception_handler.rb +0 -12
  36. data/generators/scheduler/templates/lib/scheduler/hijack_puts.rb +0 -8
  37. data/generators/scheduler_task/scheduler_task_generator.rb +0 -11
  38. data/generators/scheduler_task/templates/scheduled_tasks/example_task.rb +0 -10
  39. data/init.rb +0 -1
  40. data/install.rb +0 -1
  41. data/lib/scheduler.rb +0 -2
  42. data/spec/README +0 -1
  43. data/uninstall.rb +0 -1
@@ -0,0 +1,47 @@
1
+ begin
2
+ require 'active_support/hash_with_indifferent_access'
3
+ rescue LoadError
4
+ begin
5
+ require 'active_support/core_ext/hash'
6
+ rescue LoadError
7
+ puts "can't load activesupport gem not loaded"
8
+ raise $!
9
+ end
10
+ end
11
+
12
+ class CommandLineArgsToHash
13
+ def self.parse(args, options = {})
14
+ new(args, options).parse
15
+ end
16
+
17
+ def initialize(args, options = {})
18
+ @args = args
19
+ @options = options
20
+ end
21
+
22
+ def parse
23
+ hash = ::HashWithIndifferentAccess.new
24
+ @args.each{|arg|
25
+ k, v = read_argument(arg)
26
+ hash[k] = v
27
+ }
28
+ hash
29
+ end
30
+
31
+ def read_argument(arg)
32
+ k, v = arg.sub(/^\-\-/, '').split('=')
33
+ k = k.gsub(/-/, '_') # replace - to _ so that --skip-init becomes options[:skip_init]
34
+ v = true if v.nil? # default passed in args to true.
35
+ v = format_value(k, v)
36
+ [k, v]
37
+ end
38
+
39
+ def format_value(k, v)
40
+ if @options[:array_args] && @options[:array_args].include?(k)
41
+ v = v.split(/,\s*/) if v.respond_to?(:split)
42
+ end
43
+ v = false if v == 'false'
44
+ v = true if v == 'true'
45
+ v
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ # override this in your app to do something meaningful,
2
+ # like post to campfire or hoptoad.
3
+ #
4
+ # Example campfire code below, using 'tinder' gem:
5
+ module Scheduler
6
+ class ExceptionHandler
7
+ # @@campfire_subdomain = ''
8
+ # @@campfire_username = ''
9
+ # @@campfire_password = ''
10
+ # @@campfire_room_name = ''
11
+ # @@campfire_room = nil
12
+
13
+ def self.handle_exception(exception, job, message)
14
+ # If your team all hangs out in Campfire, you might want to try
15
+ # something like Tinder here to write these messages out to campfire,
16
+ # Such as:
17
+ #
18
+ # if Rails.env.production? || Rails.env.staging?
19
+ # msg = "#{message}, see log for backtrace"
20
+ #
21
+ # unless @@campfire_room
22
+ # campfire = Tinder::Campfire.new(@@campfire_subdomain, :ssl => true)
23
+ # campfire.login(@@campfire_username, @@campfire_password)
24
+ # @@campfire_room = campfire.find_room_by_name(@@campfire_room_name)
25
+ # end
26
+ # @@campfire_room.speak(msg)
27
+ # end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
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('lib', 'scheduled_tasks')
9
+
10
+ m.template 'lib/scheduled_tasks/session_cleaner_task.rb',
11
+ 'lib/scheduled_tasks/session_cleaner_task.rb'
12
+
13
+ m.readme('README')
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+
2
+ GREAT!
3
+
4
+ Now that you've generated the scheduler daemon and a default task,
5
+ you can take a look at the new task:
6
+
7
+ lib/scheduled_tasks/session_cleaner_task.rb
8
+
9
+ or make your own:
10
+
11
+ script/generate scheduler_task MyTaskName
@@ -0,0 +1,29 @@
1
+ class SessionCleanerTask < Scheduler::SchedulerTask
2
+ environments :all
3
+
4
+ every '1d', :first_at => Chronic.parse('next 2 am')
5
+
6
+ def run
7
+ remove_old_sessions
8
+ end
9
+
10
+ def remove_old_sessions
11
+ log "running the session cleaner"
12
+ if ActionController::Base.session_store == session_store_class
13
+ ActiveRecord::Base.connection.execute("DELETE FROM #{session_table_name} WHERE updated_at < '#{7.days.ago.to_s(:db)}'")
14
+ log "old sessions are gone!"
15
+ else
16
+ log "sessions are not stored in the database; nothing to do."
17
+ end
18
+ end
19
+
20
+ def session_store_class
21
+ return ActiveRecord::SessionStore if defined?(ActiveRecord::SessionStore)
22
+ # pre rails 2.3 support...
23
+ return CGI::Session::ActiveRecordStore if defined?(CGI::Session::ActiveRecordStore)
24
+ end
25
+
26
+ def session_table_name
27
+ ActiveRecord::Base.pluralize_table_names ? :sessions : :session
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ class SchedulerTaskGenerator < Rails::Generators::NamedBase
2
+ check_class_collision :suffix => 'Task'
3
+
4
+ def create_task
5
+ template File.join(source_dir, 'example_task.rb'), "scheduled_tasks/#{file_name}_task.rb"
6
+ readme(File.join(template_dir, 'README'))
7
+ end
8
+
9
+ private
10
+ def source_dir
11
+ File.join(template_dir, 'scheduled_tasks')
12
+ end
13
+
14
+ def template_dir
15
+ File.join(File.dirname(__FILE__), 'templates')
16
+ end
17
+ end
@@ -11,4 +11,4 @@ to run it in the background (a la system start-up):
11
11
  You'll probably want to add tests or specs for your new task.
12
12
  You can find existing specs for plugin in the scheduler_daemon/spec folder.
13
13
 
14
- Be sure to copy them to your spec folder if you're using rspec.
14
+ Be sure to copy them to your spec folder if you're using rspec.
@@ -0,0 +1,19 @@
1
+ class <%= class_name %>Task < Scheduler::SchedulerTask
2
+ environments :all
3
+ # environments :staging, :production
4
+
5
+ every '10s'
6
+ # other examples:
7
+ # every '24h', :first_at => Chronic.parse('next midnight')
8
+ # cron '* 4 * * *' # cron style
9
+ # in '30s' # run once, 30 seconds from scheduler start/restart
10
+
11
+
12
+ def run
13
+ # Your code here, eg:
14
+ # User.send_due_invoices!
15
+
16
+ # use log() for writing to scheduler daemon log
17
+ log("I've sent invoices!")
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module Scheduler
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ generators do
5
+ require 'scheduler_daemon/rails/generators/scheduler_task/scheduler_task_generator'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,18 +1,21 @@
1
1
  module Scheduler
2
2
  class SchedulerTask
3
+ attr_accessor :daemon_scheduler, :rufus_scheduler
3
4
  class <<self
4
5
  def add_to(schedule)
5
- %w(every in at cron).each{|time|
6
- if args = self.instance_variable_get("@#{time}")
6
+ %w(every in at cron).each{|time_cmd|
7
+ if args = self.instance_variable_get("@#{time_cmd}")
7
8
  # add a default tag to the arguments so we know which task was running
8
9
  options = args.extract_options!
9
10
  options.merge!(:tags => [name])
10
- # args = ['5s'] if Rails.env.development? # just for testing. :)
11
11
  args << options
12
12
 
13
- schedule.send(time, *args) do
13
+ schedule.send(time_cmd, *args) do
14
14
  begin
15
- new.run
15
+ a_task = new
16
+ a_task.daemon_scheduler = schedule.daemon_scheduler
17
+ a_task.rufus_scheduler = schedule
18
+ a_task.run
16
19
  ensure
17
20
  # Note: AR's ActiveRecord::Base.connection_pool.with_connection(&block) seems broken;
18
21
  # it doesn't release the connection properly.
@@ -55,8 +58,8 @@ module Scheduler
55
58
  @environments = args.map{|arg| arg.to_sym }
56
59
  end
57
60
 
58
- def should_run_in_current_environment?
59
- @environments.nil? || @environments == [:all] || @environments.include?(RAILS_ENV.to_sym)
61
+ def should_run_in_current_environment?(env)
62
+ @environments.nil? || @environments == [:all] || @environments.include?(env.to_sym)
60
63
  end
61
64
  end
62
65
 
@@ -64,6 +67,12 @@ module Scheduler
64
67
  def run
65
68
  nil
66
69
  end
70
+
71
+ def log(*args)
72
+ daemon_scheduler.log(*args)
73
+ end
74
+ alias :puts :log
67
75
  end
68
76
  end
69
- SchedulerTask = Scheduler::SchedulerTask # alias this for backwards compatability
77
+ # alias this for backwards compatability
78
+ # SchedulerTask = Scheduler::SchedulerTask unless defined?(::SchedulerTask)
@@ -1,74 +1,97 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
1
4
  # -*- encoding: utf-8 -*-
2
5
 
3
6
  Gem::Specification.new do |s|
4
7
  s.name = %q{scheduler_daemon}
5
- s.version = "0.5.1"
8
+ s.version = "1.1.1"
6
9
 
7
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
11
  s.authors = ["Steven Soroka"]
9
- s.date = %q{2009-10-16}
12
+ s.date = %q{2011-04-14}
13
+ s.description = %q{a Rails 2.3, Rails 3, and Ruby compatible scheduler daemon. Replaces cron/rake pattern of periodically running rake tasks to perform maintenance tasks, only loading the environment ONCE.}
10
14
  s.email = %q{ssoroka78@gmail.com}
15
+ s.executables = ["scheduler_daemon"]
11
16
  s.extra_rdoc_files = [
12
17
  "README.markdown"
13
18
  ]
14
19
  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"
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "MIT-LICENSE",
23
+ "README.markdown",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "bin/scheduler_daemon",
27
+ "lib/loader/scheduler_loader.rb",
28
+ "lib/scheduler_daemon.rb",
29
+ "lib/scheduler_daemon/base.rb",
30
+ "lib/scheduler_daemon/command_line_args_to_hash.rb",
31
+ "lib/scheduler_daemon/exception_handler.rb",
32
+ "lib/scheduler_daemon/rails/generators/scheduler/USAGE",
33
+ "lib/scheduler_daemon/rails/generators/scheduler/scheduler_generator.rb",
34
+ "lib/scheduler_daemon/rails/generators/scheduler/templates/README",
35
+ "lib/scheduler_daemon/rails/generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task.rb",
36
+ "lib/scheduler_daemon/rails/generators/scheduler_task/scheduler_task_generator.rb",
37
+ "lib/scheduler_daemon/rails/generators/scheduler_task/templates/README",
38
+ "lib/scheduler_daemon/rails/generators/scheduler_task/templates/scheduled_tasks/example_task.rb",
39
+ "lib/scheduler_daemon/rails/railtie.rb",
40
+ "lib/scheduler_daemon/scheduler_task.rb",
41
+ "scheduler_daemon.gemspec",
42
+ "spec/command_line_args_to_hash_spec.rb",
43
+ "spec/scheduled_tasks/session_cleaner_task_spec.rb",
44
+ "spec/scheduler_spec.rb",
45
+ "spec/spec_helper.rb"
42
46
  ]
43
47
  s.homepage = %q{http://github.com/ssoroka/scheduler_daemon}
44
- s.rdoc_options = ["--charset=UTF-8"]
45
48
  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}
49
+ s.rubygems_version = %q{1.7.2}
50
+ s.summary = %q{Rails 3 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
51
  s.test_files = [
52
+ "spec/command_line_args_to_hash_spec.rb",
49
53
  "spec/scheduled_tasks/session_cleaner_task_spec.rb",
50
- "spec/scheduler_spec.rb"
54
+ "spec/scheduler_spec.rb",
55
+ "spec/spec_helper.rb"
51
56
  ]
52
57
 
53
58
  if s.respond_to? :specification_version then
54
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
59
  s.specification_version = 3
56
60
 
57
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
61
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
62
+ s.add_runtime_dependency(%q<scheduler_daemon>, [">= 0"])
63
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.8"])
64
+ s.add_runtime_dependency(%q<daemons>, [">= 1.0.10"])
65
+ s.add_runtime_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
66
+ s.add_runtime_dependency(%q<chronic>, [">= 0.2.0"])
67
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
58
68
  s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.8"])
59
69
  s.add_runtime_dependency(%q<daemons>, [">= 1.0.10"])
60
70
  s.add_runtime_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
61
71
  s.add_runtime_dependency(%q<chronic>, [">= 0.2.0"])
62
72
  else
73
+ s.add_dependency(%q<scheduler_daemon>, [">= 0"])
74
+ s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
75
+ s.add_dependency(%q<daemons>, [">= 1.0.10"])
76
+ s.add_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
77
+ s.add_dependency(%q<chronic>, [">= 0.2.0"])
78
+ s.add_dependency(%q<activesupport>, [">= 0"])
63
79
  s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
64
80
  s.add_dependency(%q<daemons>, [">= 1.0.10"])
65
81
  s.add_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
66
82
  s.add_dependency(%q<chronic>, [">= 0.2.0"])
67
83
  end
68
84
  else
85
+ s.add_dependency(%q<scheduler_daemon>, [">= 0"])
86
+ s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
87
+ s.add_dependency(%q<daemons>, [">= 1.0.10"])
88
+ s.add_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
89
+ s.add_dependency(%q<chronic>, [">= 0.2.0"])
90
+ s.add_dependency(%q<activesupport>, [">= 0"])
69
91
  s.add_dependency(%q<eventmachine>, [">= 0.12.8"])
70
92
  s.add_dependency(%q<daemons>, [">= 1.0.10"])
71
93
  s.add_dependency(%q<rufus-scheduler>, [">= 2.0.1"])
72
94
  s.add_dependency(%q<chronic>, [">= 0.2.0"])
73
95
  end
74
96
  end
97
+
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'scheduler_daemon/command_line_args_to_hash'
3
+
4
+ describe CommandLineArgsToHash do
5
+ it 'should process arguments' do
6
+ h = CommandLineArgsToHash.parse('--hello')
7
+ h['hello'].should == true
8
+ end
9
+
10
+ it 'should change key names with - to _' do
11
+ h = CommandLineArgsToHash.parse(['--hi-there'])
12
+ h['hi_there'].should == true
13
+ end
14
+
15
+ it 'should play nice with array args' do
16
+ h = CommandLineArgsToHash.parse(['--only=one,two,three'], :array_args => 'only')
17
+ h['only'].should == %w(one two three)
18
+ end
19
+
20
+ it 'should handle multiple args ok' do
21
+ h = CommandLineArgsToHash.parse(['--one', '--two=three'])
22
+ h['one'].should == true
23
+ h['two'].should == 'three'
24
+ end
25
+
26
+ end
@@ -1,19 +1,21 @@
1
1
  # copy this spec to your project after installing the plugin if you want to run the specs.
2
2
  # suggested file name for this file: spec/scheduler_daemon/scheduled_tasks/session_cleaner_task_spec.rb
3
3
 
4
- require File.dirname(__FILE__) + '/../../spec_helper'
5
- require 'daemons/lib/scheduler_task'
6
- require 'daemons/lib/scheduled_tasks/remove_old_sessions_task'
4
+ # require File.join(File.dirname(__FILE__), %w(.. spec_helper))
5
+ require 'spec_helper'
6
+ require 'scheduler_daemon/scheduler_task'
7
+ require 'scheduler_daemon/rails/generators/scheduler/templates/lib/scheduled_tasks/session_cleaner_task'
7
8
 
8
- describe RemoveOldSessionsTask do
9
+ describe SessionCleanerTask do
9
10
  before(:each) do
10
- @task = RemoveOldSessionsTask.new
11
- @task.stub!(:puts)
11
+ @task = SessionCleanerTask.new
12
+ @task.stub!(:log)
12
13
  end
13
14
 
14
15
  it "should remove old sessions" do
15
16
  # this test only matters if we're using AR's session store.
16
- if ActionController::Base.session_store == ActiveRecord::SessionStore
17
+ if defined?(ActionController) && defined?(ActiveRecord) &&
18
+ ActionController::Base.session_store == ActiveRecord::SessionStore
17
19
 
18
20
  # insert old session
19
21
  ActiveRecord::Base.connection.execute(%(delete from #{@task.session_table_name} where session_id = 'abc123'))
@@ -26,6 +28,8 @@ describe RemoveOldSessionsTask do
26
28
  lambda {
27
29
  @task.run
28
30
  }.should change(get_session_count, :call).by_at_most(-1)
31
+ else
32
+ pending 'skipping SessionCleanerTask test since it depends on rails and ActiveRecord::SessionStore; try copying this spec to your rails application.'
29
33
  end
30
34
  end
31
35
  end