nats-streaming 0.1.0 → 0.2.0

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: 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.