fastly_nsq 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +1 -1
  5. data/Gemfile +0 -2
  6. data/README.md +56 -14
  7. data/Rakefile +4 -9
  8. data/examples/Rakefile +36 -0
  9. data/fastly_nsq.gemspec +1 -2
  10. data/lib/fastly_nsq/message_queue/consumer.rb +5 -1
  11. data/lib/fastly_nsq/message_queue/listener.rb +27 -4
  12. data/lib/fastly_nsq/message_queue/producer.rb +5 -1
  13. data/lib/fastly_nsq/rake_task.rb +40 -0
  14. data/lib/fastly_nsq/sample_message_processor.rb +16 -12
  15. data/lib/fastly_nsq/version.rb +1 -1
  16. data/{test/lib/fastly_nsq/fake_message_queue_test.rb → spec/lib/fastly_nsq/fake_message_queue_spec.rb} +12 -12
  17. data/{test/lib/fastly_nsq/fastly_nsq_test.rb → spec/lib/fastly_nsq/fastly_nsq_spec.rb} +3 -3
  18. data/spec/lib/fastly_nsq/message_queue/consumer_spec.rb +93 -0
  19. data/spec/lib/fastly_nsq/message_queue/listener_spec.rb +78 -0
  20. data/spec/lib/fastly_nsq/message_queue/producer_spec.rb +84 -0
  21. data/{test/lib/fastly_nsq/message_queue/strategy.rb → spec/lib/fastly_nsq/message_queue/strategy_spec.rb} +5 -7
  22. data/{test/lib/fastly_nsq/sample_message_processor_test.rb → spec/lib/fastly_nsq/sample_message_processor_spec.rb} +8 -22
  23. data/spec/spec_helper.rb +44 -0
  24. data/spec/support/env_helpers.rb +19 -0
  25. data/test/lib/fastly_nsq/rake_task_test.rb +68 -0
  26. metadata +17 -33
  27. data/test/lib/fastly_nsq/message_queue/consumer_test.rb +0 -59
  28. data/test/lib/fastly_nsq/message_queue/listener_test.rb +0 -45
  29. data/test/lib/fastly_nsq/message_queue/producer_test.rb +0 -54
  30. data/test/test_helper.rb +0 -49
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95925013466f1c6030b499fcc757af3bb2ef9108
4
- data.tar.gz: de2bf7042bd3c5e3321401292f85f90c711097e5
3
+ metadata.gz: 325bb3dda2921106c66242e7d74c159e19b1d23a
4
+ data.tar.gz: d6db3266246c089e744efb2f16fabd0cee8349a8
5
5
  SHA512:
6
- metadata.gz: d6960321ea681e336e80ece23721a43e6314d1352866fa59b3ee5adb1ba851be9f4119e4514e3d07ed55dfeaefbb7b840d89380b215786524e495f2ef800bded
7
- data.tar.gz: 029dc818205f8fa98c697d7de108ef6a4cb2d344f4a106eeca2ad1d18bcbb1475a7bd9800f2e6f44c39d4151201ac61ae9d698e728708c00e5f290ed4f990e5d
6
+ metadata.gz: cda98052c9c52f8aa1fe65a4dd0a6e311530e300adbf58d1e9bc794a652ed21852c3d6928ef1bf0b98c5e043700f68b2924d4a9de7915e1b008905a3c25097ec
7
+ data.tar.gz: d58bb1d4976fd771677bf38857b3b292f4bb57fb3cd56fc26772b0761896b91dd7969712f1a9011c59b04a3307b5086b340d74e9bea64fb4a96a6e02c8f69388
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  /html/
4
4
  /pkg/
