clockwork 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/clockwork.gemspec +1 -1
- data/lib/clockwork/database_events.rb +4 -4
- data/lib/clockwork/database_events/event.rb +12 -17
- data/lib/clockwork/database_events/event_collection.rb +59 -0
- data/lib/clockwork/database_events/event_store.rb +129 -0
- data/lib/clockwork/database_events/manager.rb +1 -1
- data/lib/clockwork/database_events/synchronizer.rb +23 -0
- data/test/database_events/event_store_test.rb +24 -0
- data/test/database_events/{sync_performer_test.rb → synchronizer_test.rb} +2 -2
- data/test/database_events/test_helpers.rb +1 -1
- metadata +8 -5
- data/lib/clockwork/database_events/registry.rb +0 -39
- data/lib/clockwork/database_events/sync_performer.rb +0 -94
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fbf625509799141df225a803d47a38486923c26
|
4
|
+
data.tar.gz: 9e4f834dd23c3fa8d73b65a22643566be36dbef8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5875887345a81b5d7c8202b6f6d4d5fc7a2b1fa968611a7ebb914d949e951fa25b63585e7b60d0e64e115866a2ee04172b08268037c2d95f0142cf78d43cd377
|
7
|
+
data.tar.gz: ac4cdfbb58324b6faa106556c3339df3aefae1c8701b860ecab04402660475eb399e659caf516a486c54e68e6b43e98b9f84b1647e848063d22c2d84d8207347
|
data/clockwork.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative 'database_events/event'
|
2
|
-
require_relative 'database_events/
|
3
|
-
require_relative 'database_events/
|
2
|
+
require_relative 'database_events/synchronizer'
|
3
|
+
require_relative 'database_events/event_store'
|
4
4
|
require_relative 'database_events/manager'
|
5
5
|
|
6
6
|
# TERMINOLOGY
|
@@ -15,7 +15,7 @@ module Clockwork
|
|
15
15
|
|
16
16
|
module Methods
|
17
17
|
def sync_database_events(options={}, &block)
|
18
|
-
DatabaseEvents::
|
18
|
+
DatabaseEvents::Synchronizer.setup(options, &block)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -23,4 +23,4 @@ module Clockwork
|
|
23
23
|
|
24
24
|
module DatabaseEvents
|
25
25
|
end
|
26
|
-
end
|
26
|
+
end
|
@@ -4,35 +4,30 @@ module Clockwork
|
|
4
4
|
|
5
5
|
class Event < Clockwork::Event
|
6
6
|
|
7
|
-
attr_accessor :
|
7
|
+
attr_accessor :event_store, :at
|
8
8
|
|
9
|
-
def initialize(manager, period, job, block,
|
9
|
+
def initialize(manager, period, job, block, event_store, options={})
|
10
10
|
super(manager, period, job, block, options)
|
11
|
-
@
|
12
|
-
@
|
11
|
+
@event_store = event_store
|
12
|
+
@event_store.register(self, job)
|
13
13
|
end
|
14
14
|
|
15
15
|
def name
|
16
|
-
(
|
16
|
+
(job_has_name? && job.name) ? job.name : "#{job.class}:#{job.id}"
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
name
|
21
|
-
end
|
22
|
-
|
23
|
-
def name_or_frequency_has_changed?(model)
|
24
|
-
name_has_changed?(model) || frequency_has_changed?(model)
|
19
|
+
def job_has_name?
|
20
|
+
job.respond_to?(:name)
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
job.respond_to?(:name) && job.name != model.name
|
23
|
+
def to_s
|
24
|
+
name
|
30
25
|
end
|
31
26
|
|
32
|
-
def
|
33
|
-
@period
|
27
|
+
def frequency
|
28
|
+
@period
|
34
29
|
end
|
35
30
|
end
|
36
31
|
|
37
32
|
end
|
38
|
-
end
|
33
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Clockwork
|
2
|
+
module DatabaseEvents
|
3
|
+
class EventCollection
|
4
|
+
|
5
|
+
def initialize(manager=Clockwork.manager)
|
6
|
+
@events = []
|
7
|
+
@manager = manager
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(event)
|
11
|
+
@events << event
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_changed?(model)
|
15
|
+
return true if event.nil?
|
16
|
+
|
17
|
+
(has_name? && name != model.name) ||
|
18
|
+
frequency != model.frequency ||
|
19
|
+
ats != model_ats(model)
|
20
|
+
end
|
21
|
+
|
22
|
+
def unregister
|
23
|
+
events.each{|e| manager.unregister(e) }
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :events, :manager
|
29
|
+
|
30
|
+
def event
|
31
|
+
events.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_name?
|
35
|
+
event.job_has_name?
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
event.name
|
40
|
+
end
|
41
|
+
|
42
|
+
def frequency
|
43
|
+
event.frequency
|
44
|
+
end
|
45
|
+
|
46
|
+
def ats
|
47
|
+
events.collect(&:at).compact
|
48
|
+
end
|
49
|
+
|
50
|
+
def model_ats(model)
|
51
|
+
at_strings_for(model).collect{|at| At.parse(at) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def at_strings_for(model)
|
55
|
+
model.at.to_s.split(',').map(&:strip)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# How EventStore and Clockwork manager events are kept in sync...
|
2
|
+
#
|
3
|
+
# The normal Clockwork::Manager is responsible for keeping track of
|
4
|
+
# Clockwork events, and ensuring they are scheduled at the correct time.
|
5
|
+
# It has an @events array for this purpose.
|
6
|
+
|
7
|
+
# For keeping track of Database-backed events though, we need to keep
|
8
|
+
# track of more information about the events, e.g. the block which should
|
9
|
+
# be triggered when they are run, which model the event comes from, the
|
10
|
+
# model ID it relates to etc. Therefore, we devised a separate mechanism
|
11
|
+
# for keeping track of these database-backed events: the per-model EventStore.
|
12
|
+
|
13
|
+
# Having two classes responsible for keeping track of events though leads to
|
14
|
+
# a slight quirk, in that these two have to be kept in sync. The way this is
|
15
|
+
# done is by letting the EventStore largely defer to the Clockwork Manager.
|
16
|
+
|
17
|
+
# 1. When the EventStore wishes to recreate events:
|
18
|
+
# - it asks the Clockwork.manager to do this for it
|
19
|
+
# - by calling Clockwork.manager.every
|
20
|
+
|
21
|
+
# 2. When the DatabaseEvents::Manager creates events (via its #register)
|
22
|
+
# - it creates a new DatabaseEvents::Event
|
23
|
+
# - DatabaseEvents::Event#initialize registers it with the EventStore
|
24
|
+
module Clockwork
|
25
|
+
|
26
|
+
module DatabaseEvents
|
27
|
+
|
28
|
+
class EventStore
|
29
|
+
|
30
|
+
def initialize(block_to_perform_on_event_trigger)
|
31
|
+
@related_events = {}
|
32
|
+
@block_to_perform_on_event_trigger = block_to_perform_on_event_trigger
|
33
|
+
end
|
34
|
+
|
35
|
+
# DatabaseEvents::Manager#register creates a new DatabaseEvents::Event, whose
|
36
|
+
# #initialize method registers the new database event with the EventStore by
|
37
|
+
# calling this method.
|
38
|
+
def register(event, model)
|
39
|
+
related_events_for(model.id).add(event)
|
40
|
+
end
|
41
|
+
|
42
|
+
def update(current_model_objects)
|
43
|
+
unregister_all_except(current_model_objects)
|
44
|
+
update_registered_models(current_model_objects)
|
45
|
+
register_new_models(current_model_objects)
|
46
|
+
end
|
47
|
+
|
48
|
+
def unregister_all_except(model_objects)
|
49
|
+
ids = model_objects.collect(&:id)
|
50
|
+
(@related_events.keys - ids).each{|id| unregister(id) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def update_registered_models(model_objects)
|
54
|
+
registered_models(model_objects).each do |model|
|
55
|
+
if has_changed?(model)
|
56
|
+
unregister(model.id)
|
57
|
+
register_with_manager(model)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def register_new_models(model_objects)
|
63
|
+
unregistered_models(model_objects).each do |new_model_object|
|
64
|
+
register_with_manager(new_model_object)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
attr_reader :related_events
|
71
|
+
|
72
|
+
def registered?(model)
|
73
|
+
related_events_for(model.id) != nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def has_changed?(model)
|
77
|
+
related_events_for(model.id).has_changed?(model)
|
78
|
+
end
|
79
|
+
|
80
|
+
def related_events_for(id)
|
81
|
+
related_events[id] ||= EventCollection.new
|
82
|
+
end
|
83
|
+
|
84
|
+
def registered_models(model_objects)
|
85
|
+
model_objects.select{|m| registered?(m) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def unregistered_models(model_objects)
|
89
|
+
model_objects.select{|m| !registered?(m) }
|
90
|
+
end
|
91
|
+
|
92
|
+
def unregister(id)
|
93
|
+
related_events_for(id).unregister
|
94
|
+
related_events.delete(id)
|
95
|
+
end
|
96
|
+
|
97
|
+
# When re-creating events, the Clockwork.manager must be used to
|
98
|
+
# create them, as it is ultimately responsible for ensuring that
|
99
|
+
# the events actually get run when they should. We call its #every
|
100
|
+
# method, which will result in DatabaseEvent::Manager#register being
|
101
|
+
# called, which creates a new DatabaseEvent::Event, which will be
|
102
|
+
# registered with the EventStore on #initialize.
|
103
|
+
def register_with_manager(model)
|
104
|
+
Clockwork.manager.
|
105
|
+
every(model.frequency, model, options(model),
|
106
|
+
&@block_to_perform_on_event_trigger)
|
107
|
+
end
|
108
|
+
|
109
|
+
def options(model)
|
110
|
+
options = {
|
111
|
+
:from_database => true,
|
112
|
+
:synchronizer => self,
|
113
|
+
:at => at_strings_for(model)
|
114
|
+
}
|
115
|
+
|
116
|
+
options[:tz] = model.tz if model.respond_to?(:tz)
|
117
|
+
|
118
|
+
options
|
119
|
+
end
|
120
|
+
|
121
|
+
def at_strings_for(model)
|
122
|
+
return nil if model.at.to_s.empty?
|
123
|
+
|
124
|
+
model.at.split(',').map(&:strip)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
@@ -10,7 +10,7 @@ module Clockwork
|
|
10
10
|
|
11
11
|
def register(period, job, block, options)
|
12
12
|
@events << if options[:from_database]
|
13
|
-
Clockwork::DatabaseEvents::Event.new(self, period, job, (block || handler), options.fetch(:
|
13
|
+
Clockwork::DatabaseEvents::Event.new(self, period, job, (block || handler), options.fetch(:synchronizer), options)
|
14
14
|
else
|
15
15
|
Clockwork::Event.new(self, period, job, block || handler, options)
|
16
16
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../database_events'
|
2
|
+
|
3
|
+
module Clockwork
|
4
|
+
|
5
|
+
module DatabaseEvents
|
6
|
+
|
7
|
+
class Synchronizer
|
8
|
+
|
9
|
+
def self.setup(options={}, &block_to_perform_on_event_trigger)
|
10
|
+
model_class = options.fetch(:model) { raise KeyError, ":model must be set to the model class" }
|
11
|
+
every = options.fetch(:every) { raise KeyError, ":every must be set to the database sync frequency" }
|
12
|
+
|
13
|
+
event_store = EventStore.new(block_to_perform_on_event_trigger)
|
14
|
+
|
15
|
+
# create event that syncs clockwork events with events coming from database-backed model
|
16
|
+
Clockwork.manager.every every, "sync_database_events_for_model_#{model_class}" do
|
17
|
+
event_store.update(model_class.all)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require 'clockwork/database_events/event_store'
|
3
|
+
require 'clockwork/database_events/event_collection'
|
4
|
+
|
5
|
+
describe Clockwork::DatabaseEvents::EventStore do
|
6
|
+
|
7
|
+
described_class = Clockwork::DatabaseEvents::EventStore
|
8
|
+
EventCollection = Clockwork::DatabaseEvents::EventCollection
|
9
|
+
|
10
|
+
describe '#register' do
|
11
|
+
it 'adds the event to the event group' do
|
12
|
+
event_group = EventCollection.new
|
13
|
+
EventCollection.stubs(:new).returns(event_group)
|
14
|
+
|
15
|
+
event = OpenStruct.new
|
16
|
+
model = OpenStruct.new id: 1
|
17
|
+
subject = described_class.new(Proc.new {})
|
18
|
+
|
19
|
+
event_group.expects(:add).with(event)
|
20
|
+
|
21
|
+
subject.register(event, model)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -7,7 +7,7 @@ require_relative '../../lib/clockwork'
|
|
7
7
|
require_relative '../../lib/clockwork/database_events'
|
8
8
|
require_relative 'test_helpers'
|
9
9
|
|
10
|
-
describe Clockwork::DatabaseEvents::
|
10
|
+
describe Clockwork::DatabaseEvents::Synchronizer do
|
11
11
|
before do
|
12
12
|
@now = Time.now
|
13
13
|
DatabaseEventModel.delete_all
|
@@ -25,7 +25,7 @@ describe Clockwork::DatabaseEvents::SyncPerformer do
|
|
25
25
|
|
26
26
|
describe "setup" do
|
27
27
|
before do
|
28
|
-
@subject = Clockwork::DatabaseEvents::
|
28
|
+
@subject = Clockwork::DatabaseEvents::Synchronizer
|
29
29
|
end
|
30
30
|
|
31
31
|
describe "arguments" do
|
@@ -5,7 +5,7 @@ def setup_sync(options={})
|
|
5
5
|
frequency = options.fetch(:every) { raise KeyError, ":every must be set to the database sync frequency" }
|
6
6
|
events_run = options.fetch(:events_run) { raise KeyError, ":events_run must be provided"}
|
7
7
|
|
8
|
-
Clockwork::DatabaseEvents::
|
8
|
+
Clockwork::DatabaseEvents::Synchronizer.setup model: model_class, every: frequency do |model|
|
9
9
|
name = model.respond_to?(:name) ? model.name : model.to_s
|
10
10
|
events_run << name
|
11
11
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clockwork
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Wiggins
|
@@ -138,15 +138,17 @@ files:
|
|
138
138
|
- lib/clockwork/at.rb
|
139
139
|
- lib/clockwork/database_events.rb
|
140
140
|
- lib/clockwork/database_events/event.rb
|
141
|
+
- lib/clockwork/database_events/event_collection.rb
|
142
|
+
- lib/clockwork/database_events/event_store.rb
|
141
143
|
- lib/clockwork/database_events/manager.rb
|
142
|
-
- lib/clockwork/database_events/
|
143
|
-
- lib/clockwork/database_events/sync_performer.rb
|
144
|
+
- lib/clockwork/database_events/synchronizer.rb
|
144
145
|
- lib/clockwork/event.rb
|
145
146
|
- lib/clockwork/manager.rb
|
146
147
|
- test/at_test.rb
|
147
148
|
- test/clockwork_test.rb
|
149
|
+
- test/database_events/event_store_test.rb
|
148
150
|
- test/database_events/support/active_record_fake.rb
|
149
|
-
- test/database_events/
|
151
|
+
- test/database_events/synchronizer_test.rb
|
150
152
|
- test/database_events/test_helpers.rb
|
151
153
|
- test/event_test.rb
|
152
154
|
- test/manager_test.rb
|
@@ -177,8 +179,9 @@ summary: A scheduler process to replace cron.
|
|
177
179
|
test_files:
|
178
180
|
- test/at_test.rb
|
179
181
|
- test/clockwork_test.rb
|
182
|
+
- test/database_events/event_store_test.rb
|
180
183
|
- test/database_events/support/active_record_fake.rb
|
181
|
-
- test/database_events/
|
184
|
+
- test/database_events/synchronizer_test.rb
|
182
185
|
- test/database_events/test_helpers.rb
|
183
186
|
- test/event_test.rb
|
184
187
|
- test/manager_test.rb
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module Clockwork
|
2
|
-
|
3
|
-
module DatabaseEvents
|
4
|
-
|
5
|
-
class Registry
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@events = Hash.new []
|
9
|
-
end
|
10
|
-
|
11
|
-
def register(event, model)
|
12
|
-
@events[model.id] = @events[model.id] + [event]
|
13
|
-
end
|
14
|
-
|
15
|
-
def unregister(model)
|
16
|
-
unregister_by_id(model.id)
|
17
|
-
end
|
18
|
-
|
19
|
-
def unregister_by_id(id)
|
20
|
-
@events[id].each{|e| Clockwork.manager.unregister(e) }
|
21
|
-
@events.delete(id)
|
22
|
-
end
|
23
|
-
|
24
|
-
def unregister_all_except(ids)
|
25
|
-
(@events.keys - ids).each{|id| unregister_by_id(id) }
|
26
|
-
end
|
27
|
-
|
28
|
-
# all events of same id will have same frequency/name, just different ats
|
29
|
-
def event_for(model)
|
30
|
-
events_for(model).first
|
31
|
-
end
|
32
|
-
|
33
|
-
def events_for(model)
|
34
|
-
@events[model.id]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
require_relative '../database_events'
|
2
|
-
|
3
|
-
module Clockwork
|
4
|
-
|
5
|
-
module DatabaseEvents
|
6
|
-
|
7
|
-
class SyncPerformer
|
8
|
-
|
9
|
-
PERFORMERS = []
|
10
|
-
|
11
|
-
def self.setup(options={}, &block)
|
12
|
-
model_class = options.fetch(:model) { raise KeyError, ":model must be set to the model class" }
|
13
|
-
every = options.fetch(:every) { raise KeyError, ":every must be set to the database sync frequency" }
|
14
|
-
|
15
|
-
sync_performer = self.new(model_class, &block)
|
16
|
-
|
17
|
-
# create event that syncs clockwork events with events coming from database-backed model
|
18
|
-
Clockwork.manager.every every, "sync_database_events_for_model_#{model_class}" do
|
19
|
-
sync_performer.sync
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def initialize(model_class, &proc)
|
24
|
-
@model_class = model_class
|
25
|
-
@block = proc
|
26
|
-
@database_event_registry = Registry.new
|
27
|
-
|
28
|
-
PERFORMERS << self
|
29
|
-
end
|
30
|
-
|
31
|
-
# delegates to Registry
|
32
|
-
def register(event, model)
|
33
|
-
@database_event_registry.register(event, model)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Ensure clockwork events reflect events from database-backed model
|
37
|
-
# Adds any new events, modifies updated ones, and delets removed ones
|
38
|
-
def sync
|
39
|
-
model_ids_that_exist = []
|
40
|
-
|
41
|
-
@model_class.all.each do |model|
|
42
|
-
model_ids_that_exist << model.id
|
43
|
-
if are_different?(@database_event_registry.event_for(model), model)
|
44
|
-
create_or_recreate_event(model)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
@database_event_registry.unregister_all_except(model_ids_that_exist)
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
def are_different?(event, model)
|
52
|
-
return true if event.nil?
|
53
|
-
event.name_or_frequency_has_changed?(model) || ats_have_changed?(model)
|
54
|
-
end
|
55
|
-
|
56
|
-
def ats_have_changed?(model)
|
57
|
-
model_ats = ats_array_for_event(model)
|
58
|
-
event_ats = ats_array_from_model(model)
|
59
|
-
|
60
|
-
model_ats != event_ats
|
61
|
-
end
|
62
|
-
|
63
|
-
def ats_array_for_event(model)
|
64
|
-
@database_event_registry.events_for(model).collect{|event| event.at }.compact
|
65
|
-
end
|
66
|
-
|
67
|
-
def ats_array_from_model(model)
|
68
|
-
(at_strings_for(model) || []).collect{|at| At.parse(at) }
|
69
|
-
end
|
70
|
-
|
71
|
-
def at_strings_for(model)
|
72
|
-
model.at.to_s.empty? ? nil : model.at.split(',').map(&:strip)
|
73
|
-
end
|
74
|
-
|
75
|
-
def create_or_recreate_event(model)
|
76
|
-
if @database_event_registry.event_for(model)
|
77
|
-
@database_event_registry.unregister(model)
|
78
|
-
end
|
79
|
-
|
80
|
-
options = {
|
81
|
-
:from_database => true,
|
82
|
-
:sync_performer => self,
|
83
|
-
:at => at_strings_for(model)
|
84
|
-
}
|
85
|
-
|
86
|
-
options[:tz] = model.tz if model.respond_to?(:tz)
|
87
|
-
|
88
|
-
# we pass actual model instance as the job, rather than just name
|
89
|
-
Clockwork.manager.every model.frequency, model, options, &@block
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
94
|
-
end
|