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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 28995c167b599267520fc42d5c489da9cf3ea3a7
4
- data.tar.gz: c185ef12635ae8fcaaf300edb133adf86e3d9ac6
2
+ SHA256:
3
+ metadata.gz: 2c3178abe3610be706ab5cbb8ca2b62ee014fa94232a35346c27d48ec31fc0ab
4
+ data.tar.gz: b6a65f9d5c6ea01047cb2bc6fd2b9f58f9f2093ac5d043eecdee1ef8a221034a
5
5
  SHA512:
6
- metadata.gz: 6311c6f7d6dd160c2b5beb6cad59c87c571d7ec50e54bb50e3c8cbb656ae2fb756168a404d143ed699772c334ab2323681202509cbb9d740f954ce23bca61725
7
- data.tar.gz: c4c3b8f20fdc6da06dc73ea4f0de9ab798dfb2e8e7716777952c51bbf9a3c88fb6df5841e979ac180dbb1d4f326f3bdc78ecd7bf5e13a487fce250f3a79809ec
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`, `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).
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?` 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.
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 `ActiveSupport::TimeWithZone` if the `:tz` option is set. Otherwise, it's an instance of `Time`.
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 · tomykaira/clockwork](https://github.com/tomykaira/clockwork/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
- - [Sending errors to Airbrake](https://github.com/tomykaira/clockwork/issues/58)
547
- - [Read events from a database](https://github.com/tomykaira/clockwork/issues/25)
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
- http://github.com/tomykaira/clockwork
598
+ https://github.com/Rykian/clockwork
@@ -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].match(/^[\/.]/)
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|
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "clockwork"
3
- s.version = "2.0.2"
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"
@@ -1,5 +1,5 @@
1
1
  require 'logger'
2
- require 'active_support/time'
2
+ require 'tzinfo'
3
3
 
4
4
  require 'clockwork/at'
5
5
  require 'clockwork/event'
@@ -14,7 +14,14 @@ module Clockwork
14
14
  def has_changed?(model)
15
15
  return true if event.nil?
16
16
 
17
- event.model_attributes != model.attributes
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
@@ -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.in_time_zone(@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
- elapsed_ready(t) and (@at.nil? or @at.ready?(t)) and (@if.nil? or @if.call(t))
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')
@@ -2,7 +2,6 @@ require File.expand_path('../../lib/clockwork', __FILE__)
2
2
  require "minitest/autorun"
3
3
  require 'mocha/setup'
4
4
  require 'time'
5
- require 'active_support/time'
6
5
 
7
6
  describe 'Clockwork::At' do
8
7
  def time_in_day(hour, minute)
@@ -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
@@ -1,4 +1,5 @@
1
1
  require 'clockwork'
2
+ require 'active_support/time'
2
3
 
3
4
  module Clockwork
4
5
  LOGFILE = File.expand_path('../../tmp/signal_test.log', __FILE__)
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.2
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: 2017-03-18 00:00:00.000000000 Z
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: activesupport
29
+ name: bundler
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '0'
35
- type: :runtime
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: '0'
41
+ version: '1.3'
42
42
  - !ruby/object:Gem::Dependency
43
- name: bundler
43
+ name: rake
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '1.3'
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: '1.3'
55
+ version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: rake
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.5.1
191
+ rubygems_version: 2.7.3
192
192
  signing_key:
193
193
  specification_version: 4
194
194
  summary: A scheduler process to replace cron.