nsq-krakow 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +84 -0
  3. data/CONTRIBUTING.md +25 -0
  4. data/LICENSE +13 -0
  5. data/README.md +249 -0
  6. data/krakow.gemspec +22 -0
  7. data/lib/krakow.rb +25 -0
  8. data/lib/krakow/command.rb +89 -0
  9. data/lib/krakow/command/auth.rb +36 -0
  10. data/lib/krakow/command/cls.rb +24 -0
  11. data/lib/krakow/command/fin.rb +31 -0
  12. data/lib/krakow/command/identify.rb +55 -0
  13. data/lib/krakow/command/mpub.rb +39 -0
  14. data/lib/krakow/command/nop.rb +14 -0
  15. data/lib/krakow/command/pub.rb +37 -0
  16. data/lib/krakow/command/rdy.rb +31 -0
  17. data/lib/krakow/command/req.rb +32 -0
  18. data/lib/krakow/command/sub.rb +36 -0
  19. data/lib/krakow/command/touch.rb +31 -0
  20. data/lib/krakow/connection.rb +417 -0
  21. data/lib/krakow/connection_features.rb +10 -0
  22. data/lib/krakow/connection_features/deflate.rb +82 -0
  23. data/lib/krakow/connection_features/snappy_frames.rb +129 -0
  24. data/lib/krakow/connection_features/ssl.rb +75 -0
  25. data/lib/krakow/consumer.rb +355 -0
  26. data/lib/krakow/consumer/queue.rb +151 -0
  27. data/lib/krakow/discovery.rb +57 -0
  28. data/lib/krakow/distribution.rb +229 -0
  29. data/lib/krakow/distribution/default.rb +159 -0
  30. data/lib/krakow/exceptions.rb +30 -0
  31. data/lib/krakow/frame_type.rb +66 -0
  32. data/lib/krakow/frame_type/error.rb +26 -0
  33. data/lib/krakow/frame_type/message.rb +74 -0
  34. data/lib/krakow/frame_type/response.rb +26 -0
  35. data/lib/krakow/ksocket.rb +102 -0
  36. data/lib/krakow/producer.rb +162 -0
  37. data/lib/krakow/producer/http.rb +224 -0
  38. data/lib/krakow/utils.rb +9 -0
  39. data/lib/krakow/utils/lazy.rb +125 -0
  40. data/lib/krakow/utils/logging.rb +43 -0
  41. data/lib/krakow/version.rb +4 -0
  42. metadata +184 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 27cdf9c39570b9a623614f40d8337722d76e3f5e
