lapine 1.1.3 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 51e76e478a844476113f4887a3c5c81047f294d0
4
- data.tar.gz: 6202a4b8f09226c9a542f29b7e67677b64dd3881
3
+ metadata.gz: 606eec9764b4ad0c59adde34f12ba6eac251657a
4
+ data.tar.gz: 2acceab836b17cfe7a7c8121c149d6a176ebb7e9
5
5
  SHA512:
6
- metadata.gz: 95fab589bbbde3e8c010d33712048215abfa157ca797e5f6067f026c9aa329b213c04922fc92c3f2eba8d52a2806603bf227f10017b7663da1ebf4f47c0524de
7
- data.tar.gz: 809130f354affa21711f4b1554a953f323d33e97ce3a2253ae6ff1ee63e8b96d9d9262d84de1d58af36f2add7bf099500de8c203851a0c3a9a8d335887214f21
6
+ metadata.gz: fc643eec3ba896154c77828b7db6833c4eb2d11f018fb27a8fbb65490a3e2a9f3d246fef82292a3274910d60c1ffa7f2d6b04fe07f95bd8d1924076618d894c5
7
+ data.tar.gz: 06e26f733603299950b18f2b499d1d7ea3ca83a767b2677dd52c7429579df9580abf3997dec658a2b3a212f22cf39719bb319f5012f138b0a12003aef565793f
@@ -82,6 +82,10 @@ module Lapine
82
82
  config[:logfile]
83
83
  end
84
84
 
85
+ def delete_queues
86
+ yaml_config['delete_queues'] || []
87
+ end
88
+
85
89
  def queues
86
90
  yaml_config['queues'] || []
87
91
  end
@@ -28,23 +28,28 @@ module Lapine
28
28
 
29
29
  @queue_properties = queue_properties
30
30
  EventMachine.run do
31
- topology.each_binding do |q, conn, routing_key, classes|
31
+ topology.each_binding do |q, conn, routing_key, handlers|
32
32
  queue = conn.channel.queue(q, @queue_properties).bind(conn.exchange, routing_key: routing_key)
33
33
  queue.subscribe(ack: true) do |metadata, payload|
34
+ process(metadata, payload, handlers)
35
+ EventMachine.stop_event_loop if should_exit?
36
+ end
37
+ queues << queue
38
+ end
34
39
 
35
- message = Consumer::Message.new(payload, metadata, logger)
36
- Middleware.app.call(message) do |message|
37
- classes.each do |clazz|
38
- Lapine::Consumer::Dispatcher.new(clazz, message).dispatch
39
- end
40
+ topology.each_queue_to_delete do |q, conn, routing_key, handlers|
41
+ # if queue does not exist in RabbitMQ, skip processing
42
+ # else
43
+ queue = conn.channel.queue(q, @queue_properties)
44
+ queues_to_delete << queue
40
45
 
41
- if config.debug?
42
- @message_count += 1
43
- @running_message_count += 1
44
- end
45
- end
46
+ queue.subscribe(ack: true) do |metadata, payload|
47
+ process(metadata, payload, handlers)
48
+ end
46
49
 
47
- EventMachine.stop_event_loop if should_exit?
50
+ EventMachine.add_timer(0.5) do
51
+ logger.info "Lapine::Consumer unbinding #{queue.name} from exchange: #{exchange.name}, routing_key: #{routing_key}"
52
+ queue.unbind(conn.exchange, routing_key: routing_key)
48
53
  end
49
54
  end
50
55
 
@@ -58,6 +63,8 @@ module Lapine
58
63
  EventMachine.add_periodic_timer(5) do
59
64
  EventMachine.stop_event_loop if should_exit?
60
65
  end
66
+
67
+ schedule_queue_deletion
61
68
  end
62
69
 
63
70
  logger.warn 'exiting Lapine::Consumer'
@@ -90,6 +97,54 @@ module Lapine
90
97
  Signal.trap('INT') { EventMachine.stop }
91
98
  Signal.trap('TERM') { $STOP_LAPINE_CONSUMER = true }
92
99
  end