5
5
  /vendor/cache/*.gem
6
+ spec/examples.txt
@@ -0,0 +1 @@
1
+ 2.3.0
@@ -5,7 +5,7 @@ rvm:
5
5
  - 2.2.4
6
6
  - 2.3.0
7
7
  script:
8
- - bundle exec rake test
8
+ - bundle exec rake
9
9
  notifications:
10
10
  slack:
11
11
  rooms:
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- gem 'minitest-utils', require: false
data/README.md CHANGED
@@ -29,7 +29,7 @@ Please use [GitHub Issues] to report bugs.
29
29
 
30
30
  `fastly_nsq` is a Ruby Gem
31
31
  tested against Rails `>= 4.2`
32
- and Ruby `>= 2.0`.
32
+ and Ruby `>= 2.3.0`.
33
33
 
34
34
  To get started,
35
35
  add `fastly_nsq` to your `Gemfile`
@@ -52,9 +52,9 @@ write messages onto the queue:
52
52
 
53
53
  ```ruby
54
54
  message_data = {
55
- "event_type": "heartbeat",
56
- "data": {
57
- "key": "value"
55
+ "event_type" => "heartbeat",
56
+ "data" => {
57
+ "key" => "value"
58
58
  }
59
59
  }
60
60
 
@@ -73,10 +73,10 @@ to your application:
73
73
 
74
74
  ```ruby
75
75
  # for the fake
76
- ENV['FAKE_QUEUE'] == true
76
+ ENV['FAKE_QUEUE'] = true
77
77
 
78
78
  # for the real thing
79
- ENV['FAKE_QUEUE'] == false
79
+ ENV['FAKE_QUEUE'] = false
80
80
  ```
81
81
 
82
82
  ### `MessageQueue::Consumer`
@@ -94,9 +94,10 @@ consumer = MessageQueue::Consumer.new(
94
94
 
95
95
  consumer.size #=> 1
96
96
  message = consumer.pop
97
- message.body #=>'hey this is my message!'
97
+ message.body #=> "{ 'event_type': 'heartbeat','data': { 'key': 'value' } }"
98
98
  message.finish
99
99
  consumer.size #=> 0
100
+ consumer.terminate
100
101
  ```
101
102
 
102
103
  As above,
@@ -117,7 +118,8 @@ MessageQueue::Listener.new(topic: topic, channel: channel).process_next_message
117
118
 
118
119
  This will pop the next message
119
120
  off of the queue
120
- and send it to `MessageProcessor.new(message).go`.
121
+ and send the JSON text body
122
+ to `MessageProcessor.new(message_body).go`.
121
123
 
122
124
  To initiate a blocking loop to process messages continuously:
123
125
 
@@ -132,8 +134,45 @@ This will block until
132
134
  there is a new message on the queue,
133
135
  pop the next message
134
136
  off of the queue
135
- and send it to `MessageProcessor.new(message).go`.
137
+ and send it to `MessageProcessor.new(message_body).go`.
136
138
 
139
+ ### `MessageQueue::RakeTask`
140
+
141
+ To help facilitate running the `MessageQueue::Listener` in a blocking fashion
142
+ outside your application, a simple `RakeTask` is provided.
143
+
144
+ This can be added into your `Rakefile` in one of two ways:
145
+
146
+ Using a block:
147
+ ```ruby
148
+ require 'fastly_nsq'
149
+ require 'fastly_nsq/rake_task'
150
+
151
+ MessageQueue::RakeTask.new(:listen_task) do |task|
152
+ task.topic = 'some_topic'
153
+ task.channel = 'some_channel'
154
+ end
155
+
156
+ # usage:
157
+ `rake listen_task`
158
+ ```
159
+
160
+ or using passed in values:
161
+ ```ruby
162
+ require 'fastly_nsq'
163
+ require 'fastly_nsq/rake_task'
164
+
165
+ MessageQueue::RakeTask.new(:listen_task, [:topic, :channel])
166
+
167
+ # usage:
168
+ `rake listen_task['my_topic','my_channel']`
169
+ ```
170
+
171
+ Both methods can be used at the same time with the passed in values taking
172
+ priority over block assigned values
173
+
174
+ See the [`Rakefile`](examples/Rakefile) file
175
+ for more detail.
137
176
 
138
177
  ### Real vs. Fake
139
178
 
@@ -163,15 +202,18 @@ This class needs to adhere to the following API:
163
202
  ```ruby
164
203
  class MessageProcessor
165
204
  # This an instance of NSQ::Message or FakeMessageQueue::Message
166
- def initialize(message)
167
- @message = message
205
+ def initialize(message_body)
206
+ @message_body = message_body
168
207
  end
169
208
 
170
209
  def start
171
- # Do things with the message. It's JSON body is accessible by @message.body.
210
+ # Do things
211
+ end
212
+
213
+ private
172
214
 
173
- # Finish the message to let the queue know it is complete like so:
174
- @message.finish
215
+ def message
216
+ JSON.parse(@message_body)
175
217
  end
176
218
  end
177
219
  ```
data/Rakefile CHANGED
@@ -17,14 +17,6 @@ require 'rdoc/task'
17
17
  RDoc::Task.new
18
18
  task doc: :rdoc
19
19
 
20
- require 'rake/testtask'
21
-
22
- Rake::TestTask.new do |test|
23
- test.libs << 'test'
24
- test.pattern = 'test/**/*_test.rb'
25
- test.verbose = true
26
- end
27
-
28
20
  require 'bundler/audit/cli'
