protobuf-nats 0.5.0 → 0.5.1

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: 1a5657826a433d857f0b08fa99f314df065af9be
4
- data.tar.gz: 0f4a0ec4a8c239e595251c2894f6e7d7bca8419a
3
+ metadata.gz: df808ca99a789024cfe3ab03071d1acafeef32a5
4
+ data.tar.gz: 6ba58e9150dd5b575a3b2b44e1f6ff06ff151681
5
5
  SHA512:
6
- metadata.gz: 541b8c84ffe66f575447b69c84198ed3eedebd996879fa9dc75b3ac210ed899dc526626d7a31f0a526ec68a8407f6a19d69248e6fb7dd4845ef2fc5d41e706a9
7
- data.tar.gz: 34e7f770187a6d14d3d88aa4637688c8a5c4fd48e6fcf9dbf7f1a635a3fe0c9e739ecabcb6ccee6c8f0db34a188f58632cff4cf56b06a5fa6459bcbe84393214
6
+ metadata.gz: 648a3e8de0b1ca89864eaef8b5076d25eb74508920c31d04883b1766bf09d6237aac15b3b55ba3b5e126d51ebc063468ebbdb92278a33ac8dd953e9c85e7b1ba
7
+ data.tar.gz: f4dba8e3b094b0e2f19a89d436ed209f792cd3696d07d6c6c931352202aceec5961980be83e45708d2a39c3d091e99754b3179f3776d0934464de44933c64627
data/README.md CHANGED
@@ -38,6 +38,11 @@ used to allow JVM based servers to warm-up slowly to prevent jolts in runtime pe
38
38
 
39
39
  `PB_NATS_CLIENT_ACK_TIMEOUT` - Seconds to wait for an ACK from the rpc server (default: 5 seconds).
40
40
 
41
+ `PB_NATS_CLIENT_NACK_BACKOFF_INTERVALS` - Array of milliseconds to wait between NACK retries (default: "0,1,3,5,10").
42
+
43
+ `PB_NATS_CLIENT_NACK_BACKOFF_SPLAY_LIMIT` - Milliseconds to add to the NACK backoff timeout to avoid bursting retries
44
+ (default: 10 milliseconds).
45
+
41
46
  `PB_NATS_CLIENT_RESPONSE_TIMEOUT` - Seconds to wait for a non-ACK response from the rpc server (default: 60 seconds).
42
47
 
43
48
  `PB_NATS_CLIENT_RECONNECT_DELAY` - If we detect a reconnect delay, we will wait this many seconds (default: the ACK timeout).
data/lib/protobuf/nats.rb CHANGED
@@ -19,7 +19,8 @@ module Protobuf
19
19
  end
20
20
 
21
21
  module Messages
22
- ACK = "\1".freeze
22
+ ACK = "\1".freeze
23
+ NACK = "\2".freeze
23
24
  end
24
25
 
25
26
  NatsClient = if defined? JRUBY_VERSION
@@ -29,6 +29,30 @@ module Protobuf
29
29
  end
30
30
  end
31
31
 
32
+ def nack_backoff_intervals
33
+ @nack_backoff_intervals ||= if ::ENV.key?("PB_NATS_CLIENT_NACK_BACKOFF_INTERVALS")
34
+ ::ENV["PB_NATS_CLIENT_NACK_BACKOFF_INTERVALS"].split(",").map(&:to_i)
35
+ else
36
+ [0, 1, 3, 5, 10]
37
+ end
38
+ end
39
+
40
+ def nack_backoff_splay
41
+ @nack_backoff_splay ||= if nack_backoff_splay_limit > 0
42
+ rand(nack_backoff_splay_limit)
43
+ else
44
+ 0
45
+ end
46
+ end
47
+
48
+ def nack_backoff_splay_limit
49
+ @nack_backoff_splay_limit ||= if ::ENV.key?("PB_NATS_CLIENT_NACK_BACKOFF_SPLAY_LIMIT")
50
+ ::ENV["PB_NATS_CLIENT_NACK_BACKOFF_SPLAY_LIMIT"].to_i
51
+ else
52
+ 10
53
+ end
54
+ end
55
+
32
56
  def reconnect_delay
33
57
  @reconnect_delay ||= if ::ENV.key?("PB_NATS_CLIENT_RECONNECT_DELAY")
34
58
  ::ENV["PB_NATS_CLIENT_RECONNECT_DELAY"].to_i
@@ -47,11 +71,28 @@ module Protobuf
47
71
 
48
72
  def send_request
49
73
  retries ||= 3
74
+ nack_retry ||= 0
75
+
76
+ loop do
77
+ setup_connection
78
+ request_options = {:timeout => response_timeout, :ack_timeout => ack_timeout}
79
+ @response_data = nats_request_with_two_responses(cached_subscription_key, @request_data, request_options)
80
+ case @response_data
81
+ when :ack_timeout
82
+ next if (retries -= 1) > 0
83
+ raise ::NATS::IO::Timeout
84
+ when :nack
85
+ interval = nack_backoff_intervals[nack_retry]
86
+ nack_retry += 1
87
+ raise ::NATS::IO::Timeout if interval.nil?
88
+ sleep((interval + nack_backoff_splay)/1000.0)
89
+ next
90
+ end
91
+ break
92
+ end
50
93
 
51
- setup_connection
52
- request_options = {:timeout => response_timeout, :ack_timeout => ack_timeout}
53
- @response_data = nats_request_with_two_responses(cached_subscription_key, @request_data, request_options)
54
94
  parse_response
