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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c0e853cc4ad85d5e3814beac451289db63f3cfdf
4
- data.tar.gz: 4d5b4f49d461f7a2b9e6670d122cc74c3d3ee1dc
3
+ metadata.gz: 7fbf625509799141df225a803d47a38486923c26
4
+ data.tar.gz: 9e4f834dd23c3fa8d73b65a22643566be36dbef8
5
5
  SHA512:
6
- metadata.gz: cdc0a27e31a8c45dc07aeedf1cb5c80e0983bb25dfee570568d91147a6b54d8524efc5d7ccc580f9a9ae09e0dd4126f562951a997864d142617ca44b3d4a3c2b
7
- data.tar.gz: 68a028033d71834bd0c1904de8dfeaab9624593f1211cb9254483835c71489c7936ec9ffecef30fc70f5dd62884752b35b4c58575ab89dbbe5338eb8db4e77a4
6
+ metadata.gz: 5875887345a81b5d7c8202b6f6d4d5fc7a2b1fa968611a7ebb914d949e951fa25b63585e7b60d0e64e115866a2ee04172b08268037c2d95f0142cf78d43cd377
7
+ data.tar.gz: ac4cdfbb58324b6faa106556c3339df3aefae1c8701b860ecab04402660475eb399e659caf516a486c54e68e6b43e98b9f84b1647e848063d22c2d84d8207347
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "clockwork"
3
- s.version = "1.2.1"
3
+ s.version = "1.3.0"
4
4
 
5
5
  s.authors = ["Adam Wiggins", "tomykaira"]
6
6
  s.license = 'MIT'
@@ -1,6 +1,6 @@
1
1
  require_relative 'database_events/event'
2
- require_relative 'database_events/sync_performer'
3
- require_relative 'database_events/registry'
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::SyncPerformer.setup(options, &block)
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 :sync_performer, :at
7
+ attr_accessor :event_store, :at
8
8
 
9
- def initialize(manager, period, job, block, sync_performer, options={})
9
+ def initialize(manager, period, job, block, event_store, options={})
10
10
  super(manager, period, job, block, options)
11
- @sync_performer = sync_performer
12
- @sync_performer.register(self, job)
11
+ @event_store = event_store
12
+ @event_store.register(self, job)
13
13
  end
14
14
 
15
15
  def name
16
- (job.respond_to?(:name) && job.name) ? job.name : "#{job.class}:#{job.id}"
16
+ (job_has_name? && job.name) ? job.name : "#{job.class}:#{job.id}"
17
17
  end
18
18
 
19
- def to_s
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
- private
28
- def name_has_changed?(model)
29
- job.respond_to?(:name) && job.name != model.name
23
+ def to_s
24
+ name
30
25
  end
31
26
 
32
- def frequency_has_changed?(model)
33
- @period != model.frequency
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(:sync_performer), options)
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::SyncPerformer do
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::SyncPerformer
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::SyncPerformer.setup model: model_class, every: frequency do |model|
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.2.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/registry.rb
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/sync_performer_test.rb
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/sync_performer_test.rb
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