4
+ data.tar.gz: 96b61e498c662d817dddd4c4e560127b40724b27
5
+ SHA512:
6
+ metadata.gz: 30f924e9a9521464dab1afffa017bcf8e5cfc2661a66f056e18954b699f436b7222d0ee52ee603d35080d9cb29ffd429df207b61886585ea4b8e2c96a73cef10
7
+ data.tar.gz: 82e1d149c54b245df61b36babe1c94c318cc98c2573104900c41a7cdd7cffcee7ede68e15ee1511173a647df0bc6312c6986eaf3af5356a50687c4be8b152ea9
@@ -0,0 +1,84 @@
1
+ ## v0.4.2
2
+ * Update command subclass loading to be explicit (remove glob loading)
3
+
4
+ ## v0.4.0
5
+ * Prevent duplicate connection consumption loops (#23) (thanks @phopkins)
6
+ * Refactor connection implementation to prevent crashing blocks (#22) (thanks @phopkins)
7
+ * Properly calculate message sizes using byte length, not string length (#24) (thanks @phopkins)
8
+ * Clear responses prior to message transmission (#20) (thanks @i2amsam)
9
+ * Rebuild testing specs (not fully covered, but a good start)
10
+ * Consumer and Producer provide better connection failure recovery
11
+ * Fix in-flight issues within distribution on connection failures
12
+
13
+ _NOTE: Large portions of `Krakow::Connection` has been refactored_
14
+
15
+ ## v0.3.12
16
+ * Update Consumer#confirm and Consumer#touch to rescue out lookups and abort
17
+
18
+ ## v0.3.10
19
+ * Remove exclusive from Connection#init!
20
+
21
+ ## v0.3.8
22
+ * Remove locks and move logic to connection access
23
+ * Check for result within response prior to access (prevent slaying actor)
24
+
25
+ ## v0.3.6
26
+ * Allow `:options` key within `Producer` to set low level connection settings
27
+ * Make snappy an optional dependency
28
+ * Add initial support for authentication
29
+ * Update allowed types for optional notifier
30
+
31
+ ## v0.3.4
32
+ * Explicitly require version file (#11 and #12)
33
+
34
+ ## v0.3.2
35
+ * Fix return value from Connection#wait_time_for (#9) (thanks @AlphaB and @davidpelaez)
36
+
37
+ ## v0.3.0
38
+ * Include jitter to discovery interval lookups
39
+ * Typecast to String on PUB and MPUB
40
+ * Update exception types used for not implemented methods
41
+ * Add #confirm, #requeue, and #touch helpers to FrameType::Message instances
42
+ * Update Utils::Lazy implementation to be faster and clearer
43
+ * Add #safe_socket method on Connection to add stability
44
+ * Rebuild connections on error to prevent consumer teardown
45
+ * Reference connections without requirement of connection instance being alive
46
+ * Use #read over #recv on underlying socket to ensure proper number of bytes (thanks @thomas-holmes)
47
+ * Expand spec testing
48
+
49
+ A big thanks to @bschwartz for a large contribution in this changeset
50
+ including expanded spec coverage, message proxy helper methods, and
51
+ isolation of instability around Connection interactions.
52
+
53
+ ## v0.2.2
54
+ * Fix `nsqlookupd` attribute in `Consumer` and `Discovery`
55
+
56
+ ## v0.2.0
57
+ * Fix the rest of the namespacing issues
58
+ * Start adding some tests
59
+ * Use better exception types (NotImplementedError instead of NoMethodError)
60
+ * Be smart about responses within connections
61
+ * Add snappy support
62
+ * Add deflate support
63
+ * Add TLS support
64
+ * Prevent division by zero in distribution
65
+ * Add query methods to lazy helper (`attribute_name`?)
66
+
67
+ ## v0.1.2
68
+ * Include backoff support
69
+ * Remove `method_missing` magic
70
+ * Force message redistribution when connection removed
71
+ * Make discovery interval configurable
72
+ * Add support for HTTP producer
73
+ * Include namespace for custom exceptions #1 (thanks @copiousfreetime)
74
+ * Fix timeout method access in req command #1 (thanks @copiousfreetime)
75
+
76
+ ## v0.1.0
77
+ * Add logging support
78
+ * Include valid responses within commands
79
+ * Segregate responses from messages
80
+ * Manage connections in consumer (closed/reconnect)
81
+ * Add message distribution support
82
+
83
+ ## v0.0.1
84
+ * Initial release
@@ -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.
@@ -0,0 +1,249 @@
1
+ # Krakow
2
+
3
+ "KRAKOW! KRAKOW! Two direct hits!"
4
+
5
+ ## Spiff
6
+
7
+ ```ruby
8
+ require 'krakow'
9
+
10
+ producer = Krakow::Producer.new(
11
+ :host => 'HOST',
12
+ :port => 'PORT',
13
+ :topic => 'target'
14
+ )
15
+ producer.write('KRAKOW!', 'KRAKOW!')
16
+ ```
17
+
18
+ ## Zargons
19
+
20
+ ```ruby
21
+ require 'krakow'
22
+
23
+ consumer = Krakow::Consumer.new(
24
+ :nsqlookupd => 'http://HOST:PORT',
25
+ :topic => 'target',
26
+ :channel => 'ship'
27
+ )
28
+
29
+ consumer.queue.size # => 2
30
+ 2.times do
31
+ msg = consumer.queue.pop
32
+ puts "Received: #{msg}"
33
+ consumer.confirm(msg.message_id)
34
+ end
35
+ ```
36
+
37
+ ## What is this?
38
+
39
+ It's a Ruby library for [NSQ][1] using [Celluloid][2] under the hood.
40
+
41
+ ## Information and FAQ that I totally made up
42
+
43
+ ### Max in flight for consumers is 1, regardless of number of producers
44
+
45
+ Yep, that's right. Just one lowly message at a time. And that's probably not what
46
+ you want, so adjust it when you create your consumer instance.
47
+
48
+ ```ruby
49
+ require 'krakow'
50
+
51
+ consumer = Krakow::Consumer.new(
52
+ :nsqlookupd => 'http://HOST:PORT',
53
+ :topic => 'target',
54
+ :channel => 'ship',
55
+ :max_in_flight => 30
56
+ )
57
+ ```
58
+
59
+ ### Clean up after yourself
60
+
61
+ Since [Celluloid][2] is in use under the hood, and the main interaction points are
62
+ Actors (`Consumer` and `Producer`) you'll need to be sure you clean up. This simply
63
+ means terminating the instance (since falling out of scope will not cause it to be
64
+ garbage collected).
65
+
66
+ ```ruby
67
+ consumer = Krakow::Consumer.new(
68
+ :nsqlookupd => 'http://HOST:PORT',
69
+ :topic => 'target',
70
+ :channel => 'ship',
71
+ :max_in_flight => 30
72
+ )
73
+
74
+ # do stuff
75
+
76
+ consumer.terminate
77
+ ```
78
+
79
+ ### Please make it shutup!
80
+
81
+ Sure:
82
+
83
+ ```ruby
84
+ Krakow::Utils::Logging.level = :warn # :debug / :info / :warn / :error / :fatal
85
+ ```
86
+
87
+ ### Why is it forcing something called an "unready state"?
88
+
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.
91
+
92
+ ### I just want to connect to a producer, not a lookup service
93
+
94
+ Fine!
95
+
96
+ ```ruby
97
+ consumer = Krakow::Consumer.new(
98
+ :host => 'HOST',
99
+ :port => 'PORT',
100
+ :topic => 'target',
101
+ :channel => 'ship',
102
+ :max_in_flight => 30
103
+ )
104
+ ```
105
+ Great for testing, but you really should use the lookup service in the "real world"
106
+
107
+ ### Backoff support
108
+
109
+ NSQ has this backoff notion. It's pretty swell. Basically, if messages from a specific
110
+ producer get re-queued (fail), then message consumption from that producer is halted,
111
+ and slowly ramped back up. It gives time for downstream issues to work themselves out,
112
+ if possible, instead of just keeping the firehose of gasoline on. Neat.
113
+
114
+ By default backoff support is disabled. It can be enabled by setting the `:backoff_interval`
115
+ when constructing the `Consumer`. The interval is in seconds (and yes, floats are allowed
116
+ for sub-second intervals):
117
+
118
+ ```ruby
119
+ consumer = Krakow::Consumer.new(
120
+ :nsqlookupd => 'http://HOST:PORT',
121
+ :topic => 'target',
122
+ :channel => 'ship',
123
+ :max_in_flight => 30,
124
+ :backoff_interval => 1
125
+ )
126
+ ```
127
+
128
+ ### I need TLS!
129
+
130
+ OK!
131
+
132
+ ```ruby
133
+ consumer = Krakow::Consumer.new(
134
+ :nsqlookupd => 'http://HOST:PORT',
135
+ :topic => 'target',
136
+ :channel => 'ship',
137
+ :connection_options => {
138
+ :features => {
139
+ :tls_v1 => true
140
+ }
141
+ }
142
+ )
143
+ ```
144
+
145
+ ### I need Snappy compression!
146
+
147
+ OK!
148
+
149
+ ```ruby
150
+ consumer = Krakow::Consumer.new(
151
+ :nsqlookupd => 'http://HOST:PORT',
152
+ :topic => 'target',
153
+ :channel => 'ship',
154
+ :connection_options => {
155
+ :features => {
156
+ :snappy => true
157
+ }
158
+ }
159
+ )
160
+ ```
161
+
162
+ *NOTE*: snappy support requires the snappy
163
+ gem and is not provided by default, so you
164
+ will need to ensure it is installed either
165
+ on the system, or within the bundle.
166
+
167
+ ### I need Deflate compression!
168
+
169
+ OK!
170
+
171
+ ```ruby
172
+ consumer = Krakow::Consumer.new(
173
+ :nsqlookupd => 'http://HOST:PORT',
174
+ :topic => 'target',
175
+ :channel => 'ship',
176
+ :connection_options => {
177
+ :features => {
178
+ :deflate => true
179
+ }
180
+ }
181
+ )
182
+ ```
183
+
184
+ ### I want to use TLS based authentication!
185
+
186
+ OK!
187
+
188
+ ```ruby
189
+ consumer = Krakow::Consumer.new(
190
+ :nsqlookupd => 'http://HOST:PORT',
191
+ :topic => 'target',
192
+ :channel => 'ship',
193
+ :connection_options => {
194
+ :features => {
195
+ :tls_v1 => true
196
+ },
197
+ :config => {
198
+ :ssl_context => {
199
+ :certificate => '/path/to/cert',
200
+ :key => '/path/to/key'
201
+ }
202
+ }
203
+ }
204
+ )
205
+ ```
206
+
207
+ ### Running the tests
208
+
209
+ Run them all!
210
+
211
+ ```
212
+ bundle exec ruby test/run.rb
213
+ ```
214
+
215
+ Or, run part of them:
216
+
217
+ ```
218
+ bundle exec ruby test/specs/consumer_spec.rb
219
+ ```
220
+
221
+ *NOTE*: the specs expect that `nsqd` and `nsqlookupd` are available in `$PATH`
222
+
223
+ ### It doesn't work
224
+
225
+ Create an issue on the github repository
226
+
227
+ * https://github.com/chrisroberts/krakow/issues
228
+
229
+ ### It doesn't do `x`
230
+
231
+ Create an issue, or even better, send a PR.
232
+
233
+ * https://github.com/chrisroberts/krakow/pulls
234
+
235
+ # Info
236
+ * Repo: https://github.com/chrisroberts/krakow
237
+ * Docs: http://code.chrisroberts.org/krakow
238
+ * IRC: Freenode @ spox
239
+
240
+ [1]: http://bitly.github.io/nsq/ "NSQ: a realtime distributed messaging platform"
241
+ [2]: http://celluloid.io "Celluloid: Actor-based concurrent object framework for Ruby"
242
+
243
+ # Contributors
244
+
245
+ * Pete Hopkins (@phopkins)
246
+ * Sam Phillips (@i2amsam)
247
+ * Brendan Schwartz (@bschwartz)
248
+ * Thomas Holmes (@thomas-holmes)
249
+ * Jeremy Hinegardner (@copiousfreetime)
@@ -0,0 +1,22 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + '/lib/'
2
+ require 'krakow/version'
3
+ Gem::Specification.new do |s|
4
+ s.name = 'nsq-krakow'
5
+ s.version = Krakow::VERSION.version
6
+ s.summary = 'NSQ library'
7
+ s.author = 'Chris Roberts'
8
+ s.email = 'code@chrisroberts.org'
9
+ s.homepage = 'http://github.com/chrisroberts/krakow'
10
+ s.description = 'NSQ ruby library'
11
+ s.license = 'Apache 2.0'
12
+ s.require_path = 'lib'
13
+ s.add_runtime_dependency 'celluloid', '~> 0.16.0'
14
+ s.add_runtime_dependency 'http'
15
+ s.add_runtime_dependency 'multi_json'
16
+ s.add_runtime_dependency 'digest-crc'
17
+ s.add_development_dependency 'childprocess'
18
+ s.add_development_dependency 'snappy'
19
+ s.add_development_dependency 'minitest'
20
+ s.files = Dir['lib/**/*'] + %w(krakow.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
21
+ s.extra_rdoc_files = %w(CHANGELOG.md CONTRIBUTING.md LICENSE)
22
+ end
@@ -0,0 +1,25 @@
1
+ require 'celluloid'
2
+
3
+ if(ENV['DEBUG'])
4
+ Celluloid.task_class = Celluloid::TaskThread
5
+ end
6
+
7
+ require 'celluloid/autostart'
8
+ require 'multi_json'
9
+
10
+ # NSQ client and producer library
11
+ module Krakow
12
+ autoload :Command, 'krakow/command'
13
+ autoload :Connection, 'krakow/connection'
14
+ autoload :ConnectionFeatures, 'krakow/connection_features'
15
+ autoload :Consumer, 'krakow/consumer'
16
+ autoload :Discovery, 'krakow/discovery'
17
+ autoload :Distribution, 'krakow/distribution'
18
+ autoload :Error, 'krakow/exceptions'
19
+ autoload :FrameType, 'krakow/frame_type'
20
+ autoload :Ksocket, 'krakow/ksocket'
21
+ autoload :Producer, 'krakow/producer'
22
+ autoload :Utils, 'krakow/utils'
23
+ end
24
+
25
+ require 'krakow/version'
@@ -0,0 +1,89 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ # Messages for sending to remote server
5
+ class Command
6
+
7
+ include Utils::Lazy
8
+ # @!parse include Utils::Lazy::InstanceMethods
9
+ # @!parse extend Utils::Lazy::ClassMethods
10
+
11
+ autoload :Auth, 'krakow/command/auth'
12
+ autoload :Cls, 'krakow/command/cls'
13
+ autoload :Fin, 'krakow/command/fin'
14
+ autoload :Identify, 'krakow/command/identify'
15
+ autoload :Mpub, 'krakow/command/mpub'
16
+ autoload :Nop, 'krakow/command/nop'
17
+ autoload :Pub, 'krakow/command/pub'
18
+ autoload :Rdy, 'krakow/command/rdy'
19
+ autoload :Req, 'krakow/command/req'
20
+ autoload :Sub, 'krakow/command/sub'
21
+ autoload :Touch, 'krakow/command/touch'
22
+
23
+ class << self
24
+
25
+ # Allowed OK return values
26
+ #
27
+ # @return [Array<String>]
28
+ def ok
29
+ []
30
+ end
31
+
32
+ # Allowed ERROR return values
33
+ #
34
+ # @return [Array<String>]
35
+ def error
36
+ []
37
+ end
38
+
39
+ # Response type expected
40
+ #
41
+ # @param message [Krakow::Message] message to check
42
+ # @return [Symbol] response expected (:none, :error_only, :required)
43
+ def response_for(message)
44
+ if(message.class.ok.empty?)
45
+ if(message.class.error.empty?)
46
+ :none
47
+ else
48
+ :error_only
49
+ end
50
+ else
51
+ :required
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ # @return [Krakow::FrameType] response to command
58
+ attr_accessor :response
59
+
60
+ # @return [String] name of command
61
+ def name
62
+ self.class.name.split('::').last.upcase
63
+ end
64
+
65
+ # Convert to line output
66
+ #
67
+ # @return [String] socket ready string
68
+ def to_line(*args)
69
+ raise NotImplementedError.new 'No line conversion method defined!'
70
+ end
71
+
72
+ # Is response OK
73
+ #
74
+ # @return [TrueClass, FalseClass]
75
+ def ok?(response)
76
+ response = response.content if response.is_a?(FrameType)
77
+ self.class.ok.include?(response)
78
+ end
79
+
80
+ # Is response ERROR
81
+ #
82
+ # @return [TrueClass, FalseClass]
83
+ def error?(response)
84
+ response = response.content if response.is_a?(FrameType)
85
+ self.class.error.include?(response)
86
+ end
87
+
88
+ end
89
+ end