nats-streaming 0.1.0 → 0.2.0

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: 2b4619f24307110860a56b03d04b15be8c8f35b3
4
- data.tar.gz: 79e03889f056cfbd5fb64491c236ffe66b99f4e9
3
+ metadata.gz: b75b9c85c86a9586a19f5b9a7b742f69f4b230df
4
+ data.tar.gz: fac785865b216da75a7e1255e6b20dd33bb1a7da
5
5
  SHA512:
6
- metadata.gz: 64d4045d951790d2207aa80cc5732b0f08078f7fe244f5ea033663c74a70f901d78e5015758300fa198a7fb35457fb70ad0f5a311ca0be83a6ccaae37ef745f4
7
- data.tar.gz: 7cbbcef0b8ab55e53b8ca2124427ff41f77356eb326d775106249ea58c880cea88dd065657df323289abea2e7dbae517cb6383be4a26133a35857355b6cfbafc
6
+ metadata.gz: 7b1738c21713867a7f3d14405620539fb6e8cdc6306665bd2cdce3a6e6c9e19e46a0c4037c1408e1d09fc63d95914cdea78ec0b727ab18be405ffe7d783424a1
7
+ data.tar.gz: 33a9106e621be55c92dbaa585f31865755d6414e012fb6341e402d896d2ae66b4e3336418701ab2ef515048463393450868fb72a58986d98f766469782ff8bd5
@@ -2,6 +2,7 @@ require 'stan/pb/protocol.pb'
2
2
  require 'nats/io/client'
3
3
  require 'securerandom'
4
4
  require 'monitor'
5
+ require 'stan/version'
5
6
 
6
7
  module STAN
7
8
 
@@ -24,12 +25,24 @@ module STAN
24
25
  # Errors
25
26
  class Error < StandardError; end
26
27
 
27
- # When we detect we cannot connect to the server
28
+ # When we get an error from the server during connect request
28
29
  class ConnectError < Error; end
29
30
 
31
+ # When we cannot connect due to an invalid connection
32
+ class BadConnectionError < Error; end
33
+
30
34
  # When we detect we have a request timeout
31
35
  class TimeoutError < Error; end
32
36
 
37
+ # When we detect we cannot connect to NATS Streaming
38
+ class ConnectReqTimeoutError < TimeoutError; end
39
+
40
+ # When we timeout making a subscription
41
+ class SubReqTimeoutError < TimeoutError; end
42
+
43
+ # When we timeout closing session with NATS Streaming
44
+ class CloseReqTimeoutError < TimeoutError; end
45
+
33
46
  class Client
34
47
  include MonitorMixin
35
48
 
@@ -117,15 +130,15 @@ module STAN
117
130
  end
118
131
 
119
132
  # If no connection to NATS present at this point then bail already
120
- raise ConnectError.new("stan: invalid connection to nats") unless @nats
133
+ raise BadConnectionError.new("stan: invalid connection to nats") unless @nats
121
134
 
122
135
  # Heartbeat subscription
123
136
  @hb_inbox = (STAN.create_inbox).freeze
124
137
 
125
138
  # Setup acks and heartbeats processing callbacks
126
- @hb_inbox_sid = nats.subscribe(@hb_inbox) { |raw| process_heartbeats(raw) }
127
- @ack_subject_sid = nats.subscribe(@ack_subject) { |raw| process_ack(raw) }
128
- nats.flush
139
+ @hb_inbox_sid = nats.subscribe(@hb_inbox) { |raw, reply, subject| process_heartbeats(raw, reply, subject) }
140
+ @ack_subject_sid = nats.subscribe(@ack_subject) { |raw, reply, subject| process_ack(raw, reply, subject) }
141
+ nats.flush(options[:connect_timeout])
129
142
 
130
143
  # Initial connect request to discover subjects to be used
131
144
  # for communicating with STAN.
@@ -135,8 +148,24 @@ module STAN
135
148
  })
136
149
 
137
150
  # TODO: Check for error and bail if required