29
21
 
30
22
  namespace :bundler do
@@ -36,5 +28,8 @@ namespace :bundler do
36
28
  end
37
29
  end
38
30
 
31
+ require 'rspec/core/rake_task'
32
+ RSpec::Core::RakeTask.new(:spec)
33
+
39
34
  task(:default).clear
40
- task default: ['test', 'bundler:audit']
35
+ task default: ['spec', 'bundler:audit']
@@ -0,0 +1,36 @@
1
+ require 'fastly_nsq'
2
+ require 'fastly_nsq/rake_task'
3
+
4
+ ##
5
+ # Both topic and channel will need to be passed into the rake task when
6
+ # it is called.
7
+ #
8
+ # ex: `rake listen_task[my_topic,my_channel]`
9
+ # topic will be 'my_topic' and channel will be 'my_channel'
10
+ #
11
+ MessageQueue::RakeTask.new(:listen_task, [:topic, :channel])
12
+
13
+ ##
14
+ # Topic and channel can also be preset in the task by passing a block and
15
+ # assigning value like so. This is useful if you want a single purpose
16
+ # listener task.
17
+ #
18
+ # ex: `rake listen_task`
19
+ # topic will be 'some_topic' and channel will be 'some_channel'
20
+ #
21
+ MessageQueue::RakeTask.new(:listen_task) do |task|
22
+ task.topic = 'some_topic'
23
+ task.channel = 'some_channel'
24
+ end
25
+
26
+ ##
27
+ # Both forms can be combine to provide defaults of a sort with the ability
28
+ # to override at time of rake call
29
+ #
30
+ # ex: `rake listen_task[altered_topic]`
31
+ # topic will be 'altered_topic' and channel will be 'some_channel'
32
+ #
33
+ MessageQueue::RakeTask.new(:listen_task, [:topic, :channel]) do |task|
34
+ task.topic = 'some_topic'
35
+ task.channel = 'some_channel'
36
+ end
@@ -23,11 +23,10 @@ Gem::Specification.new do |gem|
23
23
  gem.add_development_dependency 'awesome_print', '~> 1.6'
24
24
  gem.add_development_dependency 'bundler', '~> 1.10'
25
25
  gem.add_development_dependency 'bundler-audit', '~> 0.4'
26
- gem.add_development_dependency 'minitest', '~> 5.8'
27
26
  gem.add_development_dependency 'pry-byebug', '~> 3.3'
28
27
  gem.add_development_dependency 'rake', '~> 10.5'
29
28
  gem.add_development_dependency 'rdoc', '~> 4.2'
30
- gem.add_development_dependency 'rspec-mocks', '~> 3.4'
29
+ gem.add_development_dependency 'rspec', '~> 3.4'
31
30
  gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
