say_when 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  *.DS_Store
6
+ .rvmrc
@@ -1,13 +1,18 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+ require 'rails/generators/active_record/migration'
4
+
1
5
  module SayWhen
2
- class MigrationGenerator < Rails::Generator::Base
6
+ class MigrationGenerator < Rails::Generators::Base
7
+
8
+ include Rails::Generators::Migration
9
+ extend ActiveRecord::Generators::Migration
10
+
11
+ source_root File.expand_path('../templates', __FILE__)
12
+
3
13
  def manifest
4
- record do |m|
5
- m.migration_template 'migration.rb', 'db/migrate'
6
- end
14
+ migration_template 'migration.rb', 'db/migrate/create_say_when_tables'
7
15
  end
8
16
 
9
- def file_name
10
- "say_when_migration"
11
- end
12
17
  end
13
- end
18
+ end
@@ -1,4 +1,5 @@
1
- class SayWhenMigration < ActiveRecord::Migration
1
+ class CreateSayWhenTables < ActiveRecord::Migration
2
+
2
3
  def self.up
3
4
 
4
5
  create_table :say_when_jobs, :force => true do |t|
@@ -26,14 +26,12 @@ module SayWhen
26
26
  @trigger ||= load_trigger
27
27
  end
28
28
 
29
- def fired
29
+ def fired(fired_at=Time.now)
30
30
  self.lock.synchronize {
31
- fired = Time.now
32
- next_fire = trigger.next_fire_at(fired) rescue nil
33
- self.last_fire_at = fired
34
- self.next_fire_at = next_fire
31
+ self.last_fire_at = fired_at
32
+ self.next_fire_at = trigger.next_fire_at(last_fire_at + 1.second) rescue nil
35
33
 
36
- if next_fire.nil?
34
+ if next_fire_at.nil?
37
35
  self.status = STATE_COMPLETE
38
36
  else
39
37
  self.status = STATE_WAITING
@@ -50,7 +48,7 @@ module SayWhen
50
48
  end
51
49
 
52
50
  def execute
53
- self.execute_job(data)
51
+ execute_job(data)
54
52
  end
55
53
 
56
54
  def load_trigger
@@ -58,11 +56,11 @@ module SayWhen
58
56
  require "say_when/triggers/#{strategy}_strategy"
59
57
  trigger_class_name = "SayWhen::Triggers::#{strategy.to_s.camelize}Strategy"
60
58
  trigger_class = trigger_class_name.constantize
61
- trigger_class.new(trigger_options)
59
+ trigger_class.new((trigger_options || {}).merge(:job=>self))
62
60
  end
63
61
 
64
62
  def execute_job(options)
65
- task_method = (self.job_method || 'execute').to_s
63
+ task_method = (job_method || 'execute').to_s
66
64
  task = get_task(task_method)
67
65
  task.send(task_method, options)
68
66
  end
@@ -70,8 +68,8 @@ module SayWhen
70
68
  def get_task(task_method)
71
69
  task = nil
72
70
 
73
- if self.job_class
74
- tc = self.job_class.constantize
71
+ if job_class
72
+ tc = job_class.constantize
75
73
  if tc.respond_to?(task_method)
76
74
  task = tc
77
75
  else
@@ -79,14 +77,14 @@ module SayWhen
79
77
  if to.respond_to?(task_method)
80
78
  task = to
81
79
  else
82
- raise "Neither '#{self.job_class}' class nor instance respond to '#{task_method}'"
80
+ raise "Neither '#{job_class}' class nor instance respond to '#{task_method}'"
83
81
  end
84
82
  end
85
- elsif self.scheduled
86
- if self.scheduled.respond_to?(task_method)
87
- task = self.scheduled
83
+ elsif scheduled
84
+ if scheduled.respond_to?(task_method)
85
+ task = scheduled
88
86
  else
89
- raise "Scheduled '#{self.scheduled.inspect}' does not respond to '#{task_method}'"
87
+ raise "Scheduled '#{scheduled.inspect}' does not respond to '#{task_method}'"
90
88
  end
91
89
  end
92
90
  task
@@ -13,9 +13,9 @@ module SayWhen
13
13
 
14
14
  # send the job to the other end, then in the a13g processor, call the execute method
15
15
  def process(job)
16
- message = {:job_id=>job.id}.to_yaml
17
- publish :say_when, message
16
+ publish(:say_when, {:job_id=>job.id}.to_yaml)
18
17
  end
18
+
19
19
  end
20
20
 
21
21
  end
@@ -59,10 +59,11 @@ module SayWhen
59
59
  logger.info "SayWhen::Scheduler starting"
60
60
 
61
61
  [$stdout, $stderr].each{|s| s.sync = true; s.flush}
62
+
62
63
  trap("TERM", "EXIT")
63
- trap("QUIT") { stop }
64
64
 
65
65
  begin
66
+
66
67
  self.running = true
67
68
 
68
69
  logger.info "SayWhen::Scheduler running"
@@ -82,18 +83,20 @@ module SayWhen
82
83
  logger.debug "SayWhen:: job processed"
83
84
 
84
85
  # this should update next fire at, and put back in list of scheduled jobs
85
- job.fired
86
+ job.fired(time_now)
86
87
  logger.debug "SayWhen:: job fired complete"
87
-
88
- end
89
- rescue Object=>ex
90
- begin
91
- job_msg = job && " job:'#{job.inspect}'"
92
- logger.error "SayWhen:: Failure to process#{job_msg}: #{ex.message}\n\t#{ex.backtrace.join("\t\n")}"
93
- job.release if job
94
- rescue
95
- puts ex
96
88
  end
89
+ rescue Interrupt
90
+ job_msg = job && " job:'#{job.inspect}'"
91
+ logger.error "\nSayWhen:: Interrupt! #{job_msg}"
92
+ exit
93
+ rescue StandardError=>ex
94
+ job_msg = job && " job:'#{job.inspect}'"
95
+ logger.error "SayWhen:: Failure to process#{job_msg}: #{ex.message}\n\t#{ex.backtrace.join("\t\n")}"
96
+ job.release if job
97
+ rescue Exception=>ex
98
+ logger.error "SayWhen:: Exception in process#{job_msg}: #{ex.message}\n\t#{ex.backtrace.join("\t\n")}"
99
+ exit
97
100
  end
98
101
  end
99
102
  end
@@ -17,6 +17,13 @@ module SayWhen #:nodoc:
17
17
 
18
18
  module InstanceMethods
19
19
 
20
+ def schedule_instance(next_at_method, job={})
21
+ options = job_options(job)
22
+ options[:trigger_strategy] = :scheduled
23
+ options[:trigger_options] = {:next_at_method => next_at_method}
24
+ Scheduler.schedule(options)
25
+ end
26
+
20
27
  def schedule_cron(expression, time_zone, job={})
21
28
  options = job_options(job)
22
29
  options[:trigger_strategy] = :cron
@@ -27,14 +34,14 @@ module SayWhen #:nodoc:
27
34
  def schedule_once(time, job={})
28
35
  options = job_options(job)
29
36
  options[:trigger_strategy] = :once
30
- options[:trigger_options] = time
37
+ options[:trigger_options] = {:at => time}
31
38
  Scheduler.schedule(options)
32
39
  end
33
40
 
34
41
  def schedule_in(after, job={})
35
42
  options = job_options(job)
36
43
  options[:trigger_strategy] = :once
37
- options[:trigger_options] = Time.now + after
44
+ options[:trigger_options] = {:at => (Time.now + after)}
38
45
  Scheduler.schedule(options)
39
46
  end
40
47
 
@@ -23,11 +23,11 @@ module SayWhen
23
23
  SayWhen::Storage::ActiveRecord::Job.transaction do
24
24
  # select and lock the next job that needs executin' (status waiting, and after no_later_than)
25
25
  next_job = find(:first,
26
- :lock => true,
27
- :order => 'next_fire_at ASC',
28
- :conditions => ['status = ? and ? >= next_fire_at',
29
- STATE_WAITING,
30
- no_later_than.in_time_zone('UTC')])
26
+ :lock => true,
27
+ :order => 'next_fire_at ASC',
28
+ :conditions => ['status = ? and ? >= next_fire_at',
29
+ STATE_WAITING,
30
+ no_later_than.in_time_zone('UTC')])
31
31
 
