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