sidetiq 0.3.5 → 0.3.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79f2b65ef53704beb2a8b0176b5a72a840b5df07
4
- data.tar.gz: 99004a1cb008a81248c80217603b041f6c44fcb8
3
+ metadata.gz: 1df64df09fdf5d7e87b13410a3a8b39c325fd70a
4
+ data.tar.gz: 43e79f2eb7c71065ba27f54cf8e36924c8575250
5
5
  SHA512:
6
- metadata.gz: 8e15758167ae4177fa2dcf367fb40b5a1070b4815f78105d0437df53a9f478b81a7ac6e9c3b01d6420fd08be1f230bb3464a808a72d6c42469e4c64ca9b1db3a
7
- data.tar.gz: 534269b3b8e92d1fd4ff9f3f15e82145fc180f9f976a697fa8a2ad4ba9220cae2e7a26b480eba5dea001dfdd43f1efd06d3c52aa9a50f3c804e47c8ae844a176
6
+ metadata.gz: 3b11cd2d90c41504bd9914ca3058cc242c9d4819d4d8550348e2326d85aaacbcf9293f02f5ac01b058be6b222f94eedbca5bafeba76c3cc231e168c1d63a964c
7
+ data.tar.gz: c5b583be6d96c52e8494bc790c406f5d06cd84e0e0b643e0ca14ef9eae1dc36b5e858cfde858a2e8891d3c11bb18d2982f4018370beba0451cccd54f1171930d
data/.travis.yml CHANGED
@@ -1,6 +1,39 @@
1
1
  language: ruby
2
+ branches:
3
+ only:
4
+ - master
5
+ services:
6
+ - redis-server
2
7
  rvm:
3
8
  - 1.9.3
4
9
  - 2.0.0
5
10
  - jruby-19mode
6
11
  - rbx-19mode
12
+ - ruby-head
13
+ - jruby-head
14
+ jdk:
15
+ - openjdk6
16
+ - openjdk7
17
+ - oraclejdk7
18
+ matrix:
19
+ exclude:
20
+ - rvm: 2.0.0
21
+ jdk: openjdk7
22
+ - rvm: 2.0.0
23
+ jdk: openjdk6
24
+ - rvm: 1.9.3
25
+ jdk: openjdk7
26
+ - rvm: 1.9.3
27
+ jdk: openjdk6
28
+ - rvm: rbx-19mode
29
+ jdk: openjdk7
30
+ - rvm: rbx-19mode
31
+ jdk: openjdk6
32
+ - rvm: ruby-head
33
+ jdk: openjdk7
34
+ - rvm: ruby-head
35
+ jdk: openjdk6
36
+ allow_failures:
37
+ - rvm: rbx-19mode
38
+ - rvm: ruby-head
39
+ - rvm: jruby-head
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ 0.3.6
2
+ -----
3
+
4
+ - Better protection against stale locks and race-conditions.
5
+
6
+ Locking is now done using WATCH/MULTI/EXEC/UNWATCH and additionally
7
+ includes a host and process specific identifier to prevent accidental
8
+ unlocks from other Sidekiq processes.
9
+
10
+ - Fix Sidetiq::Schedulable documentation.
11
+
1
12
  0.3.5
2
13
  -----
3
14
 
data/lib/sidetiq.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  require 'monitor'
3
3
  require 'ostruct'
4
4
  require 'singleton'
5
+ require 'socket'
5
6
 
6
7
  # gems
7
8
  require 'ice_cube'
@@ -10,6 +11,7 @@ require 'sidekiq'
10
11
  # internal
11
12
  require 'sidetiq/config'
12
13
  require 'sidetiq/clock'
14
+ require 'sidetiq/lock'
13
15
  require 'sidetiq/middleware'
14
16
  require 'sidetiq/schedule'
15
17
  require 'sidetiq/schedulable'
data/lib/sidetiq/clock.rb CHANGED
@@ -52,7 +52,7 @@ module Sidetiq
52
52
  tick = gettime
53
53
  mon_synchronize do
54
54
  schedules.each do |worker, sched|
55
- synchronize_clockworks(worker) do |redis|
55
+ Lock.new(worker).synchronize do |redis|
56
56
  if sched.backfill? && (last = worker.last_scheduled_occurrence) > 0
57
57
  last = Sidetiq.config.utc ? Time.at(last).utc : Time.at(last)
58
58
  sched.occurrences_between(last + 1, tick).each do |past_t|
@@ -150,24 +150,6 @@ module Sidetiq
150
150
  end
151
151
  end
152
152
 
153
- def synchronize_clockworks(klass)
154
- lock = "sidetiq:#{klass.name}:lock"
155
-
156
- Sidekiq.redis do |redis|
157
- if redis.setnx(lock, 1)
158
- Sidetiq.logger.debug "Sidetiq::Clock lock #{lock}"
159
-
160
- begin
161
- redis.pexpire(lock, Sidetiq.config.lock_expire)
162
- yield redis
163
- ensure
164
- redis.del(lock)
165
- Sidetiq.logger.debug "Sidetiq::Clock unlock #{lock}"
166
- end
167
- end
168
- end
169
- end
170
-
171
153
  def clock