32
32
  # make sure there is a job ready to run
33
33
  return nil if next_job.nil?
@@ -41,10 +41,11 @@ module SayWhen
41
41
 
42
42
  def before_create
43
43
  self.status = STATE_WAITING
44
- self.next_fire_at = self.trigger.next_fire_at(Time.now)
44
+ self.next_fire_at = self.trigger.next_fire_at
45
45
  end
46
46
 
47
- def fired
47
+
48
+ def fired(fired_at=Time.now)
48
49
  Job.transaction {
49
50
  super
50
51
  self.save!
@@ -58,7 +59,6 @@ module SayWhen
58
59
  }
59
60
  end
60
61
 
61
-
62
62
  # default impl with some error handling and result recording
63
63
  def execute
64
64
  result = nil
@@ -32,8 +32,8 @@ module SayWhen
32
32
 
33
33
  def initialize(options={})
34
34
  super
35
- self.status = STATE_WAITING unless self.status
36
- self.next_fire_at = self.trigger.next_fire_at(Time.now)
35
+ self.status = STATE_WAITING unless self.status
36
+ self.next_fire_at = trigger.next_fire_at
37
37
  self.class.jobs << self
38
38
  end
39
39
 
@@ -1,22 +1,22 @@
1
1
  namespace :say_when do
