sidetiq 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,6 +1,14 @@
1
1
  language: ruby
2
+ before_script:
3
+ - bundle exec rake compile
2
4
  rvm:
5
+ - 1.9.2
3
6
  - 1.9.3
4
7
  - 2.0.0
5
- before_script:
6
- - bundle exec rake compile
8
+ - ruby-head
9
+ - jruby-19mode
10
+ - rbx-19mode
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: 1.9.2
14
+ - rvm: jruby-19mode
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ 0.2.0
2
+ -----
3
+
4
+ - Add class methods to get last and next scheduled occurrence.
5
+ - Pass last and next (current) occurrence to #perform, if desired.
6
+ This checks the method arity of #perform.
7
+ - Bump Sidekiq dependency to 2.8.0
8
+ - Fix incorrectly assigned Thread priority.
9
+ - Adjust clock sleep depending of execution time of the last tick.
10
+ - Don't log thread object ids.
11
+ - Issue a warning from the middleware if the clock thread died previously.
12
+
1
13
  0.1.5
2
14
  -----
3
15
 
data/lib/sidetiq/clock.rb CHANGED
@@ -92,7 +92,7 @@ module Sidetiq
92
92
  Sidekiq.logger.info "Sidetiq::Clock start"
93
93
  @thread = Thread.start { clock { tick } }
94
94
  @thread.abort_on_exception = true
95
- @thread.priority = Sidetiq.config.resolution
95
+ @thread.priority = Sidetiq.config.priority
96
96
  @thread
97
97
  end
98
98
 
@@ -131,15 +131,20 @@ module Sidetiq
131
131
 
132
132
  def enqueue(worker, time)
133
133
  key = "sidetiq:#{worker.name}"
134
+ time_f = time.to_f
134
135
 
135
136
  synchronize_clockworks("#{key}:lock") do |redis|
136
- status = redis.get(key)
137
+ next_run = (redis.get("#{key}:next") || -1).to_f
137
138
 
138
- if status.nil? || status.to_f < time.to_f
139
- time_f = time.to_f
140
- Sidekiq.logger.info "Sidetiq::Clock enqueue #{worker.name} (at: #{time_f})"
141
- redis.set(key, time_f)
142
- worker.perform_at(time)
139
+ if next_run < time_f
140
+ Sidekiq.logger.info "Sidetiq::Clock enqueue #{worker.name} (at: #{time_f}) (last: #{next_run})"
141
+
142
+ redis.mset("#{key}:last", next_run, "#{key}:next", time_f)
143
+
144
+ arity = [worker.instance_method(:perform).arity - 1, -1].max
145
+ args = [next_run, time_f][0..arity]
146
+
147
+ worker.perform_at(time, *args)
143
148
  end
144
149
  end
145
150
  end
@@ -147,24 +152,32 @@ module Sidetiq
147
152
  def synchronize_clockworks(lock)
148
153
  Sidekiq.redis do |redis|
149
154
  if redis.setnx(lock, 1)
150
- Sidekiq.logger.debug "Sidetiq::Clock lock #{lock} #{Thread.current.inspect}"
155
+ Sidekiq.logger.debug "Sidetiq::Clock lock #{lock}"
151
156
 
152
157
  redis.pexpire(lock, Sidetiq.config.lock_expire)
153
158
  yield redis
154
159
  redis.del(lock)
155
160
 
156
- Sidekiq.logger.debug "Sidetiq::Clock unlock #{lock} #{Thread.current.inspect}"
161
+ Sidekiq.logger.debug "Sidetiq::Clock unlock #{lock}"
157
162
  end
158
163
  end
159
164
  end
160
165
 
161
166
  def clock
162
167
  loop do
163
- yield
164
- Thread.pass
165
- sleep Sidetiq.config.resolution
168
+ sleep_time = time { yield }
169
+
170
+ if sleep_time > 0
171
+ Thread.pass
172
+ sleep sleep_time
173
+ end
166
174
  end
167
175
  end
176
+
177
+ def time
178
+ start = gettime
179
+ yield
180
+ Sidetiq.config.resolution - (gettime.to_f - start.to_f)
181
+ end
168
182
  end
169
183
  end
170
-
@@ -6,7 +6,10 @@ module Sidetiq
6
6
 
7
7
  def call(*args)
8
8
  # Restart the clock if the thread died.
9
- @clock.start! if !@clock.ticking?
9
+ if !@clock.ticking?
10
+ Sidekiq.logger.warn "Sidetiq::Clock thread died. Restarting..."
11
+ @clock.start!
12
+ end
10
13
  yield
11
14
  end
12
15
  end
@@ -12,12 +12,28 @@ module Sidetiq
12
12
  # end
13
13
  module Schedulable
14
14
  module ClassMethods