172
154
  loop do
173
155
  sleep_time = time { yield }
@@ -0,0 +1,63 @@
1
+ module Sidetiq
2
+ class Lock # :nodoc: all
3
+ attr_reader :key, :timeout
4
+
5
+ OWNER = "#{Socket.gethostname}:#{Process.pid}"
6
+
7
+ def initialize(key, timeout = Sidetiq.config.lock_expire)
8
+ @key = key.kind_of?(Class) ? "sidetiq:#{key.name}:lock" : "sidetiq:#{key}:lock"
9
+ @timeout = timeout
10
+ end
11
+
12
+ def synchronize
13
+ Sidekiq.redis do |redis|
14
+ if lock(redis)
15
+ Sidetiq.logger.debug "Sidetiq::Clock lock #{key}"
16
+
17
+ begin
18
+ yield redis
19
+ ensure
20
+ unlock(redis)
21
+ Sidetiq.logger.debug "Sidetiq::Clock unlock #{key}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def lock(redis)
30
+ acquired = false
31
+
32
+ watch(redis, key) do
33
+ if !redis.exists(key)
34
+ acquired = !!redis.multi do |multi|
35
+ multi.psetex(key, timeout, OWNER)
36
+ end
37
+ end
38
+ end
39
+
40
+ acquired
41
+ end
42
+
43
+ def unlock(redis)
44
+ watch(redis, key) do
45
+ if redis.get(key) == OWNER
46
+ redis.multi do |multi|
47
+ multi.del(key)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def watch(redis, *args)
54
+ redis.watch(*args)
55
+
56
+ begin
57
+ yield
58
+ ensure
59
+ redis.unwatch
60
+ end
61
+ end
62
+ end
63
+ end
@@ -8,7 +8,7 @@ module Sidetiq
8
8
  # include Sidetiq::Schedulable
9
9
  #
10
10
  # # Daily at midnight
11
- # tiq { daily }
11
+ # recurrence { daily }
12
12
  # end
13
13
  module Schedulable
14
14
  module ClassMethods
@@ -47,7 +47,7 @@ module Sidetiq
47
47
  # include Sidekiq::Worker
48
48
  # include Sidetiq::Schedulable
49
49
  #
50
- # tiq { daily }
50
+ # recurrence { daily }
51
51
  #
52
52
  # def perform
53
53
  # end
@@ -8,7 +8,7 @@ module Sidetiq
8
8
  MINOR = 3
9
9
 
10
10
  # Public: Sidetiq patch level.
11
- PATCH = 5
11
+ PATCH = 6
12
12
 
13
13
  # Public: String representation of the current Sidetiq version.
14
14
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
data/test/test_lock.rb ADDED
@@ -0,0 +1,30 @@
1
+ require_relative 'helper'
2
+
3
+ class TestLock < Sidetiq::TestCase
4
+ def test_locking
5
+ lock_name = SecureRandom.hex(8)
6
+ key = SecureRandom.hex(8)
7
+
8
+ Sidekiq.redis do |redis|
9
+ redis.set(key, 0)
10
+
11
+ 5.times.map do
12
+ Thread.start do
13
+ locked(lock_name) do |r|
14
+ sleep 0.1
15
+ r.incr(key)
16
+ end
17
+ end
18
+ end.each(&:join)
19
+
20
+ assert_equal "1", redis.get(key)
21
+ end
22
+ end
23
+
24
+ def locked(lock_name)
25
+ Sidetiq::Lock.new(lock_name).synchronize do |redis|
26
+ yield redis
27
+ end
28
+ end
29
+ end
30
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidetiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Svensson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-29 00:00:00.000000000 Z
11
+ date: 2013-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -56,6 +56,7 @@ files:
56
56
  - lib/sidetiq.rb
57
57
  - lib/sidetiq/clock.rb
58
58
  - lib/sidetiq/config.rb
59
+ - lib/sidetiq/lock.rb
59
60
  - lib/sidetiq/middleware.rb
60
61
  - lib/sidetiq/schedulable.rb
61
62
  - lib/sidetiq/schedule.rb
@@ -73,6 +74,7 @@ files:
73
74
  - test/helper.rb
74
75
  - test/test_clock.rb
75
76
  - test/test_config.rb
77
+ - test/test_lock.rb
76
78
  - test/test_middleware.rb
77
79
  - test/test_schedule.rb
78
80
  - test/test_sidetiq.rb
@@ -113,6 +115,7 @@ test_files:
113
115
  - test/helper.rb
114
116
  - test/test_clock.rb
115
117
  - test/test_config.rb
118
+ - test/test_lock.rb
116
119
  - test/test_middleware.rb
117
120
  - test/test_schedule.rb
118
121
  - test/test_sidetiq.rb