clockwork 1.3.1 → 2.0.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 +4 -4
- data/README.md +29 -3
- data/clockwork.gemspec +1 -1
- data/lib/clockwork/database_events/event.rb +3 -2
- data/lib/clockwork/database_events/event_collection.rb +4 -27
- data/lib/clockwork/database_events/event_store.rb +6 -1
- data/lib/clockwork/database_events/manager.rb +5 -1
- data/test/database_events/support/active_record_fake.rb +4 -0
- data/test/database_events/synchronizer_test.rb +34 -2
- data/test/database_events/test_helpers.rb +13 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6614568ab73c78b0be1866b355ba1cd288cce5a6
|
4
|
+
data.tar.gz: a083d36f8fc30fb7b55f86278b1fd1e3577d4915
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dffa0ee3bcd26a2febaafebac063f71a46857001654b3748b292601f4134a9f64c0186b626bb72bc4c4d39eaec1a41e3c162d6ca5b64d53de248176854cd7915
|
7
|
+
data.tar.gz: 169d1db6499306e74dd86c89767e92818ffcc3d55873ac9dd04ddec9fe8b2d5648cb685e1dfbac4d3ad7bff4e467fcd2046e9c4cb0c680aef079906b354fd76a
|
data/README.md
CHANGED
@@ -142,9 +142,9 @@ module Clockwork
|
|
142
142
|
end
|
143
143
|
```
|
144
144
|
|
145
|
-
This tells clockwork to fetch all `ClockworkDatabaseEvent` instances from the database,
|
145
|
+
This tells clockwork to fetch all `ClockworkDatabaseEvent` instances from the database, and create an internal clockwork event for each one. Each clockwork event will be configured based on the instance's `frequency` and, optionally, its `at`, `name`, `if?` and `tz` methods. The code above also says to reload the events from the database every `1.minute`; we need pick up any changes in the database frequently (choose a sensible reload frequency by changing the `every:` option).
|
146
146
|
|
147
|
-
When one of the events is ready to be run (based on it's `frequency`, `at` and
|
147
|
+
When one of the events is ready to be run (based on it's `frequency`, and possible `at`, `if?` and `tz` methods), clockwork arranges for the block passed to `sync_database_events` to be run. The above example shows how you could use either DelayedJob or Sidekiq to kick off a worker job. This approach is good because the ideal is to use clockwork as a simple scheduler, and avoid making it carry out any long-running tasks.
|
148
148
|
|
149
149
|
### Your Model Classes
|
150
150
|
|
@@ -158,10 +158,14 @@ When one of the events is ready to be run (based on it's `frequency`, `at` and p
|
|
158
158
|
|
159
159
|
- `frequency` returning the how frequently (in seconds) the database event should be run
|
160
160
|
|
161
|
-
- `
|
161
|
+
- `attributes` returning a hash of [attribute name] => [attribute value] values (or really anything that we can use store on registering the event, and then compare again to see if the state has changed later)
|
162
|
+
|
163
|
+
- (optionally) `at` return any acceptable clockwork `:at` string
|
162
164
|
|
163
165
|
- (optionally) `name` returning the name for the event (used to identify it in the Clcockwork output)
|
164
166
|
|
167
|
+
- (optionally) `if?` returning either true or false, depending on whether the database event should run at the given time (this method will be passed the time as a parameter, much like the standard clockwork `:if`)
|
168
|
+
|
165
169
|
- (optionally) `tz` returning the timezone to use (default is the local timezone)
|
166
170
|
|
167
171
|
#### Example Setup
|
@@ -220,6 +224,28 @@ end
|
|
220
224
|
...
|
221
225
|
```
|
222
226
|
|
227
|
+
#### Example use of `if?`
|
228
|
+
|
229
|
+
Database events support the ability to run events if certain conditions are met. This can be used to only run events on a given day, week, or month, or really any criteria you could conceive. Best of all, these criteria e.g. which day to
|
230
|
+
run it on can be attributes on your Model, and therefore change dynamically as you change the Model in the database.
|
231
|
+
|
232
|
+
So for example, if you had a Model that had a `day` and `month` integer attribute, you could specify that the Database event should only run on a particular day of a particular month as follows:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
# app/models/clockwork_database_event.rb
|
236
|
+
class ClockworkDatabaseEvent < ActiveRecord::Base
|
237
|
+
|
238
|
+
...
|
239
|
+
|
240
|
+
def if?(time)
|
241
|
+
time.day == day && time.month == month
|
242
|
+
end
|
243
|
+
|
244
|
+
...
|
245
|
+
end
|
246
|
+
```
|
247
|
+
|
248
|
+
|
223
249
|
Event Parameters
|
224
250
|
----------
|
225
251
|
|
data/clockwork.gemspec
CHANGED
@@ -4,12 +4,13 @@ module Clockwork
|
|
4
4
|
|
5
5
|
class Event < Clockwork::Event
|
6
6
|
|
7
|
-
attr_accessor :event_store, :
|
7
|
+
attr_accessor :event_store, :model_attributes
|
8
8
|
|
9
|
-
def initialize(manager, period, job, block, event_store, options={})
|
9
|
+
def initialize(manager, period, job, block, event_store, model_attributes, options={})
|
10
10
|
super(manager, period, job, block, options)
|
11
11
|
@event_store = event_store
|
12
12
|
@event_store.register(self, job)
|
13
|
+
@model_attributes = model_attributes
|
13
14
|
end
|
14
15
|
|
15
16
|
def name
|
@@ -14,9 +14,7 @@ module Clockwork
|
|
14
14
|
def has_changed?(model)
|
15
15
|
return true if event.nil?
|
16
16
|
|
17
|
-
|
18
|
-
frequency != model.frequency ||
|
19
|
-
ats != model_ats(model)
|
17
|
+
event.model_attributes != model.attributes
|
20
18
|
end
|
21
19
|
|
22
20
|
def unregister
|
@@ -27,33 +25,12 @@ module Clockwork
|
|
27
25
|
|
28
26
|
attr_reader :events, :manager
|
29
27
|
|
28
|
+
# All events in the same collection (for a model instance) are equivalent
|
29
|
+
# so we can use any of them. Only their @at variable will be different,
|
30
|
+
# but we don't care about that here.
|
30
31
|
def event
|
31
32
|
events.first
|
32
33
|
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
34
|
end
|
58
35
|
end
|
59
36
|
end
|
@@ -112,11 +112,16 @@ module Clockwork
|
|
112
112
|
options = {
|
113
113
|
:from_database => true,
|
114
114
|
:synchronizer => self,
|
115
|
-
:at => at_strings_for(model)
|
116
115
|
}
|
117
116
|
|
117
|
+
options[:at] = at_strings_for(model) if model.respond_to?(:at)
|
118
|
+
options[:if] = ->(time){ model.if?(time) } if model.respond_to?(:if?)
|
118
119
|
options[:tz] = model.tz if model.respond_to?(:tz)
|
119
120
|
|
121
|
+
# store the state of the model at time of registering so we can
|
122
|
+
# easily compare and determine if state has changed later
|
123
|
+
options[:model_attributes] = model.attributes
|
124
|
+
|
120
125
|
options
|
121
126
|
end
|
122
127
|
|
@@ -10,7 +10,11 @@ module Clockwork
|
|
10
10
|
|
11
11
|
def register(period, job, block, options)
|
12
12
|
@events << if options[:from_database]
|
13
|
-
|
13
|
+
synchronizer = options.fetch(:synchronizer)
|
14
|
+
model_attributes = options.fetch(:model_attributes)
|
15
|
+
|
16
|
+
Clockwork::DatabaseEvents::Event.
|
17
|
+
new(self, period, job, (block || handler), synchronizer, model_attributes, options)
|
14
18
|
else
|
15
19
|
Clockwork::Event.new(self, period, job, block || handler, options)
|
16
20
|
end
|
@@ -10,8 +10,6 @@ require_relative 'test_helpers'
|
|
10
10
|
describe Clockwork::DatabaseEvents::Synchronizer do
|
11
11
|
before do
|
12
12
|
@now = Time.now
|
13
|
-
DatabaseEventModel.delete_all
|
14
|
-
DatabaseEventModel2.delete_all
|
15
13
|
|
16
14
|
Clockwork.manager = @manager = Clockwork::DatabaseEvents::Manager.new
|
17
15
|
class << @manager
|
@@ -21,6 +19,9 @@ describe Clockwork::DatabaseEvents::Synchronizer do
|
|
21
19
|
|
22
20
|
after do
|
23
21
|
Clockwork.clear!
|
22
|
+
DatabaseEventModel.delete_all
|
23
|
+
DatabaseEventModel2.delete_all
|
24
|
+
DatabaseEventModelWithIf.delete_all
|
24
25
|
end
|
25
26
|
|
26
27
|
describe "setup" do
|
@@ -254,6 +255,37 @@ describe Clockwork::DatabaseEvents::Synchronizer do
|
|
254
255
|
end
|
255
256
|
end
|
256
257
|
|
258
|
+
describe "with model that responds to `if?`" do
|
259
|
+
|
260
|
+
before do
|
261
|
+
@events_run = []
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "when model.if? is true" do
|
265
|
+
it 'runs' do
|
266
|
+
DatabaseEventModelWithIf.create(:if_state => true, :frequency => 10)
|
267
|
+
setup_sync(model: DatabaseEventModelWithIf, :every => 1.minute, :events_run => @events_run)
|
268
|
+
|
269
|
+
tick_at(@now, :and_every_second_for => 9.seconds)
|
270
|
+
|
271
|
+
assert_equal 1, @events_run.length
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
describe "when model.if? is false" do
|
276
|
+
it 'does not run' do
|
277
|
+
DatabaseEventModelWithIf.create(:if_state => false, :frequency => 10, :name => 'model with if?')
|
278
|
+
setup_sync(model: DatabaseEventModelWithIf, :every => 1.minute, :events_run => @events_run)
|
279
|
+
|
280
|
+
tick_at(@now, :and_every_second_for => 1.minute)
|
281
|
+
|
282
|
+
# require 'byebug'
|
283
|
+
# byebug if events_run.length > 0
|
284
|
+
assert_equal 0, @events_run.length
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
257
289
|
describe "with task that responds to `tz`" do
|
258
290
|
before do
|
259
291
|
@events_run = []
|
@@ -55,4 +55,17 @@ end
|
|
55
55
|
class DatabaseEventModelWithoutName
|
56
56
|
include ActiveRecordFake
|
57
57
|
attr_accessor :frequency, :at
|
58
|
+
end
|
59
|
+
|
60
|
+
class DatabaseEventModelWithIf
|
61
|
+
include ActiveRecordFake
|
62
|
+
attr_accessor :name, :frequency, :at, :tz, :if_state
|
63
|
+
|
64
|
+
def name
|
65
|
+
@name || "#{self.class}:#{id}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def if?(time)
|
69
|
+
@if_state
|
70
|
+
end
|
58
71
|
end
|