circuit_breakage 0.1.1 → 0.1.2

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
2
  SHA1:
3
- metadata.gz: 264f3254581c4bdf631cfb997e2a66a177a19d92
4
- data.tar.gz: 59a4cca4490e79cd3195c9a04b5f1a07a85c5e9a
3
+ metadata.gz: 9026fcf0d50eb38007dd97047ae181393d29a68b
4
+ data.tar.gz: ab1c9b2050bb6e6293e3347ce40fe5588ccbe179
5
5
  SHA512:
6
- metadata.gz: 64348b4b18f1f35e66a1c1b45993093b36cb31ea6ddd5b2e814f32898dfe1de1e869c976a777bea536e7efea2a9051734676821b85221b5c014c1e266f01ad72
7
- data.tar.gz: ae0ecdcedc18b541b266b6cf800a6710c487c24549f8bbbb56f8a75e8e2b56d4a9ce42e8591392ed43991b15df2e8b9b9faa6b0a6bb1935d16ba292508f2db68
6
+ metadata.gz: 7627acaac4f74fd5988531384648f43a35d27a3029e1342ea1b140a57a22f7dd31322162b918d8c5339d9ef655118c62020eed1f9c476dd2ed4f9aedbb759c02
7
+ data.tar.gz: c27a067b42074c300fbd4fc94e8f3d77d4f0a9ef7dc5bf2b4a4df5e66e646eea108a27920f9e8d18891f9c9b89f84df81de095f81a41b89ea2f24c261cf09c23
data/README.md CHANGED
@@ -33,7 +33,12 @@ end
33
33
  The unique feature of this particular Circuit Breaker gem is that it also
34
34
  supports shared state via Redis, using the SETNX and GETSET commands. This
35
35
  allows a number of circuit breakers running in separate processes to trip and
36
- un-trip in unison.
36
+ un-trip in unison. To be specific, when the circuit is closed, all processes
37
+ proceed as normal. When the circuit is open, all processes will raise
38
+ `CircuitBreakage::CircuitOpen`. When the circuit is open, but the retry
39
+ duration has expired (this is sometimes referred to as a "half open" state),
40
+ exactly *one* process will retry, and then either close the circuit or reset
41
+ the retry timer as appropriate.
37
42
 
38
43
  ```ruby
39
44
  connection = some_redis_connection
@@ -42,7 +47,3 @@ key = 'my_app/some_operation'
42
47
  breaker = CircuitBreakage::RedisBackedBreaker.new(connection, key, block)
43
48
  # Everything else is the same as above.
44
49
  ```
45
-
46
- So, if you have the same piece of code running on 27 instances across 3
47
- different servers, as soon as one trips, they all trip, and as soon as one
48
- resets, they all reset.
@@ -6,13 +6,14 @@ module CircuitBreakage
6
6
  class RedisBackedBreaker < Breaker
7
7
 
8
8
  # How long before we decide a lock-holder has crashed, in seconds.
9
- LOCK_TIMEOUT = DEFAULT_TIMEOUT + 10
9
+ DEFAULT_LOCK_TIMEOUT = DEFAULT_TIMEOUT + 10
10
10
 
11
- attr_reader :connection, :key
11
+ attr_reader :connection, :key, :lock_timeout
12
12
 
13
13
  def initialize(connection, key, block)
14
14
  @connection = connection
15
15
  @key = key
16
+ @lock_timeout = DEFAULT_LOCK_TIMEOUT
16
17
  super(block)
17
18
  end
18
19
 
@@ -38,22 +39,30 @@ module CircuitBreakage
38
39
 
39
40
  def try_with_mutex(lock, &block)
40
41
  mutex_key = "#{@key}/locks/#{lock}"
42
+ lock_timestamp = Time.now.to_i
41
43
 
42
- acquired = @connection.setnx(mutex_key, Time.now.to_i)
43
- if acquired == 0 # mutex is already acquired
44
- locked_at = @connection.get(mutex_key)
45
- raise CircuitBreakage::CircuitOpen if locked_at + LOCK_TIMEOUT < Time.now.to_i
46
- locked_at_second_check = @connection.getset(mutex_key, Time.now.to_i)
44
+ # See http://redis.io/commands/setnx for a walkthrough of this logic.
45
+ acquired = @connection.setnx(mutex_key, lock_timestamp)
46
+ if !acquired
47
+ locked_at = @connection.get(mutex_key).to_i
48
+ raise CircuitBreakage::CircuitOpen if !lock_expired(locked_at)
49
+ locked_at_second_check = @connection.getset(mutex_key, Time.now.to_i).to_i
47
50
  raise CircuitBreakage::CircuitOpen if locked_at_second_check != locked_at
48
- # If we get here, then the lock is expired, and we're the first to re-acquire it.
49
51
  end
50
52
 
51
53
  begin
52
54
  block.call
53
55
  ensure
54
- @connection.del(mutex_key)
56
+ if !lock_expired(lock_timestamp)
57
+ # There's a tiny unavoidable race condition here.
58
+ @connection.del(mutex_key)
59
+ end
55
60
  end
56
61
  end
57
62
 
63
+ def lock_expired(timestamp)
64
+ timestamp + @lock_timeout < Time.now.to_i
65
+ end
66
+
58
67
  end
59
68
  end
@@ -1,3 +1,3 @@
1
1
  module CircuitBreakage
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: circuit_breakage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Hyland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-11 00:00:00.000000000 Z
11
+ date: 2014-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler