clockwork 1.3.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|