fastly_nsq 0.1.4 → 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.
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