100
+
101
+ private
102
+
103
+ def queues
104
+ @queues ||= []
105
+ end
106
+
107
+ def queues_to_delete
108
+ @queues_to_delete ||= []
109
+ end
110
+
111
+ def schedule_queue_deletion
112
+ EventMachine.add_timer(30) do
113
+ queues_to_delete.each do |queue|
114
+ logger.info "Lapine::Consumer checking #{queue.name} for deletion"
115
+
116
+ begin
117
+ queue.status do |message_count, consumer_count|
118
+ if message_count == 0
119
+ logger.info "Lapine::Consumer deleting #{queue.name}"
120
+ queue.unsubscribe
121
+ queue.delete unless config.transient?
122
+ queues_to_delete.delete(queue)
123
+ else
124
+ logger.info "Lapine::Consumer skipping #{queue.name} deletion, message count: #{message_count}"
125
+ schedule_queue_deletion
126
+ end
127
+ end
128
+ rescue => e
129
+ logger.error "Unable to delete queue #{queue.name}, error: #{e.message}"
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def process(metadata, payload, handlers)
136
+ message = Consumer::Message.new(payload, metadata, logger)
137
+ Middleware.app.call(message) do |message|
138
+ handlers.each do |handler|
139
+ Lapine::Consumer::Dispatcher.new(handler, message).dispatch
140
+ end
141
+
142
+ if config.debug?
143
+ @message_count += 1
144
+ @running_message_count += 1
145
+ end
146
+ end
147
+ end
93
148
  end
94
149
  end
95
150
  end
@@ -6,16 +6,17 @@ module Lapine
6
6
 
7
7
  def each_binding
8
8
  config.queues.each do |node|
9
- classes = node['handlers'].map do |handler|
10
- handler.split('::').inject(Object) do |const, name|
11
- const.const_get(name)
12
- end
13
- end
14
-
9
+ classes = classify(node['handlers'])
15
10
  yield node['q'], get_conn(node['topic']), node['routing_key'], classes
16
11
  end
17
12
  end
18
13
 
14
+ def each_queue_to_delete
15
+ config.delete_queues.each do |node|
16
+ classes = classify(node['handlers'])
17
+ yield node['q'], get_conn(node['topic']), node['routing_key'], classes
18
+ end
19
+ end
19
20
 
20
21
  def each_topic
21
22
  config.topics.each do |topic|
@@ -32,6 +33,15 @@ module Lapine
32
33
 
33
34
  private
34
35
 
36
+ def classify(handlers)
37
+ return [] unless handlers
38
+ handlers.map do |handler|
39
+ handler.split('::').inject(Object) do |const, name|
40
+ const.const_get(name)
41
+ end
42
+ end
43
+ end
44
+
35
45
  def get_conn(name)
36
46
  @cons ||= {}.tap do |cons|
37
47
  each_topic do |topic|
@@ -1,3 +1,3 @@
1
1
  module Lapine
2
- VERSION = '1.1.3'
2
+ VERSION = '1.2.0'
3
3
  end
@@ -170,6 +170,23 @@ RSpec.describe Lapine::Consumer::Config do
170
170
  end
171
171
  end
172
172
 
173
+ describe '#delete_queues' do
174
+ let(:config_from_file) { {} }
175
+
176
+ it 'defaults to empty array' do
177
+ expect(config.delete_queues).to eq([])
178
+ end
179
+
180
+ context 'with an array' do
181
+ let(:config_from_file) { {'delete_queues' => ['a.b.c', 'e.f.g']} }
182
+
183
+ it 'reads from config' do
184
+ expect(config.delete_queues).to eq(['a.b.c', 'e.f.g'])
185
+ end
186
+
187
+ end
188
+ end
189
+
173
190
  describe '#transient?' do
174
191
  it 'is false by default' do
175
192
  expect(config.transient?).to be false
@@ -39,11 +39,13 @@ RSpec.describe Lapine::Consumer::Runner do
39
39
  connection_properties: connection_properties,
40
40
  require: [],
41
41
  queues: queues,
42
+ delete_queues: delete_queues,
42
43
  topics: ['testing.topic'],
43
44
  debug?: true,
44
45
  transient?: true) }
45
46
  let(:connection_properties) { {host: '127.0.0.1', port: 5672, ssl: false, vhost: '/', username: 'guest', password: 'guest'} }
46
47
  let(:message) { Oj.dump({'pay' => 'load'}) }
48
+ let(:delete_queues) { [] }
47
49
 
48
50
  describe '#run' do
49
51
  before do
