pebbles-river 0.0.1 → 0.0.2

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: 0738174b6c9733edbe9524576e2ecf48ca2ad56e
4
- data.tar.gz: bdf513a26a16bd44be5a02dec8af1ac9b11f467f
3
+ metadata.gz: 32827f1f43724f8f2d5cf53943d89b519be5be11
4
+ data.tar.gz: 38db2f8b16ea69ca288e4f5c26c5debe1556356a
5
5
  SHA512:
6
- metadata.gz: 9068b048fa0c91a0640d15d77756dc742c3add7aa0a3106fd50178bf86e58717caa0d917497879b92394b596d74353ae8ca7a9b2ee3ceda8a68455e0d4a6689b
7
- data.tar.gz: 8f0747a995edcd03ca44e64122ef63187904263fe248a22417860a44f854da54ad40c4da1629a448868d0fca7f30ca1595648c64d70a1bb8788f488672fbef19
6
+ metadata.gz: 077a5f0d4d2dc0f2f02cd38b839b49bd14a5bb2201023e2fbdc3fc4f6e4ee6f2370fceba64d97e10e17fb609f14bb8f4af1601acbe8c439b3b23ebef4900b237
7
+ data.tar.gz: b2b43a50bdeba51c83dcdebec4bf94dce4096d239aabd7189954a19d6446c775949ca92eb0b78ca61453c4aab249676da214d425f8bc3d508c5eb01bca269a33
@@ -0,0 +1,17 @@
1
+ module Pebbles
2
+ module River
3
+
4
+ class ConnectionError < StandardError
5
+ attr_reader :connection_exception
6
+
7
+ def initialize(message, connection_exception = nil)
8
+ super(message)
9
+ @connection_exception = connection_exception
10
+ end
11
+ end
12
+
13
+ class ConnectFailure < ConnectionError; end
14
+ class SendFailure < ConnectionError; end
15
+
16
+ end
17
+ end
@@ -1,17 +1,6 @@
1
1
  module Pebbles
2
2
  module River
3
3
 
4
- class SendFailure < StandardError
5
-
6
- attr_reader :connection_exception
7
-
8
- def initialize(message, connection_exception = nil)
9
- super(message)
10
- @connection_exception = connection_exception
11
- end
12
-
13
- end
14
-
15
4
  class River
16
5
 
17
6
  attr_reader :environment
@@ -20,6 +9,7 @@ module Pebbles
20
9
  options = {environment: options} if options.is_a?(String) # Backwards compatibility
21
10
 
22
11
  @environment = (options[:environment] || ENV['RACK_ENV'] || 'development').dup.freeze
12
+ @last_connect_attempt = nil
23
13
  end
24
14
 
25
15
  def connected?
@@ -28,18 +18,26 @@ module Pebbles
28
18
 
29
19
  def connect
30
20
  unless connected?
31
- bunny.start
32
- bunny.qos
21
+ handle_connection_error do
22
+ bunny.start
23
+ bunny.qos
24
+ end
33
25
  end
34
26
  end
35
27
 
36
28
  def disconnect
37
- bunny.stop if connected?
29
+ if connected?
30
+ begin
31
+ bunny.stop
32
+ rescue *CONNECTION_EXCEPTIONS
33
+ # Ignore
34
+ end
35
+ end
38
36
  end
39
37
 
40
38
  def publish(options = {})
41
39
  connect
42
- handle_connection_error do
40
+ handle_connection_error(SendFailure) do
43
41
  exchange.publish(options.to_json,
44
42
  persistent: options.fetch(:persistent, true),
45
43
  key: Routing.routing_key_for(options.slice(:event, :uid)))
@@ -79,21 +77,32 @@ module Pebbles
79
77
  @exchange ||= bunny.exchange(exchange_name, EXCHANGE_OPTIONS.dup)
80
78
  end
81
79
 
82
- def handle_connection_error(&block)
83
- retry_until = nil
84
- begin
85
- yield
86
- rescue *CONNECTION_EXCEPTIONS => exception
87
- retry_until ||= Time.now + 4
88
- if Time.now < retry_until
89
- sleep(0.5)
80
+ def handle_connection_error(exception_klass = ConnectFailure, &block)
81
+ last_exception = nil
82
+ Timeout.timeout(MAX_RETRY_TIMEOUT) do
83
+ retry_until, retry_count = nil, 0
84
+ begin
85
+ yield
86
+ rescue *CONNECTION_EXCEPTIONS => exception
87
+ last_exception = exception
88
+ retry_count += 1
89
+ backoff(retry_count)
90
90
  retry