2
- task :setup
3
2
 
4
3
  desc "Start the SayWhen Scheduler"
5
- task :start => [ :preload ] do
4
+ task :start => :environment do
6
5
  require 'say_when'
7
6
  SayWhen::Scheduler.start
8
7
  end
9
8
 
10
- # Preload app files if this is Rails
11
- # thanks resque
12
- task :preload => :setup do
13
- if defined?(Rails) && Rails.respond_to?(:application)
14
- # Rails 3
15
- Rails.application.eager_load!
16
- elsif defined?(Rails::Initializer)
17
- # Rails 2.3
18
- $rails_rake_task = false
19
- Rails::Initializer.run :load_application_classes
20
- end
21
- end
9
+ # # Preload app files if this is Rails
10
+ # # thanks resque
11
+ # task :preload => :setup do
12
+ # if defined?(Rails) && Rails.respond_to?(:application)
13
+ # # Rails 3
14
+ # Rails.application.eager_load!
15
+ # elsif defined?(Rails::Initializer)
16
+ # # Rails 2.3
17
+ # $rails_rake_task = false
18
+ # Rails::Initializer.run :load_application_classes
19
+ # end
20
+ # end
21
+
22
22
  end
@@ -2,7 +2,13 @@ module SayWhen
2
2
  module Triggers
3
3
  module Base
4
4
 
5
- def next_fire_at(time=Time.now)
5
+ attr_accessor :job
6
+
7
+ def initialize(options={})
8
+ @job = options.delete(:job)
9
+ end
10
+
11
+ def next_fire_at(time=nil)
6
12
  raise NotImplementedError.new('You need to implement next_fire_at in your strategy')
7
13
  end
8
14
 
@@ -10,11 +10,12 @@ module SayWhen
10
10
  attr_accessor :cron_expression
11
11
 
12
12
  def initialize(options={})
13
+ super
13
14
  @cron_expression = SayWhen::CronExpression.new(options)
14
15
  end
15
16
 
16
- def next_fire_at(time=Time.now)
17
- cron_expression.next_fire_at(time)
17
+ def next_fire_at(time=nil)
18
+ cron_expression.next_fire_at(time || Time.now)
18
19
  end
19
20
 
20
21
  end
@@ -9,22 +9,16 @@ module SayWhen
9
9
  attr_accessor :once_at
10
10
 
11
11
  def initialize(options=nil)
