krakow 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/CONTRIBUTING.md +25 -0
  3. data/LICENSE +13 -0
  4. data/README.md +62 -9
  5. data/krakow.gemspec +3 -1
  6. data/lib/krakow/command/cls.rb +3 -4
  7. data/lib/krakow/command/fin.rb +13 -4
  8. data/lib/krakow/command/identify.rb +22 -9
  9. data/lib/krakow/command/mpub.rb +14 -4
  10. data/lib/krakow/command/nop.rb +3 -4
  11. data/lib/krakow/command/pub.rb +15 -5
  12. data/lib/krakow/command/rdy.rb +13 -4
  13. data/lib/krakow/command/req.rb +14 -4
  14. data/lib/krakow/command/sub.rb +14 -4
  15. data/lib/krakow/command/touch.rb +13 -4
  16. data/lib/krakow/command.rb +25 -3
  17. data/lib/krakow/connection.rb +286 -60
  18. data/lib/krakow/connection_features/deflate.rb +26 -1
  19. data/lib/krakow/connection_features/snappy_frames.rb +34 -3
  20. data/lib/krakow/connection_features/ssl.rb +43 -1
  21. data/lib/krakow/connection_features.rb +1 -0
  22. data/lib/krakow/consumer.rb +162 -49
  23. data/lib/krakow/discovery.rb +17 -6
  24. data/lib/krakow/distribution/default.rb +61 -33
  25. data/lib/krakow/distribution.rb +107 -57
  26. data/lib/krakow/exceptions.rb +14 -0
  27. data/lib/krakow/frame_type/error.rb +13 -7
  28. data/lib/krakow/frame_type/message.rb +47 -4
  29. data/lib/krakow/frame_type/response.rb +14 -4
  30. data/lib/krakow/frame_type.rb +20 -8
  31. data/lib/krakow/producer/http.rb +95 -6
  32. data/lib/krakow/producer.rb +60 -17
  33. data/lib/krakow/utils/lazy.rb +99 -40
  34. data/lib/krakow/utils/logging.rb +11 -0
  35. data/lib/krakow/utils.rb +3 -0
  36. data/lib/krakow/version.rb +3 -1
  37. data/lib/krakow.rb +1 -0
  38. metadata +11 -11
  39. data/Gemfile +0 -5
  40. data/Gemfile.lock +0 -34
  41. data/test/spec.rb +0 -81
  42. data/test/specs/consumer.rb +0 -49
  43. data/test/specs/http_producer.rb +0 -123
  44. data/test/specs/producer.rb +0 -20
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## v0.3.0
2
+ * Include jitter to discovery interval lookups
3
+ * Typecast to String on PUB and MPUB
4
+ * Update exception types used for not implemented methods
5
+ * Add #confirm, #requeue, and #touch helpers to FrameType::Message instances
6
+ * Update Utils::Lazy implementation to be faster and clearer
7
+ * Add #safe_socket method on Connection to add stability
8
+ * Rebuild connections on error to prevent consumer teardown
9
+ * Reference connections without requirement of connection instance being alive
10
+ * Use #read over #recv on underlying socket to ensure proper number of bytes (thanks @thomas-holmes)
11
+ * Expand spec testing
12
+
13
+ A big thanks to @bschwartz for a large contribution in this changeset
14
+ including expanded spec coverage, message proxy helper methods, and
15
+ isolation of instability around Connection interactions.
16
+
1
17
  ## v0.2.2
2
18
  * Fix `nsqlookupd` attribute in `Consumer` and `Discovery`
3
19
 
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,25 @@
1
+ # Contributing
2
+
3
+ ## Branches
4
+
5
+ ### `master` branch
6
+
7
+ The master branch is the current stable released version.
8
+
9
+ ### `develop` branch
10
+
11
+ The develop branch is the current edge of development.
12
+
13
+ ## Pull requests
14
+
15
+ * https://github.com/chrisroberts/krakow/pulls
16
+
17
+ Please base all pull requests of the `develop` branch. Merges to
18
+ `master` only occur through the `develop` branch. Pull requests
19
+ based on `master` will likely be cherry picked.
20
+
21
+ ## Issues
22
+
23
+ Need to report an issue? Use the github issues:
24
+
25
+ * https://github.com/chrisroberts/krakow/issues
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2014 Chris Roberts
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md CHANGED
@@ -86,7 +86,8 @@ Krakow::Utils::Logging.level = :warn # :debug / :info / :warn / :error / :fatal
86
86
 
