fastly_nsq 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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