15
+ def last_scheduled_occurrence
16
+ get_timestamp "last"
17
+ end
18
+
19
+ def next_scheduled_occurrence
20
+ get_timestamp "next"
21
+ end
22
+
15
23
  def tiq(&block) # :nodoc:
16
24
  clock = Sidetiq::Clock.instance
17
25
  clock.synchronize do
18
26
  clock.schedule_for(self).instance_eval(&block)
19
27
  end
20
28
  end
29
+
30
+ private
31
+
32
+ def get_timestamp(key)
33
+ Sidekiq.redis do |redis|
34
+ (redis.get("sidetiq:#{name}:#{key}") || -1).to_f
35
+ end
36
+ end
21
37
  end
22
38
 
23
39
  def self.included(klass) # :nodoc:
@@ -25,4 +41,3 @@ module Sidetiq
25
41
  end
26
42
  end
27
43
  end
28
-
@@ -5,10 +5,10 @@ module Sidetiq
5
5
  MAJOR = 0
6
6
 
7
7
  # Public: Sidetiq minor version number.
8
- MINOR = 1
8
+ MINOR = 2
9
9
 
10
10
  # Public: Sidetiq patch level.
11
- PATCH = 5
11
+ PATCH = 0
12
12
 
13
13
  # Public: String representation of the current Sidetiq version.
14
14
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
data/sidetiq.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
  gem.version = Sidetiq::VERSION::STRING
9
9
  gem.authors = ["Tobias Svensson"]
10
10
  gem.email = ["tob@tobiassvensson.co.uk"]
11
- gem.description = "High-resolution job scheduler for Sidekiq"
11
+ gem.description = "Recurring jobs for Sidekiq"
12
12
  gem.summary = gem.description
13
13
  gem.homepage = "http://github.com/tobiassvn/sidetiq"
14
14
  gem.license = "MIT"
@@ -19,6 +19,6 @@ Gem::Specification.new do |gem|
19
19
  gem.require_paths = ["lib"]
20
20
  gem.extensions = ['ext/sidetiq_ext/extconf.rb']
21
21
 
22
- gem.add_dependency 'sidekiq', '~> 2.7.0'
23
- gem.add_dependency 'ice_cube', '~> 0.9.3'
22
+ gem.add_dependency 'sidekiq', '~> 2.8.0'
23
+ gem.add_dependency 'ice_cube', '~> 0.10.0'
24
24
  end
data/test/helper.rb CHANGED
@@ -1,5 +1,7 @@
1
- require 'simplecov'
2
- SimpleCov.start { add_filter "/test/" }
1
+ if ENV["COVERAGE"]
2
+ require 'simplecov'
3
+ SimpleCov.start { add_filter "/test/" }
4
+ end
3
5
 
4
6
  require 'minitest/autorun'
5
7
  require 'mocha/setup'
data/test/test_clock.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require_relative 'helper'
2
2
 
3
3
  class TestClock < Sidetiq::TestCase
4
- class FakeWorker;
4
+ class FakeWorker
5
+ def perform
6
+ end
5
7
  end
6
8
 
7
9
  def test_delegates_to_instance
@@ -61,5 +63,72 @@ class TestClock < Sidetiq::TestCase
61
63
  clock.tick
62
64
  clock.tick
63
65
  end
64
- end
65
66
 
