clockwork 1.2.1 → 1.3.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.
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