fastly_nsq 0.4.0 → 0.5.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: 7d55c09a395246d423966f21f8dc1d7ee1b29da7
4
- data.tar.gz: d1499d0fee9093424f9134137e80637f0459c490
3
+ metadata.gz: 6b927006ea75538d36b77a9988c99f159327e72c
4
+ data.tar.gz: 0ba8e537719bcb36721c65292741d779f9d4da4c
5
5
  SHA512:
6
- metadata.gz: 646415b3b22eca19dc1cf8882ec7dde9187baee661f802fa73703ef74638ee38c45561489aa747380d48e9357b83a20286c4d29d581b58700dd42848370bf653
7
- data.tar.gz: 3549a0dfd59543708a28185358d36cd48a5880eb2695b1b0a99408822267b31139a2700e90964547d179386244d9184e3628f6de0df504665aafe2a0c6d21f12
6
+ metadata.gz: acaa3eb91200476a12e5f4099ef6515803293007f8643d49cd9651d5f786a6c9e2f36f39ff8086cff38a339a2767346ffada9131bb584db7d6155343d08788ed
7
+ data.tar.gz: 667ebee86054600dbd16e1f0450f51ce0186d759210c4c4c5e3fbac1f1d84e994124c4496cbcfce2ce6281da1398a5e3e0b8c22e45fdf3b1700511081be008bf
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.3.0`.
32
+ and Ruby `>= 2.1.8`.
33
33
 
34
34
  To get started,
35
35
  add `fastly_nsq` to your `Gemfile`
@@ -88,7 +88,7 @@ read messages off of the queue:
88
88
  consumer = MessageQueue::Consumer.new(
89
89
  topic: 'topic',
90
90
  channel: 'channel'
91
- ).connection
91
+ )
92
92
 
93
93
  consumer.size #=> 1
94
94
  message = consumer.pop
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.require_paths = ['lib']
22
22
 
23
23
  gem.add_development_dependency 'awesome_print', '~> 1.6'
24
- gem.add_development_dependency 'bundler', '~> 1.11.2'
24
+ gem.add_development_dependency 'bundler', '~> 1.12'
25
25
  gem.add_development_dependency 'bundler-audit', '~> 0.5.0'
26
26
  gem.add_development_dependency 'overcommit', '~> 0.32.0'
27
27
  gem.add_development_dependency 'pry-byebug', '~> 3.3'
@@ -1,5 +1,7 @@
1
1
  module FakeMessageQueue
2
2
  @@logger = Logger.new(nil)
3
+ @@delay = 0.5
4
+ @@queue = []
3
5
 
4
6
  def self.queue
5
7
  @@queue
@@ -21,6 +23,14 @@ module FakeMessageQueue
21
23
  @@logger
22
24
  end
23
25
 
26
+ def self.delay
27
+ @@delay
28
+ end
29
+
30
+ def self.delay=(delay)
31
+ @@delay = delay
32
+ end
33
+
24
34
  class Producer
25
35
  def initialize(nsqd:, topic:, ssl_context: nil)
26
36
  end
@@ -42,22 +52,24 @@ module FakeMessageQueue
42
52
  end
43
53
 
44
54
  class Consumer
45
- SECONDS_BETWEEN_QUEUE_CHECKS = 0.5
46
-
47
- def initialize(nsqlookupd:, topic:, channel:, ssl_context: nil)
55
+ def initialize(nsqlookupd: nil, topic:, channel:, ssl_context: nil)
48
56
  end
49
57
 
50
- def pop
58
+ def pop(delay = FakeMessageQueue.delay)
51
59
  message = nil
52
60
 
53
61
  until message
54
62
  message = queue.pop
55
- sleep SECONDS_BETWEEN_QUEUE_CHECKS
63
+ sleep delay
56
64
  end
57
65
 
58
66
  message
59
67
  end
60
68
 
69
+ def pop_without_blocking
70
+ queue.pop
71
+ end
72
+
61
73
  def size
62
74
  queue.size
63
75
  end
@@ -1,27 +1,27 @@
1
+ require 'forwardable'
2
+
1
3
  class InvalidParameterError < StandardError; end
2
4
 
3
5
  module MessageQueue
4
6
  class Consumer
7
+ extend Forwardable
8
+ def_delegator :connection, :pop
9
+ def_delegator :connection, :pop_without_blocking
10
+ def_delegator :connection, :size
11
+ def_delegator :connection, :terminate
12
+
5
13
  def initialize(topic:, channel:, ssl_context: nil)
6
14
  @topic = topic
7
15
  @channel = channel
8
16
  @ssl_context = SSLContext.new(ssl_context)
9
17
  end
10
18
 
11
- def connection
12
- @connection ||= consumer.new(params)
13
- end
14
-
15
- def terminate
16
- @connection.terminate
17
- end
18
-
19
19
  private
20
20
 
21
21
  attr_reader :channel, :topic, :ssl_context
22
22
 
23
- def consumer
24
- Strategy.for_queue::Consumer
23
+ def connection
24
+ Strategy.for_queue::Consumer.new(params)
25
25
  end
26
26
 
27
27
  def params
@@ -1,8 +1,10 @@
1
1
  module MessageQueue
2
2
  class Listener
3
- def initialize(topic:, channel:)
4
- @topic = topic
5
- @channel = channel
3
+ def initialize(topic:, channel:, processor: nil, consumer: nil)
4
+ @topic = topic
5
+ @channel = channel
6
+ @processor = processor || DEFAULT_PROCESSOR
7
+ @consumer = consumer || MessageQueue::Consumer.new(consumer_params)
6
8
  end
7
9
 
8
10
  def go
@@ -26,18 +28,15 @@ module MessageQueue
26
28
 
27
29
  private
28
30
 
29
- attr_reader :channel, :topic
31
+ attr_reader :channel, :topic, :processor, :consumer
32
+ DEFAULT_PROCESSOR = ->(body, topic) { MessageProcessor.new(message_body: body, topic: topic).go }
30
33
 
31
34
  def process_one_message
32
35
  message = consumer.pop
33
- MessageProcessor.new(message_body: message.body, topic: topic).go
36
+ processor.call(message.body, topic)
34
37
  message.finish
35
38
  end
36
39
 
37
- def consumer
38
- @consumer ||= MessageQueue::Consumer.new(consumer_params).connection
39
- end
40
-
41
40
  def consumer_params
42
41
  { topic: topic, channel: channel }
43
42
  end
@@ -1,3 +1,3 @@
1
1
  module FastlyNsq
2
- VERSION = '0.4.0'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -88,65 +88,55 @@ RSpec.describe FakeMessageQueue::Message do
88
88
  end
89
89
 
90
90
  RSpec.describe FakeMessageQueue::Consumer do
91
+ let(:topic) { 'death_star' }
92
+ let(:channel) { 'star_killer_base' }
93
+ let(:consumer) { FakeMessageQueue::Consumer.new topic: topic, channel: channel }
94
+
91
95
  after do
92
96
  FakeMessageQueue.reset!
93
97
  end
94
98
 
95
- describe '#size' do
96
- it 'tells you how many messages are in the queue' do
97
- FakeMessageQueue.queue = ['hello']
98
- topic = 'death_star'
99
- channel = 'star_killer_base'
99
+ describe 'when there are no messages on the queue' do
100
+ it 'tells you there are 0 messages in the queue' do
101
+ expect(consumer.size).to eq 0
102
+ end
100
103
 
101
- consumer = FakeMessageQueue::Consumer.new(
102
- nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
103
- topic: topic,
104
- channel: channel,
105
- )
106
- queue_size = consumer.size
104
+ it 'blocks forever (until timeout) from #pop' do
105
+ FakeMessageQueue.delay = 0.1
106
+ delay = FakeMessageQueue.delay + 0.1
107
+
108
+ expect do
109
+ Timeout.timeout(delay) do
110
+ consumer.pop
111
+ end
112
+ end.to raise_error(Timeout::Error)
113
+ end
114
+
115
+ it 'returns nil from #pop_without_blocking' do
116
+ popped_message = consumer.pop_without_blocking
107
117
 
108
- expect(queue_size).to eq 1
118
+ expect(popped_message).to be_nil
109
119
  end
110
120
  end
111
121
 
112
- describe '#pop' do
113
- context 'when there is a message on the queue' do
114
- it 'returns the last message off of the queue' do
115
- message = FakeMessageQueue::Message.new('hello')
116
- FakeMessageQueue.queue = [message]
117
- topic = 'death_star'
118
- channel = 'star_killer_base'
119
-
120
- consumer = FakeMessageQueue::Consumer.new(
121
- nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
122
- topic: topic,
123
- channel: channel,
124
- )
125
- popped_message = consumer.pop
126
-
127
- expect(popped_message).to eq message
128
- end
122
+ describe 'when there is a message on the queue' do
123
+ let(:message) { FakeMessageQueue::Message.new 'hello' }
124
+ before { FakeMessageQueue.queue = [message] }
125
+
126
+ it 'tells you there are messages in the queue' do
127
+ expect(consumer.size).to eq 1
129
128
  end
130
129
 
131
- context 'when there no message on the queue' do
132
- it 'blocks for longer than the queue check cycle' do
133
- FakeMessageQueue.queue = []
134
- topic = 'death_star'
135
- channel = 'star_killer_base'
136
- delay = FakeMessageQueue::Consumer::SECONDS_BETWEEN_QUEUE_CHECKS + 0.1
137
-
138
- consumer = FakeMessageQueue::Consumer.new(
139
- nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
140
- topic: topic,
141
- channel: channel,
142
- )
143
-
144
- expect do
145
- Timeout.timeout(delay) do
146
- consumer.pop
147
- end
148
- end.to raise_error(Timeout::Error)
149
- end
130
+ it 'returns a message immediately from #pop' do
131
+ popped_message = consumer.pop
132
+
133
+ expect(popped_message).to eq message
134
+ end
135
+
136
+ it 'returns a message immediately from #pop_without_blocking' do
137
+ popped_message = consumer.pop_without_blocking
138
+
139
+ expect(popped_message).to eq message
150
140
  end
151
141
  end
152
142
 
@@ -1,87 +1,65 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe MessageQueue::Consumer do
4
- describe '#connection' do
5
- describe 'when using the real queue', fake_queue: false do
6
- it 'returns an instance of the queue consumer' do
7
- allow(Nsq::Consumer).to receive(:new)
8
- topic = 'death_star'
9
- channel = 'star_killer_base'
4
+ let(:channel) { 'star_killer_base' }
5
+ let(:topic) { 'death_star' }
6
+ let(:consumer) { MessageQueue::Consumer.new(topic: topic, channel: channel) }
10
7
 
11
- MessageQueue::Consumer.new(topic: topic, channel: channel).connection
8
+ def fake_consumer
9
+ double 'Consumer', connection: nil, terminate: nil, pop: :popped, size: 0
10
+ end
12
11
 
13
- expect(Nsq::Consumer).to have_received(:new).
14
- with(
15
- nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
16
- topic: topic,
17
- channel: channel,
18
- ssl_context: nil,
19
- ).at_least(:once)
20
- end
21
- end
12
+ describe 'when the ENV is set incorrectly' do
13
+ it 'raises with a helpful error' do
14
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
22
15
 
23
- describe 'when using the fake queue', fake_queue: true do
24
- it 'returns an instance of the queue consumer' do
25
- allow(FakeMessageQueue::Consumer).to receive(:new)
26
- topic = 'death_star'
27
- channel = 'star_killer_base'
16
+ expect { consumer.terminate }.to raise_error(InvalidParameterError)
17
+ end
18
+ end
28
19
 
29
- MessageQueue::Consumer.new(topic: topic, channel: channel).connection
20
+ describe 'when using the real queue', fake_queue: false do
21
+ before(:example) do
22
+ @fake_consumer = fake_consumer
23
+ allow(Nsq::Consumer).to receive(:new).and_return(@fake_consumer)
24
+ end
30
25
 
31
- expect(FakeMessageQueue::Consumer).to have_received(:new).
32
- with(
33
- nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
34
- topic: topic,
35
- channel: channel,
36
- ssl_context: nil,
37
- ).at_least(:once)
38
- end
26
+ it 'forwards #pop to Nsq::Consumer' do
27
+ consumer.pop
28
+ expect(@fake_consumer).to have_received(:pop)
39
29
  end
40
- end
41
30
 
42
- describe 'when the ENV is set incorrectly' do
43
- it 'raises with a helpful error' do
44
- allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
45
- topic = 'death_star'
46
- channel = 'star_killer_base'
31
+ it 'forwards #size to Nsq::Consumer' do
32
+ consumer.size
33
+ expect(@fake_consumer).to have_received(:size)
34
+ end
47
35
 
48
- consumer = MessageQueue::Consumer.new(topic: topic, channel: channel)
36
+ it 'forwards #terminate to Nsq::Consumer' do
37
+ consumer.terminate
49
38
 
50
- expect { consumer.connection }.to raise_error(InvalidParameterError)
39
+ expect(@fake_consumer).to have_received(:terminate)
51
40
  end
52
41
  end
53
42
 
54
- describe '#terminate' do
55
- describe 'when using the real queue', fake_queue: false do
56
- it 'closes the connection' do
57
- consumer = double('Consumer', connection: nil, terminate: nil)
58
- allow(Nsq::Consumer).to receive(:new).and_return(consumer)
59
- topic = 'death_star'
60
- channel = 'star_killer_base'
61
- params = { topic: topic, channel: channel }
62
-
63
- live_consumer = MessageQueue::Consumer.new(params)
64
- live_consumer.connection
65
- live_consumer.terminate
43
+ describe 'when using the fake queue', fake_queue: true do
44
+ before(:example) do
45
+ @fake_consumer = fake_consumer
46
+ allow(FakeMessageQueue::Consumer).to receive(:new).and_return(@fake_consumer)
47
+ end
66
48
 
67
- expect(consumer).to have_received(:terminate)
68
- end
49
+ it 'forwards #pop to FakeMessageQueue::Consumer' do
50
+ consumer.pop
51
+ expect(@fake_consumer).to have_received(:pop)
69
52
  end
70
53
 
71
- describe 'when using the fake queue', fake_queue: true do
72
- it 'closes the connection' do
73
- consumer = double('Consumer', connection: nil, terminate: nil)
74
- allow(FakeMessageQueue::Consumer).to receive(:new).and_return(consumer)
75
- topic = 'death_star'
76
- channel = 'star_killer_base'
77
- params = { topic: topic, channel: channel }
54
+ it 'forwards #size to FakeMessageQueue::Consumer' do
55
+ consumer.size
56
+ expect(@fake_consumer).to have_received(:size)
57
+ end
78
58
 
79
- live_consumer = MessageQueue::Consumer.new(params)
80
- live_consumer.connection
81
- live_consumer.terminate
59
+ it 'forwards #terminate to FakeMessageQueue::Consumer' do
60
+ consumer.terminate
82
61
 
83
- expect(consumer).to have_received(:terminate)
84
- end
62
+ expect(@fake_consumer).to have_received(:terminate)
85
63
  end
86
64
  end
87
65
  end
@@ -1,67 +1,87 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe MessageQueue::Listener do
4
- describe '#process_next_message' do
5
- it 'pass the topic and channel to the consumer' do
6
- allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
7
- message = double('Message', finish: nil, body: nil)
8
- connection = double('Connection', pop: message, terminate: nil)
9
- consumer = double('Consumer', connection: connection)
10
- allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
11
- topic = 'testing_topic'
12
- channel = 'testing_channel'
13
-
14
- MessageQueue::Listener.new(topic: topic, channel: channel).
15
- process_next_message
4
+ let(:topic) { 'testing_topic' }
5
+ let(:channel) { 'testing_channel' }
6
+ let(:consumer) { FakeMessageQueue::Consumer.new topic: topic, channel: channel }
7
+
8
+ module TestMessageProcessor
9
+ @@messages_processed = []
10
+ Message = Struct.new(:body, :topic) do
11
+ def finish
12
+ @did_finish = true
13
+ end
14
+ end
15
+
16
+ def self.call(body, topic)
17
+ @@messages_processed.push Message.new(body, topic)
18
+ end
19
+
20
+ def self.messages_processed
21
+ @@messages_processed
22
+ end
23
+
24
+ def self.clear
25
+ @@messages_processed = []
26
+ end
27
+ end
28
+
29
+ let(:listener) do
30
+ MessageQueue::Listener.new topic: topic,
31
+ channel: channel,
32
+ processor: TestMessageProcessor,
33
+ consumer: consumer
34
+ end
35
+
36
+ let(:message) { TestMessageProcessor::Message.new 'this is message body', topic }
37
+ let(:messages_processed) { TestMessageProcessor.messages_processed }
38
+ let(:expected_message) { TestMessageProcessor::Message.new('this is message body', topic) }
39
+ let(:expected_messages) { [expected_message] }
40
+
41
+ describe 'instantiating without a consumer' do
42
+ it 'instantiates a consumer, passing the topic and channel' do
43
+ allow(MessageQueue::Consumer).to receive(:new)
44
+
45
+ MessageQueue::Listener.new topic: topic,
46
+ channel: channel,
47
+ processor: TestMessageProcessor,
48
+ consumer: nil
16
49
 
17
50
  expect(MessageQueue::Consumer).to have_received(:new).
18
51
  with(topic: topic, channel: channel)
19
52
  end
53
+ end
54
+
55
+ describe 'when processing next message' do
56
+ before(:each) { TestMessageProcessor.clear }
57
+
58
+ it 'processes the next message' do
59
+ allow(consumer).to receive(:pop).and_return(message)
60
+ listener.process_next_message
20
61
 
21
- it 'processes the message' do
22
- process_message = double(go: nil)
23
- allow(MessageProcessor).to receive(:new).and_return(process_message)
24
- message_body = { data: 'value' }.to_json
25
- message = double('Message', finish: nil, body: message_body)
26
- connection = double('Connection', pop: message, terminate: nil)
27
- consumer = double('Consumer', connection: connection)
28
- allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
29
- topic = 'testing_topic'
30
- channel = 'testing_channel'
31
-
32
- MessageQueue::Listener.new(topic: topic, channel: channel).
33
- process_next_message
34
-
35
- expect(MessageProcessor).to have_received(:new).
36
- with(topic: topic, message_body: message_body)
37
- expect(process_message).to have_received(:go)
62
+ expect(messages_processed).to eql(expected_messages)
38
63
  end
39
64
 
40
65
  it 'finishes the message' do
41
- allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
42
- message = double('Message', finish: nil, body: nil)
43
- connection = double('Connection', pop: message, terminate: nil)
44
- consumer = double('Consumer', connection: connection)
45
- allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
46
- topic = 'testing_topic'
47
- channel = 'testing_channel'
48
-
49
- MessageQueue::Listener.new(topic: topic, channel: channel).
50
- process_next_message
51
-
52
- expect(message).to have_received(:finish)
66
+ allow(consumer).to receive(:pop).and_return(message)
67
+ allow(message).to receive(:finish)
68
+
69
+ listener.process_next_message
70
+
71
+ expect(message).to have_received(:finish).once
53
72
  end
54
73
 
55
74
  context 'when using the fake queue and it is empty', fake_queue: true do
75
+ before do
76
+ FakeMessageQueue.delay = 0.1
77
+ end
78
+
56
79
  it 'blocks on the process for longer than the check cycle' do
57
- topic = 'testing_topic'
58
- channel = 'testing_channel'
59
- delay = FakeMessageQueue::Consumer::SECONDS_BETWEEN_QUEUE_CHECKS + 0.1
80
+ delay = FakeMessageQueue.delay + 0.1
60
81
 
61
82
  expect do
62
83
  Timeout.timeout(delay) do
63
- MessageQueue::Listener.new(topic: topic, channel: channel).
64
- process_next_message
84
+ listener.process_next_message
65
85
  end
66
86
  end.to raise_error(Timeout::Error)
67
87
  end
@@ -71,14 +91,6 @@ RSpec.describe MessageQueue::Listener do
71
91
  describe '#go' do
72
92
  describe 'when a SIGTERM is received' do
73
93
  it 'closes the consumer connection' do
74
- allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
75
- message = double(finish: nil, body: nil)
76
- connection = double('Connection', pop: message, terminate: nil)
77
- consumer = double('Consumer', connection: connection)
78
- allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
79
- topic = 'testing_topic'
80
- channel = 'testing_channel'
81
-
82
94
  pid = fork do
83
95
  MessageQueue::Listener.new(topic: topic, channel: channel).go
84
96
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastly_nsq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tommy O'Neil
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-21 00:00:00.000000000 Z
12
+ date: 2016-05-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: awesome_print
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 1.11.2
34
+ version: '1.12'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 1.11.2
41
+ version: '1.12'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: bundler-audit
44
44
  requirement: !ruby/object:Gem::Requirement