91
- else
92
- raise SendFailure.new(exception.message, exception)
93
91
  end
94
92
  end
93
+ rescue Timeout::Error => timeout
94
+ last_exception ||= timeout
95
+ raise exception_klass.new(last_exception.message, last_exception)
95
96
  end
96
97
 
98
+ def backoff(iteration)
99
+ sleep([(1.0 / 2.0 * (2.0 ** [30, iteration].min - 1.0)).ceil, MAX_BACKOFF_SECONDS].min)
100
+ end
101
+
102
+ MAX_RETRY_TIMEOUT = 10
103
+
104
+ MAX_BACKOFF_SECONDS = MAX_RETRY_TIMEOUT
105
+
97
106
  QUEUE_OPTIONS = {durable: true}.freeze
98
107
 
99
108
  EXCHANGE_OPTIONS = {type: :topic, durable: :true}.freeze
@@ -1,5 +1,5 @@
1
1
  module Pebbles
2
2
  module River
3
- VERSION = "0.0.1"
3
+ VERSION = '0.0.2'
4
4
  end
5
5
  end
data/lib/pebbles/river.rb CHANGED
@@ -6,6 +6,7 @@ require 'pebblebed/uid'
6
6
  require 'servolux'
7
7
 
8
8
  require_relative "river/version"
9
+ require_relative "river/errors"
9
10
  require_relative "river/message"
10
11
  require_relative "river/worker"
11
12
  require_relative "river/subscription"
@@ -114,6 +114,10 @@ describe Pebbles::River::River do
114
114
 
115
115
  subject.stub(:exchange) { exchange }
116
116
  subject.stub(:sleep) { }
117
+ Timeout.stub(:timeout) { |&block|
118
+ block.call
119
+ }
120
+ expect(Timeout).to receive(:timeout).at_least(1).times
117
121
 
118
122
  expect(subject).to receive(:sleep).at_least(2).times
119
123
 
@@ -126,17 +130,33 @@ describe Pebbles::River::River do
126
130
 
127
131
  CONNECTION_EXCEPTIONS.each do |exception_class|
128
132
  context "on permanent failure with #{exception_class}" do
129
- it "re-raises #{exception_class} wrapped in SendFailure exception" do
133
+ it "retries with exponential backoff until timeout and gives up with SendFailure" do
130
134
  exchange = double('exchange')
131
135
  exchange.stub(:publish) do
132
136
  raise exception_class.new
133
137
  end
134
-
135
138
  subject.stub(:exchange) { exchange }
136
- subject.stub(:sleep) { }
137
139
 
138
- expect(-> { subject.publish({event: 'explode', uid: 'thing:rspec$1'})}).to raise_error(
139
- Pebbles::River::SendFailure)
140
+ count, sleeps = 0, []
141
+ subject.stub(:sleep) { |t|
142
+ count += 1
143
+ if count >= 10
144
+ raise Timeout::Error
145
+ end
146
+ sleeps.push(t)
147
+ }
148
+
149
+ Timeout.stub(:timeout) { |&block|
150
+ block.call
151
+ }
152
+ expect(Timeout).to receive(:timeout).at_least(1).times
153
+
154
+ expect(-> { subject.publish({event: 'explode', uid: 'thing:rspec$1'})}).to raise_error do |e|
155
+ e.should be Pebbles::River::SendFailure
156
+ e.exception.should be exception_class
157
+ end
158
+
159
+ expect(sleeps[0, 9]).to eq [1, 2, 4, 8, 10, 10, 10, 10, 10]
140
160
  end
141
161
  end
142
162
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pebbles-river
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Staubo
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-15 00:00:00.000000000 Z
12
+ date: 2014-04-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pebblebed
@@ -137,6 +137,7 @@ files:
137
137
  - Rakefile
138
138
  - lib/pebbles/river.rb
139
139
  - lib/pebbles/river/compatibility.rb
140
+ - lib/pebbles/river/errors.rb
140
141
  - lib/pebbles/river/message.rb
141
142
  - lib/pebbles/river/river.rb
142
143
  - lib/pebbles/river/routing.rb