12
- options ||= Time.now
13
- # if it's a hash, pull out the time
14
- @once_at = if options.is_a?(Time) || options.acts_like_time?
15
- options
16
- elsif options.is_a?(Hash) && options[:at]
17
- options[:at]
18
- else
19
- Time.now
20
- end
21
-
12
+ super
13
+ @once_at = options[:at] || Time.now
22
14
  end
23
15
 
24
- def next_fire_at(time=Time.now)
25
- once_at if once_at >= time
16
+ def next_fire_at(time=nil)
17
+ nfa = once_at if (!time || (time <= once_at))
18
+ puts "OnceStrategy: next_fire_at: #{nfa}, once_at: #{once_at}, time: #{time}"
19
+ return nfa
26
20
  end
27
21
 
28
22
  end
29
23
  end
30
- end
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'say_when/triggers/base'
2
+
3
+ module SayWhen
4
+ module Triggers
5
+ class ScheduledStrategy
6
+
7
+ include SayWhen::Triggers::Base
8
+
9
+ attr_accessor :scheduled, :next_at_method
10
+
11
+ def initialize(options={})
12
+ @scheduled = @job.scheduled
13
+ @next_at_method = options[:next_at_method] || 'next_fire_at'
14
+ end
15
+
16
+ def next_fire_at(time=Time.now)
17
+ scheduled.send(next_at_method, time)
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,3 @@
1
1
  module SayWhen
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/spec/db/test.db CHANGED
Binary file
@@ -0,0 +1,38 @@
1
+
2
+ require File.dirname(__FILE__) + '/../../spec_helper'
3
+ require File.dirname(__FILE__) + '/../../../lib/say_when/processor/active_messaging'
4
+ require File.dirname(__FILE__) + '/../../../lib/say_when/storage/active_record/job'
5
+
6
+ def destination(destination_name)
7
+ d = ActiveMessaging::Gateway.find_destination(destination_name).value
8
+ ActiveMessaging::Gateway.connection('default').find_destination d
9
+ end
10
+
11
+ describe SayWhen::Processor::ActiveMessaging do
12
+
13
+ before do
14
+
15
+ require 'activemessaging'
16
+
17
+ ActiveMessaging::Gateway.stub!(:load_connection_configuration).and_return({:adapter=>:test})
18
+
19
+ ActiveMessaging::Gateway.define do |s|
20
+ s.destination :say_when, '/queue/SayWhen'
21
+ end
22
+
23
+ SayWhen::Scheduler.configure do |scheduler|
24
+ scheduler.storage_strategy = :active_record
25
+ scheduler.processor_class = SayWhen::Processor::ActiveMessaging
26
+ end
27
+ @processor = SayWhen::Processor::ActiveMessaging.new(SayWhen::Scheduler.scheduler)
28
+ end
29
+
30
+ it "process a job by sending a message" do
31
+ @job = mock('SayWhen::Storage::ActiveRecord::Job')
32
+ @job.should_receive(:id).and_return(100)
33
+ @processor.process(@job)
34
+ destination(:say_when).messages.size.should == 1
35
+ YAML::load(destination(:say_when).messages.first.body)[:job_id].should == 100
36
+ end
37
+
38
+ end
@@ -28,7 +28,7 @@ describe SayWhen::Scheduler do
28
28
 
29
29
  job = SayWhen::Scheduler.schedule(
30
30
  :trigger_strategy => 'once',
31
- :trigger_options => 10.second.since,
31
+ :trigger_options => {:at => 10.second.since},
32
32
  :job_class => 'SayWhen::Test::TestTask',
33
33
  :job_method => 'execute'
34
34
  )
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: say_when
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Kuklewicz
@@ -15,11 +15,12 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-06-06 00:00:00 Z
18
+ date: 2012-08-15 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activemessaging
22
- version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
23
24
  none: false
24
25
  requirements:
25
26
  - - ~>
@@ -31,11 +32,11 @@ dependencies:
31
32
  - 0
32
33
  version: 0.9.0
33
34
  type: :development
34
- prerelease: false
35
- requirement: *id001
35
+ version_requirements: *id001
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activesupport
38
- version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
39
40
  none: false