67
+ class LastTickWorker
68
+ def perform last_tick
69
+ end
70
+ end
71
+
72
+ def test_enqueues_jobs_with_default_last_tick_arg_on_first_run
73
+ schedule = Sidetiq::Schedule.new(Sidetiq::Clock::START_TIME)
74
+ schedule.hourly
75
+
76
+ time = Time.local(2011, 1, 1, 1, 30)
77
+
78
+ clock.stubs(:gettime).returns(time, time + 3600)
79
+ clock.stubs(:schedules).returns(LastTickWorker => schedule)
80
+
81
+ expected_first_tick = time + 1800
82
+ expected_second_tick = expected_first_tick + 3600
83
+
84
+ LastTickWorker.expects(:perform_at).with(expected_first_tick, -1).once
85
+ LastTickWorker.expects(:perform_at).with(expected_second_tick, expected_first_tick.to_f).once
86
+
87
+ clock.tick
88
+ clock.tick
89
+ end
90
+
91
+ class LastAndScheduledTicksWorker
92
+ def perform last_tick, scheduled_tick
93
+ end
94
+ end
95
+
96
+ def test_enqueues_jobs_with_last_run_timestamp_and_next_run_timestamp
97
+ schedule = Sidetiq::Schedule.new(Sidetiq::Clock::START_TIME)
98
+ schedule.hourly
99
+
100
+ time = Time.local(2011, 1, 1, 1, 30)
101
+
102
+ clock.stubs(:gettime).returns(time, time + 3600)
103
+ clock.stubs(:schedules).returns(LastAndScheduledTicksWorker => schedule)
104
+
105
+ expected_first_tick = time + 1800
106
+ expected_second_tick = expected_first_tick + 3600
107
+
108
+ LastAndScheduledTicksWorker.expects(:perform_at).with(expected_first_tick, -1, expected_first_tick.to_f).once
109
+ clock.tick
110
+
111
+ LastAndScheduledTicksWorker.expects(:perform_at).with(expected_second_tick, expected_first_tick.to_f, expected_second_tick.to_f).once
112
+ clock.tick
113
+ end
114
+
115
+ class SplatArgsWorker
116
+ def perform arg1, *args
117
+ end
118
+ end
119
+
120
+ def test_enqueues_jobs_correctly_for_splat_args_perform_methods
121
+ schedule = Sidetiq::Schedule.new(Sidetiq::Clock::START_TIME)
122
+ schedule.hourly
123
+
124
+ time = Time.local(2011, 1, 1, 1, 30)
125
+
126
+ clock.stubs(:gettime).returns(time, time + 3600)
127
+ clock.stubs(:schedules).returns(SplatArgsWorker => schedule)
128
+
129
+ expected_first_tick = time + 1800
130
+
131
+ SplatArgsWorker.expects(:perform_at).with(expected_first_tick, -1, expected_first_tick.to_f).once
132
+ clock.tick
133
+ end
134
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'helper'
2
+
3
+ class TestWorker < Sidetiq::TestCase
4
+ class FakeWorker
5
+ include Sidetiq::Schedulable
6
+ end
7
+
8
+ def test_timestamps_for_new_worker
9
+ assert FakeWorker.last_scheduled_occurrence == -1
10
+ assert FakeWorker.next_scheduled_occurrence == -1
11
+ end
12
+
13
+ def test_timestamps_for_existing_worker
14
+ last_run = (Time.now - 100).to_f
15
+ next_run = (Time.now + 100).to_f
16
+
17
+ Sidekiq.redis do |redis|
18
+ redis.set "sidetiq:TestWorker::FakeWorker:last", last_run
19
+ redis.set "sidetiq:TestWorker::FakeWorker:next", next_run
20
+ end
21
+
22
+ assert FakeWorker.last_scheduled_occurrence == last_run
23
+ assert FakeWorker.next_scheduled_occurrence == next_run
24
+ end
25
+ end
metadata CHANGED
@@ -2,21 +2,21 @@
2
2
  name: sidetiq
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.5
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Tobias Svensson
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-06 00:00:00.000000000 Z
12
+ date: 2013-03-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  version_requirements: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 2.7.0
19
+ version: 2.8.0
20
20
  none: false
21
21
  name: sidekiq
22
22
  type: :runtime
@@ -25,14 +25,14 @@ dependencies:
25
25
  requirements:
26
26
  - - ~>
27
27
  - !ruby/object:Gem::Version
28
- version: 2.7.0
28
+ version: 2.8.0
29
29
  none: false
30
30
  - !ruby/object:Gem::Dependency
31
31
  version_requirements: !ruby/object:Gem::Requirement
32
32
  requirements:
33
33
  - - ~>
34
34
  - !ruby/object:Gem::Version
35
- version: 0.9.3
35
+ version: 0.10.0
36
36
  none: false
37
37
  name: ice_cube
38
38
  type: :runtime
@@ -41,9 +41,9 @@ dependencies:
41
41
  requirements:
42
42
  - - ~>
43
43
  - !ruby/object:Gem::Version
44
- version: 0.9.3
44
+ version: 0.10.0
45
45
  none: false
46
- description: High-resolution job scheduler for Sidekiq
46
+ description: Recurring jobs for Sidekiq
47
47
  email:
48
48
  - tob@tobiassvensson.co.uk
49
49
  executables: []
@@ -81,6 +81,7 @@ files:
81
81
  - test/test_schedule.rb
82
82
  - test/test_version.rb
83
83
  - test/test_web.rb
84
+ - test/test_worker.rb
84
85
  homepage: http://github.com/tobiassvn/sidetiq
85
86
  licenses:
86
87
  - MIT
@@ -105,7 +106,7 @@ rubyforge_project:
105
106
  rubygems_version: 1.8.23
106
107
  signing_key:
107
108
  specification_version: 3
108
- summary: High-resolution job scheduler for Sidekiq
109
+ summary: Recurring jobs for Sidekiq
109
110
  test_files:
110
111
  - test/helper.rb
111
112
  - test/test_clock.rb
@@ -115,4 +116,5 @@ test_files:
115
116
  - test/test_schedule.rb
116
117
  - test/test_version.rb
117
118
  - test/test_web.rb
119
+ - test/test_worker.rb
118
120
  has_rdoc: