say_when 0.1.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 +5 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/generators/say_when_migration/say_when_migration_generator.rb +11 -0
- data/generators/say_when_migration/templates/migration.rb +48 -0
- data/lib/generators/.DS_Store +0 -0
- data/lib/generators/say_when/migration/migration_generator.rb +13 -0
- data/lib/generators/say_when/migration/templates/migration.rb +47 -0
- data/lib/say_when/base_job.rb +96 -0
- data/lib/say_when/cron_expression.rb +621 -0
- data/lib/say_when/processor/active_messaging.rb +22 -0
- data/lib/say_when/processor/base.rb +17 -0
- data/lib/say_when/processor/simple.rb +15 -0
- data/lib/say_when/scheduler.rb +129 -0
- data/lib/say_when/storage/active_record/acts.rb +85 -0
- data/lib/say_when/storage/active_record/job.rb +85 -0
- data/lib/say_when/storage/active_record/job_execution.rb +17 -0
- data/lib/say_when/storage/memory/base.rb +34 -0
- data/lib/say_when/storage/memory/job.rb +48 -0
- data/lib/say_when/storage/mongoid/job.rb +15 -0
- data/lib/say_when/tasks.rb +22 -0
- data/lib/say_when/triggers/base.rb +11 -0
- data/lib/say_when/triggers/cron_strategy.rb +22 -0
- data/lib/say_when/triggers/once_strategy.rb +30 -0
- data/lib/say_when/version.rb +3 -0
- data/lib/say_when.rb +28 -0
- data/lib/tasks/say_when.rake +2 -0
- data/say_when.gemspec +26 -0
- data/spec/active_record_spec_helper.rb +11 -0
- data/spec/db/schema.rb +36 -0
- data/spec/db/test.db +0 -0
- data/spec/mongoid_spec_helper.rb +7 -0
- data/spec/say_when/cron_expression_spec.rb +72 -0
- data/spec/say_when/scheduler_spec.rb +76 -0
- data/spec/say_when/storage/active_record/job_spec.rb +84 -0
- data/spec/say_when/storage/memory/job_spec.rb +31 -0
- data/spec/say_when/storage/memory/trigger_spec.rb +54 -0
- data/spec/say_when/storage/mongoid/trigger_spec.rb +57 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/models.rb +31 -0
- metadata +224 -0
@@ -0,0 +1,129 @@
|
|
1
|
+
module SayWhen
|
2
|
+
|
3
|
+
class Scheduler
|
4
|
+
|
5
|
+
DEFAULT_PROCESSOR_CLASS = SayWhen::Processor::Simple
|
6
|
+
DEFAULT_STORAGE_STRATEGY = :memory
|
7
|
+
|
8
|
+
@@scheduler = nil
|
9
|
+
@@lock = nil
|
10
|
+
|
11
|
+
attr_accessor :storage_strategy, :processor_class, :tick_length
|
12
|
+
|
13
|
+
attr_accessor :running
|
14
|
+
|
15
|
+
# support for a singleton scheduler, but you are not restricted to this
|
16
|
+
class << self
|
17
|
+
|
18
|
+
def scheduler
|
19
|
+
self.lock.synchronize {
|
20
|
+
if @@scheduler.nil?
|
21
|
+
@@scheduler = self.new
|
22
|
+
end
|
23
|
+
}
|
24
|
+
@@scheduler
|
25
|
+
end
|
26
|
+
|
27
|
+
def configure
|
28
|
+
yield self.scheduler
|
29
|
+
self.scheduler
|
30
|
+
end
|
31
|
+
|
32
|
+
def lock
|
33
|
+
@@lock ||= Mutex.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def schedule(job)
|
37
|
+
self.scheduler.schedule(job)
|
38
|
+
end
|
39
|
+
|
40
|
+
def start
|
41
|
+
self.scheduler.start
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
self.tick_length = 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def processor
|
51
|
+
if @processor.nil?
|
52
|
+
@processor_class ||= DEFAULT_PROCESSOR_CLASS
|
53
|
+
@processor = @processor_class.new(self)
|
54
|
+
end
|
55
|
+
@processor
|
56
|
+
end
|
57
|
+
|
58
|
+
def start
|
59
|
+
logger.info "SayWhen::Scheduler starting"
|
60
|
+
|
61
|
+
[$stdout, $stderr].each{|s| s.sync = true; s.flush}
|
62
|
+
trap("TERM", "EXIT")
|
63
|
+
trap("QUIT") { stop }
|
64
|
+
|
65
|
+
begin
|
66
|
+
self.running = true
|
67
|
+
|
68
|
+
logger.info "SayWhen::Scheduler running"
|
69
|
+
job = nil
|
70
|
+
while running
|
71
|
+
begin
|
72
|
+
time_now = Time.now
|
73
|
+
logger.debug "SayWhen:: Looking for job that should be ready to fire before #{time_now}"
|
74
|
+
job = job_class.acquire_next(time_now)
|
75
|
+
if job.nil?
|
76
|
+
logger.debug "SayWhen:: no jobs to acquire, sleep"
|
77
|
+
sleep(tick_length)
|
78
|
+
else
|
79
|
+
logger.debug "SayWhen:: got a job: #{job.inspect}"
|
80
|
+
# delegate processing the trigger to the processor
|
81
|
+
self.processor.process(job)
|
82
|
+
logger.debug "SayWhen:: job processed"
|
83
|
+
|
84
|
+
# this should update next fire at, and put back in list of scheduled jobs
|
85
|
+
job.fired
|
86
|
+
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
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
logger.info "SayWhen::Scheduler stopped"
|
102
|
+
end
|
103
|
+
|
104
|
+
def stop
|
105
|
+
logger.info "SayWhen::Scheduler stopping..."
|
106
|
+
self.running = false
|
107
|
+
end
|
108
|
+
|
109
|
+
def job_class
|
110
|
+
@job_class ||= load_job_class
|
111
|
+
end
|
112
|
+
|
113
|
+
def load_job_class
|
114
|
+
strategy = @storage_strategy || DEFAULT_STORAGE_STRATEGY
|
115
|
+
require "say_when/storage/#{strategy}/job"
|
116
|
+
job_class_name = "SayWhen::Storage::#{strategy.to_s.camelize}::Job"
|
117
|
+
job_class_name.constantize
|
118
|
+
end
|
119
|
+
|
120
|
+
def schedule(job)
|
121
|
+
job_class.create(job)
|
122
|
+
end
|
123
|
+
|
124
|
+
def logger
|
125
|
+
SayWhen::logger
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module SayWhen #:nodoc:
|
2
|
+
module Storage #:nodoc:
|
3
|
+
module ActiveRecord #:nodoc:
|
4
|
+
module Acts #:nodoc:
|
5
|
+
|
6
|
+
def self.included(base) # :nodoc:
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def acts_as_scheduled
|
12
|
+
include SayWhen::Storage::ActiveRecord::Acts::InstanceMethods
|
13
|
+
|
14
|
+
has_many :scheduled_jobs, :as=>:scheduled, :class_name=>'SayWhen::Storage::ActiveRecord::Job'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module InstanceMethods
|
19
|
+
|
20
|
+
def schedule_cron(expression, time_zone, job={})
|
21
|
+
options = job_options(job)
|
22
|
+
options[:trigger_strategy] = :cron
|
23
|
+
options[:trigger_options] = {:expression => expression, :time_zone => time_zone}
|
24
|
+
Scheduler.schedule(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def schedule_once(time, job={})
|
28
|
+
options = job_options(job)
|
29
|
+
options[:trigger_strategy] = :once
|
30
|
+
options[:trigger_options] = time
|
31
|
+
Scheduler.schedule(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def schedule_in(after, job={})
|
35
|
+
options = job_options(job)
|
36
|
+
options[:trigger_strategy] = :once
|
37
|
+
options[:trigger_options] = Time.now + after
|
38
|
+
Scheduler.schedule(options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# helpers
|
42
|
+
|
43
|
+
def job_options(job)
|
44
|
+
{ :scheduled => self,
|
45
|
+
:job_class => extract_job_class(job),
|
46
|
+
:job_method => extract_job_method(job),
|
47
|
+
:data => extract_data(job) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_job_class(job)
|
51
|
+
if job.is_a?(Hash)
|
52
|
+
job[:class]
|
53
|
+
elsif job.is_a?(Class)
|
54
|
+
job.name
|
55
|
+
elsif job.is_a?(String)
|
56
|
+
job
|
57
|
+
else
|
58
|
+
raise "Could not identify job class from: #{job}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def extract_job_method(job)
|
63
|
+
if job.is_a?(Hash)
|
64
|
+
job[:method]
|
65
|
+
else
|
66
|
+
'execute'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def extract_data(job)
|
71
|
+
if job.is_a?(Hash)
|
72
|
+
job[:data]
|
73
|
+
else
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end # InstanceMethods
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
ActiveRecord::Base.send(:include, SayWhen::Storage::ActiveRecord::Acts) unless ActiveRecord::Base.include?(SayWhen::Storage::ActiveRecord::Acts)
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'say_when/base_job'
|
3
|
+
require 'say_when/storage/active_record/job_execution'
|
4
|
+
require 'say_when/storage/active_record/acts'
|
5
|
+
|
6
|
+
module SayWhen
|
7
|
+
module Storage
|
8
|
+
module ActiveRecord
|
9
|
+
|
10
|
+
class Job < ::ActiveRecord::Base
|
11
|
+
|
12
|
+
include SayWhen::BaseJob
|
13
|
+
|
14
|
+
self.table_name = "say_when_jobs"
|
15
|
+
|
16
|
+
|
17
|
+
serialize :trigger_options
|
18
|
+
serialize :data
|
19
|
+
belongs_to :scheduled, :polymorphic => true
|
20
|
+
has_many :job_executions, :class_name=>'SayWhen::Storage::ActiveRecord::JobExecution'
|
21
|
+
|
22
|
+
def self.acquire_next(no_later_than)
|
23
|
+
SayWhen::Storage::ActiveRecord::Job.transaction do
|
24
|
+
# select and lock the next job that needs executin' (status waiting, and after no_later_than)
|
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')])
|
31
|
+
|
32
|
+
# make sure there is a job ready to run
|
33
|
+
return nil if next_job.nil?
|
34
|
+
|
35
|
+
# set status to acquired to take it out of rotation
|
36
|
+
next_job.update_attribute(:status, STATE_ACQUIRED)
|
37
|
+
|
38
|
+
return next_job
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def before_create
|
43
|
+
self.status = STATE_WAITING
|
44
|
+
self.next_fire_at = self.trigger.next_fire_at(Time.now)
|
45
|
+
end
|
46
|
+
|
47
|
+
def fired
|
48
|
+
Job.transaction {
|
49
|
+
super
|
50
|
+
self.save!
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def release
|
55
|
+
Job.transaction {
|
56
|
+
super
|
57
|
+
self.save!
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# default impl with some error handling and result recording
|
63
|
+
def execute
|
64
|
+
result = nil
|
65
|
+
execution = SayWhen::Storage::ActiveRecord::JobExecution.create(:job=>self, :status=>'executing', :start_at=>Time.now)
|
66
|
+
|
67
|
+
begin
|
68
|
+
result = self.execute_job(data)
|
69
|
+
execution.result = result
|
70
|
+
execution.status = 'complete'
|
71
|
+
rescue Object=>ex
|
72
|
+
execution.result = "#{ex.class.name}: #{ex.message}\n\t#{ex.backtrace.join("\n\t")}"
|
73
|
+
execution.status = 'error'
|
74
|
+
end
|
75
|
+
|
76
|
+
execution.end_at = Time.now
|
77
|
+
execution.save!
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module SayWhen
|
4
|
+
module Storage
|
5
|
+
module ActiveRecord
|
6
|
+
|
7
|
+
class JobExecution < ::ActiveRecord::Base
|
8
|
+
|
9
|
+
self.table_name = "say_when_job_executions"
|
10
|
+
|
11
|
+
belongs_to :job, :class_name=>'SayWhen::Storage::ActiveRecord::Job'
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SayWhen
|
2
|
+
module Storage
|
3
|
+
module Memory
|
4
|
+
|
5
|
+
module Base
|
6
|
+
|
7
|
+
attr_accessor :props
|
8
|
+
|
9
|
+
def has_properties(*args)
|
10
|
+
@props ||= []
|
11
|
+
args.each do |a|
|
12
|
+
unless @props.member?(a.to_s)
|
13
|
+
@props << a.to_s
|
14
|
+
class_eval { attr_accessor(a.to_sym) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.included(base)
|
20
|
+
base.extend self
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(args={})
|
24
|
+
args.each do |k,v|
|
25
|
+
if self.class.props.member?(k.to_s)
|
26
|
+
self.send("#{k}=", v)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'say_when/storage/memory/base'
|
2
|
+
|
3
|
+
module SayWhen
|
4
|
+
module Store
|
5
|
+
module Memory
|
6
|
+
|
7
|
+
# define a trigger class
|
8
|
+
class Job
|
9
|
+
|
10
|
+
cattr_accessor :jobs
|
11
|
+
@@jobs = SortedSet.new
|
12
|
+
|
13
|
+
include SayWhen::Storage::Memory::Base
|
14
|
+
include SayWhen::BaseJob
|
15
|
+
|
16
|
+
has_properties :group, :name, :status, :start_at, :end_at
|
17
|
+
has_properties :trigger_strategy, :trigger_options, :last_fire_at, :next_fire_at
|
18
|
+
has_properties :job_class, :job_method, :data
|
19
|
+
has_properties :scheduled
|
20
|
+
|
21
|
+
def self.acquire_next(no_later_than)
|
22
|
+
self.lock.synchronize {
|
23
|
+
|
24
|
+
next_job = jobs.detect(nil) do |j|
|
25
|
+
(j.status == STATE_WAITING) && (j.next_fire_at.to_i <= no_later_than.to_i)
|
26
|
+
end
|
27
|
+
|
28
|
+
next_job.status = STATE_ACQUIRED if next_job
|
29
|
+
next_job
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(options={})
|
34
|
+
super
|
35
|
+
self.status = STATE_WAITING unless self.status
|
36
|
+
self.next_fire_at = self.trigger.next_fire_at(Time.now)
|
37
|
+
self.class.jobs << self
|
38
|
+
end
|
39
|
+
|
40
|
+
def <=>(job)
|
41
|
+
self.next_fire_at.to_i <=> job.next_fire_at.to_i
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
namespace :say_when do
|
2
|
+
task :setup
|
3
|
+
|
4
|
+
desc "Start the SayWhen Scheduler"
|
5
|
+
task :start => [ :preload ] do
|
6
|
+
require 'say_when'
|
7
|
+
SayWhen::Scheduler.start
|
8
|
+
end
|
9
|
+
|
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
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'say_when/triggers/base'
|
2
|
+
require 'say_when/cron_expression'
|
3
|
+
|
4
|
+
module SayWhen
|
5
|
+
module Triggers
|
6
|
+
class CronStrategy
|
7
|
+
|
8
|
+
include SayWhen::Triggers::Base
|
9
|
+
|
10
|
+
attr_accessor :cron_expression
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
@cron_expression = SayWhen::CronExpression.new(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def next_fire_at(time=Time.now)
|
17
|
+
cron_expression.next_fire_at(time)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'say_when/triggers/base'
|
2
|
+
|
3
|
+
module SayWhen
|
4
|
+
module Triggers
|
5
|
+
class OnceStrategy
|
6
|
+
|
7
|
+
include SayWhen::Triggers::Base
|
8
|
+
|
9
|
+
attr_accessor :once_at
|
10
|
+
|
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
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def next_fire_at(time=Time.now)
|
25
|
+
once_at if once_at >= time
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/say_when.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
require "say_when/version"
|
4
|
+
require 'say_when/base_job'
|
5
|
+
require 'say_when/cron_expression'
|
6
|
+
require 'say_when/processor/base'
|
7
|
+
require 'say_when/processor/simple'
|
8
|
+
require 'say_when/scheduler'
|
9
|
+
|
10
|
+
require 'say_when/processor/active_messaging' if defined?(ActiveMessaging)
|
11
|
+
|
12
|
+
require 'say_when/storage/active_record/job' if defined?(ActiveRecord)
|
13
|
+
|
14
|
+
module SayWhen
|
15
|
+
|
16
|
+
def SayWhen.logger=(logger)
|
17
|
+
@@logger = logger
|
18
|
+
end
|
19
|
+
|
20
|
+
def SayWhen.logger
|
21
|
+
unless defined?(@@logger)
|
22
|
+
@@logger = Rails.logger if defined?(Rails.logger) && Rails.logger
|
23
|
+
@@logger = Logger.new(STDOUT) unless defined?(@@logger)
|
24
|
+
end
|
25
|
+
@@logger
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/say_when.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "say_when/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "say_when"
|
7
|
+
s.version = SayWhen::VERSION
|
8
|
+
s.authors = ["Andrew Kuklewicz"]
|
9
|
+
s.email = ["andrew@prx.org"]
|
10
|
+
s.homepage = "http://labs.prx.org"
|
11
|
+
s.summary = %q{Scheduling system for programmatically defined and stored jobs.}
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
|
18
|
+
s.add_development_dependency "activemessaging", '~> 0.9.0'
|
19
|
+
s.add_development_dependency "activesupport", '~> 2.3.14'
|
20
|
+
s.add_development_dependency "activerecord", '~> 2.3.14'
|
21
|
+
s.add_development_dependency "mongoid", '~> 1.9.5'
|
22
|
+
s.add_development_dependency 'rspec', "~> 1.3"
|
23
|
+
s.add_development_dependency 'sqlite3'
|
24
|
+
s.add_development_dependency 'rake'
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'sqlite3'
|
3
|
+
|
4
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
5
|
+
|
6
|
+
ActiveRecord::Base.establish_connection(
|
7
|
+
:adapter => "sqlite3",
|
8
|
+
:database => (File.dirname(__FILE__) + "/db/test.db")
|
9
|
+
)
|
10
|
+
|
11
|
+
require (File.dirname(__FILE__) + "/db/schema.rb")
|
data/spec/db/schema.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
|
3
|
+
create_table :say_when_jobs, :force => true do |t|
|
4
|
+
|
5
|
+
t.string :status
|
6
|
+
|
7
|
+
t.string :trigger_strategy
|
8
|
+
t.text :trigger_options
|
9
|
+
t.string :time_zone
|
10
|
+
|
11
|
+
t.timestamp :last_fire_at
|
12
|
+
t.timestamp :next_fire_at
|
13
|
+
|
14
|
+
t.timestamp :start_at
|
15
|
+
t.timestamp :end_at
|
16
|
+
|
17
|
+
t.string :job_class
|
18
|
+
t.string :job_method
|
19
|
+
t.text :data
|
20
|
+
|
21
|
+
t.timestamps
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :say_when_job_executions, :force => true do |t|
|
25
|
+
t.integer :job_id
|
26
|
+
t.string :status
|
27
|
+
t.text :result
|
28
|
+
t.datetime :start_at
|
29
|
+
t.datetime :end_at
|
30
|
+
end
|
31
|
+
|
32
|
+
add_index :say_when_jobs, :status
|
33
|
+
add_index :say_when_jobs, :next_fire_at
|
34
|
+
|
35
|
+
|
36
|
+
end
|
data/spec/db/test.db
ADDED
Binary file
|