40
41
  requirements:
41
42
  - - ~>
@@ -47,11 +48,11 @@ dependencies:
47
48
  - 14
48
49
  version: 2.3.14
49
50
  type: :development
50
- prerelease: false
51
- requirement: *id002
51
+ version_requirements: *id002
52
52
  - !ruby/object:Gem::Dependency
53
53
  name: activerecord
54
- version_requirements: &id003 !ruby/object:Gem::Requirement
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
55
56
  none: false
56
57
  requirements:
57
58
  - - ~>
@@ -63,11 +64,11 @@ dependencies:
63
64
  - 14
64
65
  version: 2.3.14
65
66
  type: :development
66
- prerelease: false
67
- requirement: *id003
67
+ version_requirements: *id003
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: mongoid
70
- version_requirements: &id004 !ruby/object:Gem::Requirement
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
71
72
  none: false
72
73
  requirements:
73
74
  - - ~>
@@ -79,11 +80,11 @@ dependencies:
79
80
  - 5
80
81
  version: 1.9.5
81
82
  type: :development
82
- prerelease: false
83
- requirement: *id004
83
+ version_requirements: *id004
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: rspec
86
- version_requirements: &id005 !ruby/object:Gem::Requirement
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
87
88
  none: false
88
89
  requirements:
89
90
  - - ~>
@@ -94,11 +95,11 @@ dependencies:
94
95
  - 3
95
96
  version: "1.3"
96
97
  type: :development
97
- prerelease: false
98
- requirement: *id005
98
+ version_requirements: *id005
99
99
  - !ruby/object:Gem::Dependency
100
100
  name: sqlite3
101
- version_requirements: &id006 !ruby/object:Gem::Requirement
101
+ prerelease: false
102
+ requirement: &id006 !ruby/object:Gem::Requirement
102
103
  none: false
103
104
  requirements:
104
105
  - - ">="
@@ -108,11 +109,11 @@ dependencies:
108
109
  - 0
109
110
  version: "0"
110
111
  type: :development
111
- prerelease: false
112
- requirement: *id006
112
+ version_requirements: *id006
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rake
115
- version_requirements: &id007 !ruby/object:Gem::Requirement
115
+ prerelease: false
116
+ requirement: &id007 !ruby/object:Gem::Requirement
116
117
  none: false
117
118
  requirements:
118
119
  - - ">="
@@ -122,8 +123,7 @@ dependencies:
122
123
  - 0
123
124
  version: "0"
124
125
  type: :development
125
- prerelease: false
126
- requirement: *id007
126
+ version_requirements: *id007
127
127
  description:
128
128
  email:
129
129
  - andrew@prx.org
@@ -159,6 +159,7 @@ files:
159
159
  - lib/say_when/triggers/base.rb
160
160
  - lib/say_when/triggers/cron_strategy.rb
161
161
  - lib/say_when/triggers/once_strategy.rb
162
+ - lib/say_when/triggers/scheduled_strategy.rb
162
163
  - lib/say_when/version.rb
163
164
  - lib/tasks/say_when.rake
164
165
  - say_when.gemspec
@@ -167,6 +168,7 @@ files:
167
168
  - spec/db/test.db
168
169
  - spec/mongoid_spec_helper.rb
169
170
  - spec/say_when/cron_expression_spec.rb
171
+ - spec/say_when/processor/active_messaging_spec.rb
170
172
  - spec/say_when/scheduler_spec.rb
171
173
  - spec/say_when/storage/active_record/job_spec.rb
172
174
  - spec/say_when/storage/memory/job_spec.rb
@@ -214,6 +216,7 @@ test_files:
214
216
  - spec/db/test.db
215
217
  - spec/mongoid_spec_helper.rb
216
218
  - spec/say_when/cron_expression_spec.rb
219
+ - spec/say_when/processor/active_messaging_spec.rb
217
220
  - spec/say_when/scheduler_spec.rb
218
221
  - spec/say_when/storage/active_record/job_spec.rb
219
222
  - spec/say_when/storage/memory/job_spec.rb