95
+
55
96
  rescue ::Protobuf::Nats::Errors::IOException => error
56
97
  ::Protobuf::Nats.log_error(error)
57
98
 
@@ -59,10 +100,6 @@ module Protobuf
59
100
  logger.warn "An IOException was raised. We are going to sleep for #{delay} seconds."
60
101
  sleep delay
61
102
 
62
- retry if (retries -= 1) > 0
63
- raise
64
- rescue ::NATS::IO::Timeout
65
- # Nats response timeout.
66
103
  retry if (retries -= 1) > 0
67
104
  raise
68
105
  end
@@ -100,24 +137,19 @@ module Protobuf
100
137
 
101
138
  # Wait for reply
102
139
  first_message = nats.next_message(sub, ack_timeout)
103
- fail ::NATS::IO::Timeout if first_message.nil?
140
+ return :ack_timeout if first_message.nil?
141
+ return :nack if first_message.data == ::Protobuf::Nats::Messages::NACK
142
+
104
143
  second_message = nats.next_message(sub, timeout)
105
- fail ::NATS::IO::Timeout if second_message.nil?
144
+ fail(::NATS::IO::Timeout, subject) if second_message.nil?
106
145
 
107
146
  # Check messages
108
- response = nil
109
- has_ack = false
110
- case first_message.data
111
- when ::Protobuf::Nats::Messages::ACK then has_ack = true
112
- else response = first_message.data
113
- end
114
- case second_message.data
115
- when ::Protobuf::Nats::Messages::ACK then has_ack = true
116
- else response = second_message.data
117
- end
147
+ response = case ::Protobuf::Nats::Messages::ACK
148
+ when first_message.data then second_message.data
149
+ when second_message.data then first_message.data
150
+ end
118
151
 
119
- success = has_ack && response
120
- fail(::NATS::IO::Timeout, subject) unless success
152
+ fail(::NATS::IO::Timeout, subject) unless response
121
153
 
122
154
  response
123
155
  ensure
@@ -131,19 +163,16 @@ module Protobuf
131
163
  nats = Protobuf::Nats.client_nats_connection
132
164
  inbox = nats.new_inbox
133
165
  lock = ::Monitor.new
134
- ack_condition = lock.new_cond
135
- pb_response_condition = lock.new_cond
166
+ received = lock.new_cond
167
+ messages = []
168
+ first_message = nil
169
+ second_message = nil
136
170
  response = nil
171
+
137
172
  sid = nats.subscribe(inbox, :max => 2) do |message, _, _|
138
173
  lock.synchronize do
139
- case message
140
- when ::Protobuf::Nats::Messages::ACK
141
- ack_condition.signal
142
- next
143
- else
144
- response = message
145
- pb_response_condition.signal
146
- end
174
+ messages << message
175
+ received.signal
147
176
  end
148
177
  end
149
178
 
@@ -153,28 +182,31 @@ module Protobuf
153
182
 
154
183
  # Wait for the ACK from the server
155
184
  ack_timeout = opts[:ack_timeout] || 5
156
- with_timeout(ack_timeout) { ack_condition.wait(ack_timeout) }
185
+ received.wait(ack_timeout) if messages.empty?
186
+ first_message = messages.shift
187
+
188
+ return :ack_timeout if first_message.nil?
189
+ return :nack if first_message == ::Protobuf::Nats::Messages::NACK
157
190
 
158
191
  # Wait for the protobuf response
159
192
  timeout = opts[:timeout] || 60
160
- with_timeout(timeout) { pb_response_condition.wait(timeout) } unless response
193
+ received.wait(timeout) if messages.empty?
194
+ second_message = messages.shift
161
195
  end
162
196
 
197
+ response = case ::Protobuf::Nats::Messages::ACK
198
+ when first_message then second_message
199
+ when second_message then first_message
200
+ end
201
+
202
+ fail(::NATS::IO::Timeout, subject) unless response
203
+
163
204
  response
164
205
  ensure
165
206
  # Ensure we don't leave a subscription sitting around.
166
207
  nats.unsubscribe(sid) if response.nil?
167
208
  end
168
209
 
169
- # This is a copy of #with_nats_timeout
170
- def with_timeout(timeout)
171
- start_time = ::NATS::MonotonicTime.now
172
- yield
173
- end_time = ::NATS::MonotonicTime.now
174
- duration = end_time - start_time
175
- raise ::NATS::IO::Timeout.new("nats: timeout") if duration > timeout
176
- end
177
-
178
210
  end
179
211
 
180
212
  end
@@ -55,7 +55,12 @@ module Protobuf
55
55
  end
56
56
 
57
57
  # Publish an ACK to signal the server has picked up the work.
58
- nats.publish(reply_id, ::Protobuf::Nats::Messages::ACK) if was_enqueued
58
+ if was_enqueued
59
+ nats.publish(reply_id, ::Protobuf::Nats::Messages::ACK)
60
+ else
61
+ # TODO: Uncomment once we can roll out NACK messages without a 60 second timeout
62
+ # nats.publish(reply_id, ::Protobuf::Nats::Messages::NACK)
63
+ end
59
64
 
60
65
  was_enqueued
61
66
  end
@@ -1,5 +1,5 @@
1
1
  module Protobuf
2
2
  module Nats
3
- VERSION = "0.5.0"
3
+ VERSION = "0.5.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protobuf-nats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Dewitt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-26 00:00:00.000000000 Z
11
+ date: 2017-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: protobuf