138
- raw = nats.request(@discover_subject, req.to_proto, timeout: options[:connect_timeout])
151
+ begin
152
+ raw = nats.request(@discover_subject, req.to_proto, timeout: options[:connect_timeout])
153
+ rescue NATS::IO::Timeout
154
+ raise ConnectReqTimeoutError.new("stan: failed connecting to '#{@cluster_id}'")
155
+ end
156
+
139
157
  resp = STAN::Protocol::ConnectResponse.decode(raw.data)
158
+ unless resp.error.empty?
159
+ # We didn't really connect but we call closing in order to
160
+ # cleanup any other present state.
161
+ # FIXME: Errors happening here should be reported async
162
+ close rescue nil
163
+
164
+ raise ConnectError.new(resp.error)
165
+ end
166
+
167
+ # Capture communication channels to STAN only when there
168
+ # have not been any errors when connecting.
140
169
  @pub_prefix = resp.pubPrefix.freeze
141
170
  @sub_req_subject = resp.subRequests.freeze
142
171
  @unsub_req_subject = resp.unsubRequests.freeze
@@ -155,6 +184,8 @@ module STAN
155
184
 
156
185
  # Publish will publish to the cluster and wait for an ack
157
186
  def publish(subject, payload, opts={}, &blk)
187
+ raise BadConnectionError.new unless @pub_prefix
188
+
158
189
  stan_subject = "#{@pub_prefix}.#{subject}"
159
190
  future = nil
160
191
  guid = STAN.create_guid
@@ -224,6 +255,8 @@ module STAN
224
255
 
225
256
  # Create subscription which dispatches messages to callback asynchronously
226
257
  def subscribe(subject, opts={}, &cb)
258
+ raise BadConnectionError.new unless @sub_req_subject
259
+
227
260
  sub_options = {}
228
261
  sub_options.merge!(opts)
229
262
  sub_options[:ack_wait] ||= DEFAULT_ACK_WAIT
@@ -239,9 +272,10 @@ module STAN
239
272
  # Listen for actual messages
240
273
  sid = nats.subscribe(sub.inbox) { |raw, reply, subject| process_msg(raw, reply, subject) }
241
274
  sub.sid = sid
242
- nats.flush
275
+ nats.flush(options[:connect_timeout])
243
276
 
244
277
  # Create the subscription request announcing the inbox on which
278
+
245
279
  # we have made the NATS subscription for processing messages.
246
280
  # First, we normalize customized subscription options before
247
281
  # encoding to protobuf.
@@ -265,7 +299,7 @@ module STAN
265
299
  end
266
300
 
267
301
  unless response.error.empty?
268
- # FIXME: Error handling on unsubscribe
302
+ # FIXME: Error handling on unsubscribe should be async
269
303
  nats.unsubscribe(sub.sid)
270
304
  raise Error.new(response.error)
271
305
  end
@@ -275,23 +309,31 @@ module STAN
275
309
 
276
310
  return sub
277
311
  end
312
+ rescue NATS::IO::Timeout
313
+ raise SubReqTimeoutError.new("stan: subscribe request timeout on '#{subject}'")
278
314
  end
279
315
 
280
316
  # Close wraps us the session with the NATS Streaming server
281
317
  def close
282
- req = STAN::Protocol::CloseRequest.new(clientID: @client_id)
283
- raw = nats.request(@close_req_subject, req.to_proto)
284
-
285
- resp = STAN::Protocol::CloseResponse.decode(raw.data)
286
- unless resp.error.empty?
287
- raise Error.new(resp.error)
318
+ # Send close when going away only if we have been able to successfully connect
319
+ if @close_req_subject
320
+ req = STAN::Protocol::CloseRequest.new(clientID: @client_id)
321
+ raw = nats.request(@close_req_subject, req.to_proto, timeout: options[:connect_timeout])
322
+
323
+ resp = STAN::Protocol::CloseResponse.decode(raw.data)
324
+ unless resp.error.empty?
325
+ raise Error.new(resp.error)
326
+ end
288
327
  end
289
328
 
329
+ # If we do not even have a connection then return already...
330
+ return unless @nats
331
+
290
332
  # TODO: If connection to nats was borrowed then we should
291
333
  # unsubscribe from all topics from STAN. If not borrowed
292
334
  # and we own the connection, then we just close.
293
335
  begin
