clockwork 2.0.2 → 2.0.3
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 +5 -5
- data/README.md +44 -8
- data/bin/clockworkd +2 -1
- data/clockwork.gemspec +2 -2
- data/lib/clockwork.rb +1 -1
- data/lib/clockwork/database_events/event_collection.rb +8 -1
- data/lib/clockwork/database_events/event_store.rb +5 -1
- data/lib/clockwork/event.rb +16 -4
- data/test/at_test.rb +0 -1
- data/test/event_test.rb +37 -0
- data/test/samples/signal_test.rb +1 -0
- metadata +15 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2c3178abe3610be706ab5cbb8ca2b62ee014fa94232a35346c27d48ec31fc0ab
|
4
|
+
data.tar.gz: b6a65f9d5c6ea01047cb2bc6fd2b9f58f9f2093ac5d043eecdee1ef8a221034a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52dee0a57f8b01792089770f77aad73af9fa7eab7a113b44733e66bd7d335abe268a7bd60f36c7f96d9c56e17d1e4d26eb94b066b9eb9ea8a669d67de1e2d9b7
|
7
|
+
data.tar.gz: fcacc19bfd3ffd3a12df1ad2d6cf71a32802e9de17b7833704af19d766cb76b8000ca236741208447af6e04515b25029da2d999c808c921b222d7076b961f985
|
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, 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`, `
|
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`, `if?`, `ignored_attributes`, `name`, 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`, and possible `at`, `if
|
147
|
+
When one of the events is ready to be run (based on it's `frequency`, and possible `at`, `if?`, `ignored attributes`, 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
|
|
@@ -166,6 +166,8 @@ When one of the events is ready to be run (based on it's `frequency`, and possib
|
|
166
166
|
|
167
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
168
|
|
169
|
+
- (optionally) `ignored_attributes` returning an array of model attributes (as symbols) to ignore when determining whether the database event has been modified since our last run
|
170
|
+
|
169
171
|
- (optionally) `tz` returning the timezone to use (default is the local timezone)
|
170
172
|
|
171
173
|
#### Example Setup
|
@@ -245,6 +247,28 @@ class ClockworkDatabaseEvent < ActiveRecord::Base
|
|
245
247
|
end
|
246
248
|
```
|
247
249
|
|
250
|
+
#### Example use of `ignored_attributes`
|
251
|
+
|
252
|
+
Clockwork compares all attributes of the model between runs to determine if the model has changed, and if it has, it runs the event if all other conditions are met.
|
253
|
+
|
254
|
+
However, in certain cases, you may want to store additional attributes in your model that you don't want to affect whether a database event is executed prior to its next interval.
|
255
|
+
|
256
|
+
So for example, you may update an attribute of your model named `last_scheduled_at` on each run to track the last time it was successfully scheduled. You can tell Clockwork to ignore that attribute in its comparison as follows:
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
# app/models/clockwork_database_event.rb
|
260
|
+
class ClockworkDatabaseEvent < ActiveRecord::Base
|
261
|
+
|
262
|
+
...
|
263
|
+
|
264
|
+
def ignored_attributes
|
265
|
+
[ :last_scheduled_at ]
|
266
|
+
end
|
267
|
+
|
268
|
+
...
|
269
|
+
end
|
270
|
+
```
|
271
|
+
|
248
272
|
|
249
273
|
Event Parameters
|
250
274
|
----------
|
@@ -319,7 +343,7 @@ Run on every first day of month.
|
|
319
343
|
Clockwork.every(1.day, 'myjob', :if => lambda { |t| t.day == 1 })
|
320
344
|
```
|
321
345
|
|
322
|
-
The argument is an instance of `
|
346
|
+
The argument is an instance of `Time`. If the `:tz` option is set, it has the given time zone. Otherwise, the time zone is the system time zone.
|
323
347
|
|
324
348
|
This argument cannot be omitted. Please use _ as placeholder if not needed.
|
325
349
|
|
@@ -341,6 +365,19 @@ Clockwork.every(1.day, 'run.me.in.new.thread', :thread => true)
|
|
341
365
|
|
342
366
|
If a job is long-running or IO-intensive, this option helps keep the clock precise.
|
343
367
|
|
368
|
+
### :skip_first_run
|
369
|
+
|
370
|
+
Normally, a clockwork process that is defined to run in a specified period will run at startup.
|
371
|
+
This is sometimes undesired behaviour, if the action being run relies on other processes booting which may be slower than clock.
|
372
|
+
To avoid this problem, `:skip_first_run` can be used.
|
373
|
+
|
374
|
+
```ruby
|
375
|
+
Clockwork.every(5.minutes, 'myjob', :skip_first_run => true)
|
376
|
+
```
|
377
|
+
|
378
|
+
The above job will not run at initial boot, and instead run every 5 minutes after boot.
|
379
|
+
|
380
|
+
|
344
381
|
Configuration
|
345
382
|
-----------------------
|
346
383
|
|
@@ -357,7 +394,6 @@ Clockwork wakes up once a second and performs its duties. To change the number o
|
|
357
394
|
sleeps, set the `sleep_timeout` configuration option as shown below in the example.
|
358
395
|
|
359
396
|
From 1.1.0, Clockwork does not accept `sleep_timeout` less than 1 seconds.
|
360
|
-
This restriction is introduced to solve more severe bug [#135](https://github.com/tomykaira/clockwork/pull/135).
|
361
397
|
|
362
398
|
### :tz
|
363
399
|
|
@@ -527,7 +563,7 @@ For more details, you can run `clockworkd -h`.
|
|
527
563
|
Issues and Pull requests
|
528
564
|
------------------------
|
529
565
|
|
530
|
-
If you find a bug, please create an issue - [Issues ·
|
566
|
+
If you find a bug, please create an issue - [Issues · Rykian/clockwork](https://github.com/Rykian/clockwork/issues).
|
531
567
|
|
532
568
|
For a bug fix or a feature request, please send a pull-request.
|
533
569
|
Do not forget to add tests to show how your feature works, or what bug is fixed.
|
@@ -543,8 +579,8 @@ Use cases
|
|
543
579
|
|
544
580
|
Feel free to add your idea or experience and send a pull-request.
|
545
581
|
|
546
|
-
-
|
547
|
-
-
|
582
|
+
- Sending errors to Airbrake
|
583
|
+
- Read events from a database
|
548
584
|
|
549
585
|
Meta
|
550
586
|
----
|
@@ -559,4 +595,4 @@ Patches contributed by Mark McGranaghan and Lukáš Konarovský
|
|
559
595
|
|
560
596
|
Released under the MIT License: http://www.opensource.org/licenses/mit-license.php
|
561
597
|
|
562
|
-
|
598
|
+
https://github.com/Rykian/clockwork
|
data/bin/clockworkd
CHANGED
@@ -4,6 +4,7 @@ STDERR.sync = STDOUT.sync = true
|
|
4
4
|
|
5
5
|
require 'clockwork'
|
6
6
|
require 'optparse'
|
7
|
+
require 'pathname'
|
7
8
|
|
8
9
|
begin
|
9
10
|
require 'daemons'
|
@@ -45,7 +46,7 @@ opts = OptionParser.new do |opts|
|
|
45
46
|
end
|
46
47
|
opts.on('-c', '--clock=FILE',"Clock .rb file. Default is #{@options[:file]}.") do |clock_file|
|
47
48
|
@options[:file] = clock_file
|
48
|
-
@options[:file] = "./#{@options[:file]}" unless @options[:file].
|
49
|
+
@options[:file] = "./#{@options[:file]}" unless Pathname.new(@options[:file]).absolute?
|
49
50
|
@options[:file] = File.expand_path(@options[:file])
|
50
51
|
end
|
51
52
|
opts.on('-d', '--dir=DIR', 'Directory to change to once the process starts') do |dir|
|
data/clockwork.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "clockwork"
|
3
|
-
s.version = "2.0.
|
3
|
+
s.version = "2.0.3"
|
4
4
|
|
5
5
|
s.authors = ["Adam Wiggins", "tomykaira"]
|
6
6
|
s.license = 'MIT'
|
@@ -18,10 +18,10 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
20
|
s.add_dependency(%q<tzinfo>)
|
21
|
-
s.add_dependency(%q<activesupport>)
|
22
21
|
|
23
22
|
s.add_development_dependency "bundler", "~> 1.3"
|
24
23
|
s.add_development_dependency "rake"
|
24
|
+
s.add_development_dependency "activesupport"
|
25
25
|
s.add_development_dependency "daemons"
|
26
26
|
s.add_development_dependency "minitest", "~> 5.8"
|
27
27
|
s.add_development_dependency "mocha"
|
data/lib/clockwork.rb
CHANGED
@@ -14,7 +14,14 @@ module Clockwork
|
|
14
14
|
def has_changed?(model)
|
15
15
|
return true if event.nil?
|
16
16
|
|
17
|
-
|
17
|
+
ignored_attributes = model.ignored_attributes if model.respond_to?(:ignored_attributes)
|
18
|
+
ignored_attributes ||= []
|
19
|
+
|
20
|
+
model_attributes = model.attributes.select do |k, _|
|
21
|
+
not ignored_attributes.include?(k.to_sym)
|
22
|
+
end
|
23
|
+
|
24
|
+
event.model_attributes != model_attributes
|
18
25
|
end
|
19
26
|
|
20
27
|
def unregister
|
@@ -112,15 +112,19 @@ module Clockwork
|
|
112
112
|
options = {
|
113
113
|
:from_database => true,
|
114
114
|
:synchronizer => self,
|
115
|
+
:ignored_attributes => [],
|
115
116
|
}
|
116
117
|
|
117
118
|
options[:at] = at_strings_for(model) if model.respond_to?(:at)
|
118
119
|
options[:if] = ->(time){ model.if?(time) } if model.respond_to?(:if?)
|
119
120
|
options[:tz] = model.tz if model.respond_to?(:tz)
|
121
|
+
options[:ignored_attributes] = model.ignored_attributes if model.respond_to?(:ignored_attributes)
|
120
122
|
|
121
123
|
# store the state of the model at time of registering so we can
|
122
124
|
# easily compare and determine if state has changed later
|
123
|
-
options[:model_attributes] = model.attributes
|
125
|
+
options[:model_attributes] = model.attributes.select do |k, v|
|
126
|
+
not options[:ignored_attributes].include?(k.to_sym)
|
127
|
+
end
|
124
128
|
|
125
129
|
options
|
126
130
|
end
|
data/lib/clockwork/event.rb
CHANGED
@@ -8,20 +8,24 @@ module Clockwork
|
|
8
8
|
@period = period
|
9
9
|
@job = job
|
10
10
|
@at = At.parse(options[:at])
|
11
|
-
@last = nil
|
12
11
|
@block = block
|
13
12
|
@if = options[:if]
|
14
13
|
@thread = options.fetch(:thread, @manager.config[:thread])
|
15
14
|
@timezone = options.fetch(:tz, @manager.config[:tz])
|
15
|
+
@skip_first_run = options[:skip_first_run]
|
16
|
+
@last = @skip_first_run ? convert_timezone(Time.now) : nil
|
16
17
|
end
|
17
18
|
|
18
19
|
def convert_timezone(t)
|
19
|
-
@timezone ? t.
|
20
|
+
@timezone ? t.getlocal(TZInfo::Timezone.get(@timezone).period_for_utc(t).utc_total_offset) : t
|
20
21
|
end
|
21
22
|
|
22
23
|
def run_now?(t)
|
23
24
|
t = convert_timezone(t)
|
24
|
-
|
25
|
+
return false unless elapsed_ready?(t)
|
26
|
+
return false unless run_at?(t)
|
27
|
+
return false unless run_if?(t)
|
28
|
+
true
|
25
29
|
end
|
26
30
|
|
27
31
|
def thread?
|
@@ -57,10 +61,18 @@ module Clockwork
|
|
57
61
|
@manager.handle_error e
|
58
62
|
end
|
59
63
|
|
60
|
-
def elapsed_ready(t)
|
64
|
+
def elapsed_ready?(t)
|
61
65
|
@last.nil? || (t - @last.to_i).to_i >= @period
|
62
66
|
end
|
63
67
|
|
68
|
+
def run_at?(t)
|
69
|
+
@at.nil? || @at.ready?(t)
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_if?(t)
|
73
|
+
@if.nil? || @if.call(t)
|
74
|
+
end
|
75
|
+
|
64
76
|
def validate_if_option(if_option)
|
65
77
|
if if_option && !if_option.respond_to?(:call)
|
66
78
|
raise ArgumentError.new(':if expects a callable object, but #{if_option} does not respond to call')
|
data/test/at_test.rb
CHANGED
data/test/event_test.rb
CHANGED
@@ -34,4 +34,41 @@ describe Clockwork::Event do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
describe '#run_now?' do
|
39
|
+
before do
|
40
|
+
@manager = Class.new
|
41
|
+
@manager.stubs(:config).returns({})
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'event skip_first_run option set to true' do
|
45
|
+
it 'returns false on first attempt' do
|
46
|
+
event = Clockwork::Event.new(@manager, 1, nil, nil, :skip_first_run => true)
|
47
|
+
assert_equal false, event.run_now?(Time.now)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns true on subsequent attempts' do
|
51
|
+
event = Clockwork::Event.new(@manager, 1, nil, nil, :skip_first_run => true)
|
52
|
+
# first run
|
53
|
+
event.run_now?(Time.now)
|
54
|
+
|
55
|
+
# second run
|
56
|
+
assert_equal true, event.run_now?(Time.now + 1)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'event skip_first_run option not set' do
|
61
|
+
it 'returns true on first attempt' do
|
62
|
+
event = Clockwork::Event.new(@manager, 1, nil, nil)
|
63
|
+
assert_equal true, event.run_now?(Time.now + 1)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'event skip_first_run option set to false' do
|
68
|
+
it 'returns true on first attempt' do
|
69
|
+
event = Clockwork::Event.new(@manager, 1, nil, nil, :skip_first_run => false)
|
70
|
+
assert_equal true, event.run_now?(Time.now)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
37
74
|
end
|
data/test/samples/signal_test.rb
CHANGED
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: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Wiggins
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2018-02-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: tzinfo
|
@@ -26,35 +26,35 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: bundler
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
35
|
-
type: :
|
34
|
+
version: '1.3'
|
35
|
+
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - "
|
39
|
+
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
41
|
+
version: '1.3'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
43
|
+
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - "
|
46
|
+
- - ">="
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - "
|
53
|
+
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: activesupport
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ">="
|
@@ -188,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
188
|
version: '0'
|
189
189
|
requirements: []
|
190
190
|
rubyforge_project:
|
191
|
-
rubygems_version: 2.
|
191
|
+
rubygems_version: 2.7.3
|
192
192
|
signing_key:
|
193
193
|
specification_version: 4
|
194
194
|
summary: A scheduler process to replace cron.
|