@@ -9,26 +9,27 @@ RSpec.describe Lapine::Consumer::Topology do
9
9
 
10
10
  let(:topics) {
11
11
  [
12
- "a.topic",
13
- "b.topic"
12
+ 'a.topic',
13
+ 'b.topic'
14
14
  ]
15
15
  }
16
16
  let(:queues) {
17
17
  [{
18
- "q" => "store.buyable",
19
- "topic" => "a.topic",
20
- "routing_key" =>
21
- "store.buyable.update",
22
- "handlers" => ["MessageBusTest::Clazz"]
18
+ 'q' => 'store.buyable',
19
+ 'topic' => 'a.topic',
20
+ 'routing_key' => 'store.buyable.update',
21
+ 'handlers' => ['MessageBusTest::Clazz']
23
22
  }]
24
23
  }
25
24
  let(:connection_properties) {
26
25
  {}
27
26
  }
27
+ let(:queues_to_delete) { [] }
28
28
  let(:config) do
29
29
  double('config',
30
30
  topics: topics,
31
31
  queues: queues,
32
+ delete_queues: queues_to_delete,
32
33
  connection_properties: connection_properties,
33
34
  debug?: debug)
34
35
  end
@@ -37,33 +38,53 @@ RSpec.describe Lapine::Consumer::Topology do
37
38
  let(:debug) { false }
38
39
  let(:logger) { nil }
39
40
 
40
- describe "#each_topic" do
41
- it "yields correct dount" do
41
+ describe '#each_topic' do
42
+ it 'yields correct dount' do
42
43
  expect { |b| topology.each_topic(&b) }.to yield_control.twice
43
44
  end
44
45
 
45
- it "yields all topics in order" do
46
- expect { |b| topology.each_topic(&b) }.to yield_successive_args("a.topic", "b.topic")
46
+ it 'yields all topics in order' do
47
+ expect { |b| topology.each_topic(&b) }.to yield_successive_args('a.topic', 'b.topic')
47
48
  end
48
49
  end
49
50
 
50
- describe "#each_binding" do
51
+ describe '#each_queue_to_delete' do
52
+ let(:conn) { double('connection') }
53
+ let(:queues_to_delete) { [
54
+ {'q' => 'queue.name', 'topic' => 'a.topic', 'handlers' => ['MessageBusTest::Clazz']},
55
+ {'q' => 'other.queue.name', 'topic' => 'a.topic', 'handlers' => ['MessageBusTest::Clazz']}
56
+ ] }
57
+ before do
58
+ allow(Lapine::Consumer::Connection).to receive(:new) { conn }
59
+ end
60
+
61
+ it 'yields queue name with connection' do
62
+ expect { |b|
63
+ topology.each_queue_to_delete(&b)
64
+ }.to yield_successive_args(
65
+ ['queue.name', conn, nil, [MessageBusTest::Clazz]],
66
+ ['other.queue.name', conn, nil, [MessageBusTest::Clazz]]
67
+ )
68
+ end
69
+ end
70
+
71
+ describe '#each_binding' do
51
72
  let(:conn) { double('connection') }
52
73
 
53
74
  before do
54
75
  allow(Lapine::Consumer::Connection).to receive(:new) { conn }
55
76
  end
56
77
 
57
- it "yields correct count" do
78
+ it 'yields correct count' do
58
79
  expect { |b| topology.each_binding(&b) }.to yield_control.once
59
80
  end
60
81
 
61
- it "yields expected arguments" do
82
+ it 'yields expected arguments' do
62
83
  expect { |b|
63
84
  topology.each_binding(&b)
64
- }.to yield_with_args("store.buyable",
85
+ }.to yield_with_args('store.buyable',
65
86
  conn,
66
- "store.buyable.update",
87
+ 'store.buyable.update',
67
88
  [MessageBusTest::Clazz])
68
89
  end
69
90
 
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'lapine'
2
2
  require 'pry'
3
3
  require 'rspec/mocks'
4
+ require 'lapine/consumer/dispatcher'
5
+ require 'lapine/consumer/middleware'
4
6
 
5
7
  Dir[File.expand_path('../support/**/*.rb', __FILE__)].each do |f|
6
8
  require f
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lapine
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Saxby
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-17 00:00:00.000000000 Z
12
+ date: 2015-05-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: amqp