294
- # Remove all present subscriptions
336
+ # Remove all related subscriptions for STAN
295
337
  @sub_map.each_pair do |_, sub|
296
338
  nats.unsubscribe(sub.sid)
297
339
  end
@@ -299,8 +341,9 @@ module STAN
299
341
  # Finally, remove the core subscriptions for STAN
300
342
  nats.unsubscribe(@hb_inbox_sid)
301
343
  nats.unsubscribe(@ack_subject_sid)
302
- rescue => e
303
- # TODO: Async error handling
344
+ nats.flush(options[:connect_timeout])
345
+ rescue NATS::IO::Timeout
346
+ raise CloseReqTimeoutError.new("stan: close request timeout")
304
347
  ensure
305
348
  if @borrowed_nats_connection
306
349
  @nats = nil
@@ -322,10 +365,14 @@ module STAN
322
365
  end
323
366
  end
324
367
 
368
+ def to_s
369
+ %Q(#<STAN::Client @cluster_id="#{@cluster_id}" @client_id="#{@client_id}">)
370
+ end
371
+
325
372
  private
326
373
 
327
374
  # Process received publishes acks
328
- def process_ack(data)
375
+ def process_ack(data, reply, subject)
329
376
  # FIXME: This should handle errors asynchronously in case there are any
330
377
 
331
378
  # Process ack
@@ -392,6 +439,7 @@ module STAN
392
439
  sub_opts[:qGroup] = opts[:queue] if opts[:queue]
393
440
  sub_opts[:durableName] = opts[:durable_name] if opts[:durable_name]
394
441
 
442
+ # Must announce the clientID as part of the protocol in each subscription
395
443
  sub_opts[:clientID] = @client_id
396
444
  sub_opts[:maxInFlight] = opts[:max_inflight]
397
445
  sub_opts[:ackWaitInSecs] = opts[:ack_wait] || opts[:ack_timeout]
@@ -440,6 +488,10 @@ module STAN
440
488
  @durable_name = opts[:durable_name]
441
489
  end
442
490
 
491
+ def to_s
492
+ %Q(#<STAN::Subscription @subject="#{@subject}" @queue="#{@queue}" @durable_name="#{@durable_name}" @inbox="#{@inbox}" @ack_inbox="#{@ack_inbox}" @sid=#{@sid}>)
493
+ end
494
+
443
495
  # Unsubscribe removes interest in the subscription.
444
496
  # For durables, it means that the durable interest is also removed from
445
497
  # the server. Restarting a durable with the same name will not resume
@@ -508,15 +560,25 @@ module STAN
508
560
  end
509
561
 
510
562
  # Data holder for sent messages
511
- # It should have an Ack method as well to reply back?
512
- Msg = Struct.new(:proto, :sub) do
563
+ # FIXME: It should have an Ack method as well to reply back?
564
+ ::STAN::Msg = Struct.new(:proto, :sub) do
513
565
  def data
514
566
  self.proto.data
515
567
  end
516
568
  def sequence
517
569
  self.proto.sequence
518
570
  end
571
+ def timestamp
572
+ self.proto.timestamp
573
+ end
574
+ def time
575
+ self.proto.timestamp / 1_000_000_000.0
576
+ end
519
577
  alias seq sequence
578
+
579
+ def to_s
580
+ "#<STAN::Msg sequence=#{self.sequence} time=#{self.time.to_f} data=#{self.data}>"
581
+ end
520
582
  end
521
583
 
522
584
  class << self
@@ -1,3 +1,3 @@
1
1
  module STAN
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nats-streaming
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Waldemar Quevedo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-30 00:00:00.000000000 Z
11
+ date: 2017-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nats-pure
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: google-protobuf
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '3'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '3'
41
41
  description: Ruby client for the NATS Streaming messaging system.
42
42
  email:
43
43
  - wally@apcera.com
@@ -68,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
68
  version: '0'
69
69
  requirements: []
70
70
  rubyforge_project:
71
- rubygems_version: 2.5.2
71
+ rubygems_version: 2.6.8
72
72
  signing_key:
73
73
  specification_version: 4
74
74
  summary: Ruby client for the NATS Streaming messaging system.