32
31
 
33
32
  gem.add_dependency 'nsq-ruby', '~> 1.5.0', '>= 1.5.0'
@@ -8,7 +8,11 @@ module MessageQueue
8
8
  end
9
9
 
10
10
  def connection
11
- consumer.new(params)
11
+ @connection ||= consumer.new(params)
12
+ end
13
+
14
+ def terminate
15
+ @connection.terminate
12
16
  end
13
17
 
14
18
  private
@@ -6,22 +6,45 @@ module MessageQueue
6
6
  end
7
7
 
8
8
  def go
9
+ Signal.trap('INT') do
10
+ shutdown
11
+ end
12
+
13
+ Signal.trap('TERM') do
14
+ shutdown
15
+ end
16
+
9
17
  loop do
10
- process_next_message
18
+ process_one_message
11
19
  end
12
20
  end
13
21
 
14
22
  def process_next_message
15
- message = consumer.pop
16
- MessageProcessor.new(message).go
23
+ process_one_message
24
+ consumer.terminate
17
25
  end
18
26
 
19
27
  private
20
28
 
29
+ def process_one_message
30
+ message = consumer.pop
31
+ MessageProcessor.new(message.body).go
32
+ message.finish
33
+ end
34
+
21
35
  attr_reader :channel, :topic
22
36
 
23
37
  def consumer
24
- MessageQueue::Consumer.new(topic: topic, channel: channel).connection
38
+ @consumer ||= MessageQueue::Consumer.new(consumer_params).connection
39
+ end
40
+
41
+ def consumer_params
42
+ { topic: topic, channel: channel }
43
+ end
44
+
45
+ def shutdown
46
+ consumer.terminate
47
+ exit
25
48
  end
26
49
  end
27
50
  end
@@ -7,7 +7,11 @@ module MessageQueue
7
7
  end
8
8
 
9
9
  def connection
10
- producer.new(params)
10
+ @producer ||= producer.new(params)
11
+ end
12
+
13
+ def terminate
14
+ @producer.terminate
11
15
  end
12
16
 
13
17
  private
@@ -0,0 +1,40 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ module MessageQueue
5
+ class RakeTask < Rake::TaskLib
6
+ attr_accessor :name, :topic, :channel
7
+
8
+ def initialize(*args, &task_block)
9
+ @name = args.shift || :begin_listening
10
+
11
+ desc 'Listen to NSQ on topic using channel' unless ::Rake.application.last_comment
12
+
13
+ task(name, *args) do |_, task_args|
14
+ RakeFileUtils.send(:verbose, verbose) do
15
+ yield(*[self, task_args].slice(0, task_block.arity)) if block_given?
16
+ @topic = task_args[:topic] if task_args[:topic]
17
+ @channel = task_args[:channel] if task_args[:channel]
18
+ run_task
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def run_task
26
+ raise ArgumentError, "topic and channel are required. Recieved topic: #{topic} channel: #{channel}" unless topic && channel
27
+
28
+ output "Listening to the queue on topic:'#{topic}' and channel ':#{channel}'"
29
+
30
+ MessageQueue::Listener.new(topic: topic, channel: channel).go
31
+
32
+ output "... done listening to queue on topic:'#{topic}' and channel ':#{channel}'"
33
+ end
34
+
35
+ # wrapping output for stubbing in tests to avoid clobbering output...
36
+ def output(str)
37
+ puts str
38
+ end
39
+ end
40
+ end
@@ -1,25 +1,33 @@
1
- class HeartbeatWorker; end
2
- class UnknownMessageWorker; end
1
+ class HeartbeatWorker
2
+ def self.perform_async(_data)
3
+ # noop
4
+ end
5
+ end
6
+
7
+ class UnknownMessageWorker
8
+ def self.perform_async(_data)
9
+ # noop
10
+ end
11
+ end
3
12
 
4
13
  class SampleMessageProcessor