87
87
  ### Why is it forcing something called an "unready state"?
88
88
 
89
- Because forcing starvation is mean.
89
+ Because forcing starvation is mean. We don't want to be mean, so we'll ensure we
90
+ are consuming from all registered connections.
90
91
 
91
92
  ### I just want to connect to a producer, not a lookup service
92
93
 
@@ -133,8 +134,10 @@ consumer = Krakow::Consumer.new(
133
134
  :nsqlookupd => 'http://HOST:PORT',
134
135
  :topic => 'target',
135
136
  :channel => 'ship',
136
- :connection_features => {
137
- :tls_v1 => true
137
+ :connection_options => {
138
+ :features => {
139
+ :tls_v1 => true
140
+ }
138
141
  }
139
142
  )
140
143
  ```
@@ -148,8 +151,10 @@ consumer = Krakow::Consumer.new(
148
151
  :nsqlookupd => 'http://HOST:PORT',
149
152
  :topic => 'target',
150
153
  :channel => 'ship',
151
- :connection_features => {
152
- :snappy => true
154
+ :connection_options => {
155
+ :features => {
156
+ :snappy => true
157
+ }
153
158
  }
154
159
  )
155
160
  ```
@@ -163,23 +168,71 @@ consumer = Krakow::Consumer.new(
163
168
  :nsqlookupd => 'http://HOST:PORT',
164
169
  :topic => 'target',
165
170
  :channel => 'ship',
166
- :connection_features => {
167
- :deflate => true
171
+ :connection_options => {
172
+ :features => {
173
+ :deflate => true
174
+ }
168
175
  }
169
176
  )
170
177
  ```
171
178
 
179
+ ### I want to use TLS based authentication!
180
+
181
+ OK!
182
+
183
+ ```ruby
184
+ consumer = Krakow::Consumer.new(
185
+ :nsqlookupd => 'http://HOST:PORT',
186
+ :topic => 'target',
187
+ :channel => 'ship',
188
+ :connection_options => {
189
+ :features => {
190
+ :tls_v1 => true
191
+ },
192
+ :config => {
193
+ :ssl_context => {
194
+ :certificate => '/path/to/cert',
195
+ :key => '/path/to/key'
196
+ }
197
+ }
198
+ }
199
+ )
200
+ ```
201
+
202
+ ### Running the tests
203
+
204
+ Run them all!
205
+
206
+ ```
207
+ bundle exec ruby test/run.rb
208
+ ```
209
+
210
+ Or, run part of them:
211
+
212
+ ```
213
+ bundle exec ruby test/specs/consumer_spec.rb
214
+ ```
215
+
172
216
  ### It doesn't work
173
217
 
174
- Create an issue on the github repository.
218
+ Create an issue on the github repository
219
+ * https://github.com/chrisroberts/krakow/issues
175
220
 
176
221
  ### It doesn't do `x`
177
222
 
178
- Create an issue, or even better, send a PR. Just base it off the `develop` branch.
223
+ Create an issue, or even better, send a PR.
224
+ * https://github.com/chrisroberts/krakow/pulls
179
225
 
180
226
  # Info
181
227
  * Repo: https://github.com/chrisroberts/krakow
228
+ * Docs: http://code.chrisroberts.org/krakow
182
229
  * IRC: Freenode @ spox
183
230
 
184
231
  [1]: http://bitly.github.io/nsq/ "NSQ: a realtime distributed messaging platform"
185
232
  [2]: http://celluloid.io "Celluloid: Actor-based concurrent object framework for Ruby"
233
+
234
+ # Contributors
235
+
236
+ * Brendan Schwartz (@bschwartz)
237
+ * Thomas Holmes (@thomas-holmes)
238
+ * Jeremy Hinegardner (@copiousfreetime)
data/krakow.gemspec CHANGED
@@ -8,11 +8,13 @@ Gem::Specification.new do |s|
8
8
  s.email = 'code@chrisroberts.org'
9
9
  s.homepage = 'http://github.com/chrisroberts/krakow'
10
10
  s.description = 'NSQ ruby library'
11
+ s.license = 'Apache 2.0'
11
12
  s.require_path = 'lib'
12
13
  s.add_dependency 'celluloid-io'
13
14
  s.add_dependency 'http'
14
15
  s.add_dependency 'multi_json'
15
16
  s.add_dependency 'snappy'
16
17
  s.add_dependency 'digest-crc'
17
- s.files = Dir['**/*']
18
+ s.files = Dir['lib/**/*'] + %w(krakow.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
19
+ s.extra_rdoc_files = %w(CHANGELOG.md CONTRIBUTING.md LICENSE)
18
20
  end
@@ -1,11 +1,10 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # Close connection
3
6
  class Cls < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- end
8
-
9
8
  def to_line
10
9
  "#{name}\n"
11
10
  end
@@ -1,11 +1,20 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # Finish a message
3
6
  class Fin < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- required! :message_id
8
- end
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :message_id, String, :required => true
16
+
17
+ # @!endgroup
9
18
 
10
19
  def to_line
11
20
  "#{name} #{message_id}\n"
@@ -1,18 +1,31 @@
1
1
  require 'multi_json'
2
+ require 'krakow'
2
3
 
3
4
  module Krakow
4
5
  class Command
6
+ # Update client metadata on server / negotiate features
5
7
  class Identify < Command
6
8
 
7
- def initialize(args={})
8
- super
9
- required! :short_id, :long_id
10
- optional(
11
- :feature_negotiation, :heartbeat_interval, :output_buffer_size,
12
- :output_buffer_timeout, :tls_v1, :snappy, :deflate, :deflate_level,
13
- :sample_rate
14
- )
15
- end
9
+ # @!group Attributes
10
+
11
+ # @!macro [attach] attribute
12
+ # @!method $1
13
+ # @return [$2] the $1 $0
14
+ # @!method $1?
15
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
16
+ attribute :short_id, [String, Numeric], :required => true
17
+ attribute :long_id, [String, Numeric], :required => true
18
+ attribute :feature_negotiation, [TrueClass, FalseClass]
19
+ attribute :heartbeat_interval, Numeric
20
+ attribute :output_buffer_size, Integer
21
+ attribute :output_buffer_timeout, Integer
22
+ attribute :tls_v1, [TrueClass, FalseClass]
23
+ attribute :snappy, [TrueClass, FalseClass]
24
+ attribute :deflate, [TrueClass, FalseClass]
25
+ attribute :deflate_level, Integer
26
+ attribute :sample_rate, Integer
27
+
28
+ # @!endgroup
16
29
 
17
30
  def to_line
18
31
  filtered = Hash[*
@@ -1,14 +1,24 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # Publish multiple messages
3
6
  class Mpub < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- required! :topic_name, :messages
8
- end
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :topic_name, String, :required => true
16
+ attribute :messages, Array, :required => true
9
17
 
18
+ # @!endgroup
10
19
  def to_line
11
20
  formatted_messages = messages.map do |message|
21
+ message = message.to_s
12
22
  [message.length, message].pack('l>a*')
13
23
  end.join
14
24
  [name, ' ', topic_name, "\n", formatted_messages.length, messages.size, formatted_messages].pack('a*a*a*a*l>l>a*')
@@ -1,11 +1,10 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # No-op
3
6
  class Nop < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- end
8
-
9
8
  def to_line
10
9
  "#{name}\n"
11
10
  end
@@ -1,15 +1,25 @@
1
+ require 'krakow'
1
2
 
2
3
  module Krakow
3
4
  class Command
5
+ # Publish single message
4
6
  class Pub < Command
5
7
 
6
- def initialize(args={})
7
- super
8
- required! :topic_name, :message
9
- end
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :topic_name, String, :required => true
16
+ attribute :message, Object, :required => true
17
+
18
+ # @!endgroup
10
19
 
11
20
  def to_line
12
- [name, ' ', topic_name, "\n", message.length, message].pack('a*a*a*a*l>a*')
21
+ msg = message.to_s
22
+ [name, ' ', topic_name, "\n", msg.length, msg].pack('a*a*a*a*l>a*')
13
23
  end
14
24
 
15
25
  class << self
@@ -1,11 +1,20 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # Update RDY state
3
6
  class Rdy < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- required! :count
8
- end
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :count, Integer, :required => true
16
+
17
+ # @!endgroup
9
18
 
10
19
  def to_line
11
20
  "#{name} #{count}\n"
@@ -1,11 +1,21 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # Re-queue a message
3
6
  class Req < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- required! :message_id, :timeout
8
- end
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :message_id, String, :required => true
16
+ attribute :timeout, Integer, :required => true
17
+
18
+ # @!endgroup
9
19
 
10
20
  def to_line
11
21
  "#{name} #{message_id} #{self.timeout}\n"
@@ -1,11 +1,21 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # Subscribe to topic/channel
3
6
  class Sub < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- required! :topic_name, :channel_name
8
- end
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :topic_name, String, :required => true
16
+ attribute :channel_name, String, :required => true
17
+
18
+ # @!endgroup
9
19
 
10
20
  def to_line
11
21
  "#{name} #{topic_name} #{channel_name}\n"
@@ -1,11 +1,20 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
2
4
  class Command
5
+ # Reset timeout for in-flight message
3
6
  class Touch < Command
4
7
 
5
- def initialize(args={})
6
- super
7
- required! :message_id
8
- end
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :message_id, String, :required => true
16
+
17
+ # @!endgroup
9
18
 
10
19
  def to_line
11
20
  "#{name} #{message_id}\n"
@@ -1,20 +1,33 @@
1
+ require 'krakow'
2
+
1
3
  module Krakow
4
+ # Messages for sending to remote server
2
5
  class Command
3
6
 
4
7
  include Utils::Lazy
8
+ # @!parse include Utils::Lazy::InstanceMethods
9
+ # @!parse extend Utils::Lazy::ClassMethods
5
10
 
6
11
  class << self
7
12
 
13
+ # Allowed OK return values
14
+ #
15
+ # @return [Array<String>]
8
16
  def ok
9
17
  []
10
18
  end
11
19
 
20
+ # Allowed ERROR return values
21
+ #
22
+ # @return [Array<String>]
12
23
  def error
13
24
  []
14
25
  end
15
26
 
16
- # message:: Krakow::Message
17
- # Returns type of response expected (:none, :error_only, :required)
27
+ # Response type expected
28
+ #
29
+ # @param message [Krakow::Message] message to check
30
+ # @return [Symbol] response expected (:none, :error_only, :required)
18
31
  def response_for(message)
19
32
  if(message.class.ok.empty?)
20
33
  if(message.class.error.empty?)
@@ -29,23 +42,32 @@ module Krakow
29
42
 
30
43
  end
31
44
 
45
+ # @return [Krakow::FrameType] response to command
32
46
  attr_accessor :response
33
47
 
34
- # Return command name
48
+ # @return [String] name of command
35
49
  def name
36
50
  self.class.name.split('::').last.upcase
37
51
  end
38
52
 
39
53
  # Convert to line output
54
+ #
55
+ # @return [String] socket ready string
40
56
  def to_line(*args)
41
57
  raise NotImplementedError.new 'No line conversion method defined!'
42
58
  end
43
59
 
60
+ # Is response OK
61
+ #
62
+ # @return [TrueClass, FalseClass]
44
63
  def ok?(response)
45
64
  response = response.content if response.is_a?(FrameType)
46
65
  self.class.ok.include?(response)
47
66
  end
48
67
 
68
+ # Is response ERROR
69
+ #
70
+ # @return [TrueClass, FalseClass]
49
71
  def error?(response)
50
72
  response = response.content if response.is_a?(FrameType)
51
73
  self.class.error.include?(response)