lapine 1.1.3 → 1.2.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: 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