5
14
  EVENT_TYPE_TO_WORKER_MAP = {
6
15
  'heartbeat' => HeartbeatWorker,
7
16
  }.freeze
8
17
 
9
- def initialize(message)
10
- @message = message
18
+ def initialize(message_body)
19
+ @message_body = message_body
11
20
  end
12
21
 
13
22
  def go
14
- process_message
15
- message.finish
23
+ process_message_body
16
24
  end
17
25
 
18
26
  private
19
27
 
20
- attr_reader :message
28
+ attr_reader :message_body
21
29
 
22
- def process_message
30
+ def process_message_body
23
31
  message_processor.perform_async(message_data)
24
32
  end
25
33
 
@@ -38,8 +46,4 @@ class SampleMessageProcessor
38
46
  def parsed_message_body
39
47
  JSON.parse(message_body)
40
48
  end
41
-
42
- def message_body
43
- message.body
44
- end
45
49
  end
@@ -1,3 +1,3 @@
1
1
  module FastlyNsq
2
- VERSION = '0.1.4'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -1,25 +1,25 @@
1
- require 'test_helper'
1
+ require 'spec_helper'
2
2
 
3
- describe FakeMessageQueue do
3
+ RSpec.describe FakeMessageQueue do
4
4
  describe '@@queue' do
5
5
  it 'is initalized as an empty array' do
6
- assert_equal [], FakeMessageQueue.queue
6
+ expect(FakeMessageQueue.queue).to eq []
7
7
  end
8
8
  end
9
9
 
10
10
  describe '.reset!' do
11
11
  it 'resets the fake message queue' do
12
12
  FakeMessageQueue.queue = ['hello']
13
- assert_equal 1, FakeMessageQueue.queue.size
13
+ expect(FakeMessageQueue.queue.size).to eq 1
14
14
 
15
15
  FakeMessageQueue.reset!
16
16
 
17
- assert_empty FakeMessageQueue.queue
17
+ expect(FakeMessageQueue.queue).to be_empty
18
18
  end
19
19
  end
20
20
  end
21
21
 
22
- describe FakeMessageQueue::Producer do
22
+ RSpec.describe FakeMessageQueue::Producer do
23
23
  after do
24
24
  FakeMessageQueue.reset!
25
25
  end
@@ -34,12 +34,12 @@ describe FakeMessageQueue::Producer do
34
34
  )
35
35
  producer.write('hello')
36
36
 
37
- assert_equal 1, FakeMessageQueue.queue.size
37
+ expect(FakeMessageQueue.queue.size).to eq 1
38
38
  end
39
39
  end
40
40
  end
41
41
 
42
- describe FakeMessageQueue::Message do
42
+ RSpec.describe FakeMessageQueue::Message do
43
43
  after do
44
44
  FakeMessageQueue.reset!
45
45
  end
@@ -57,12 +57,12 @@ describe FakeMessageQueue::Message do
57
57
  message = FakeMessageQueue.queue.pop
58
58
  body = message.body
59
59
 
60
- assert_equal content, body
60
+ expect(content).to eq body
61
61
  end
62
62
  end
63
63
  end
64
64
 
65
- describe FakeMessageQueue::Consumer do
65
+ RSpec.describe FakeMessageQueue::Consumer do
66
66
  after do
67
67
  FakeMessageQueue.reset!
68
68
  end
@@ -80,7 +80,7 @@ describe FakeMessageQueue::Consumer do
80
80
  )
81
81
  queue_size = consumer.size
82
82
 
83
- assert_equal 1, queue_size
83
+ expect(queue_size).to eq 1
84
84
  end
85
85
  end
86
86
 
@@ -98,7 +98,7 @@ describe FakeMessageQueue::Consumer do
98
98
  )
99
99
  popped_message = consumer.pop
100
100
 
101
- assert_equal message, popped_message
101
+ expect(popped_message). to eq message
102
102
  end
103
103
  end
104
104
  end