say_when 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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