msgr 0.15.2.1.b175 → 0.15.2.1.b178
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 +4 -4
- data/README.md +28 -1
- data/lib/msgr/binding.rb +5 -4
- data/lib/msgr/channel.rb +65 -0
- data/lib/msgr/connection.rb +11 -52
- data/lib/msgr/consumer.rb +10 -0
- data/lib/msgr/dispatcher.rb +2 -2
- data/lib/msgr/message.rb +4 -4
- data/lib/msgr/route.rb +4 -0
- data/lib/msgr.rb +1 -0
- data/spec/integration/msgr/dispatcher_spec.rb +3 -3
- data/spec/msgr/msgr/dispatcher_spec.rb +44 -0
- data/spec/msgr/msgr_spec.rb +32 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1c2aba57e013a4e5972ec47493539cb0b8a0ccfafd94279fc8040000aab0a8f5
|
|
4
|
+
data.tar.gz: c6d5c25f205476087f183d1b59abcad36d1bf1877ebf0f1015e870d0ccb302c7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1fd16f2b6f7414ef21dab90dad31170c0de7dc833f2a6f1737d47ff45476505aa179a4d184c27bb92446570225aa8b8a478d99690992c980199e43a07be8168e
|
|
7
|
+
data.tar.gz: fcc9d1e8251987c80958538c468c7c20fb9a526b0f4b777a08bc26f8cfacf1a4f58c22b76ad06230a79c657a7a1e594f5453b5080b2c04da44576ab621188129
|
data/README.md
CHANGED
|
@@ -83,7 +83,34 @@ class TestController < ApplicationController
|
|
|
83
83
|
end
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
##
|
|
86
|
+
## Advanced configuration
|
|
87
|
+
|
|
88
|
+
### Manual message acknowledgement
|
|
89
|
+
|
|
90
|
+
Per default messages are automatically acknowledged, if no (n)ack is sent explicitly by the consumer. This can be disabled by setting the `auto_ack` attribute to `false`.
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
class TestConsumer < Msgr::Consumer
|
|
94
|
+
self.auto_ack = false
|
|
95
|
+
|
|
96
|
+
def index
|
|
97
|
+
data = { fuubar: 'abc' }
|
|
98
|
+
|
|
99
|
+
publish data, to: 'local.test.another_action'
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
### Prefetch count
|
|
106
|
+
|
|
107
|
+
Per default each message queue has a prefetch count of 1. This value can be changed when specifying the messaging routes:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
route 'local.test.index', to: 'test#index', prefetch: 42
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Msgr and fork web server like unicorn
|
|
87
114
|
|
|
88
115
|
Per default msgr opens the rabbitmq connect when rails is loaded. If you use a multi-process web server that preloads the application (like unicorn) will lead to unexpected behavior. In this case adjust `config/rabbitmq.yml` and adjust `autostart = false`:
|
|
89
116
|
|
data/lib/msgr/binding.rb
CHANGED
|
@@ -4,18 +4,19 @@ module Msgr
|
|
|
4
4
|
class Binding
|
|
5
5
|
include Logging
|
|
6
6
|
|
|
7
|
-
attr_reader :queue, :subscription, :connection, :route, :dispatcher
|
|
7
|
+
attr_reader :queue, :subscription, :connection, :channel, :route, :dispatcher
|
|
8
8
|
|
|
9
9
|
def initialize(connection, route, dispatcher)
|
|
10
10
|
@connection = connection
|
|
11
|
+
@channel = connection.channel(prefetch: route.prefetch)
|
|
11
12
|
@route = route
|
|
12
13
|
@dispatcher = dispatcher
|
|
13
|
-
@queue =
|
|
14
|
+
@queue = @channel.queue(route.name)
|
|
14
15
|
|
|
15
16
|
route.keys.each do |key|
|
|
16
17
|
log(:debug) { "Bind #{key} to #{queue.name}." }
|
|
17
18
|
|
|
18
|
-
queue.bind
|
|
19
|
+
queue.bind @channel.exchange, routing_key: key
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
subscribe
|
|
@@ -43,7 +44,7 @@ module Msgr
|
|
|
43
44
|
def subscribe
|
|
44
45
|
@subscription = queue.subscribe(manual_ack: true) do |*args|
|
|
45
46
|
begin
|
|
46
|
-
dispatcher.call Message.new(
|
|
47
|
+
dispatcher.call Message.new(channel, *args, route)
|
|
47
48
|
rescue => err
|
|
48
49
|
log(:error) do
|
|
49
50
|
"Rescued error from subscribe: #{err.class.name}: " \
|
data/lib/msgr/channel.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Msgr
|
|
2
|
+
class Channel
|
|
3
|
+
include Logging
|
|
4
|
+
|
|
5
|
+
EXCHANGE_NAME = 'msgr'
|
|
6
|
+
|
|
7
|
+
attr_reader :config, :channel
|
|
8
|
+
|
|
9
|
+
def initialize(config, connection)
|
|
10
|
+
@config = config
|
|
11
|
+
@channel = connection.create_channel
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def prefetch(count)
|
|
15
|
+
@channel.prefetch count
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def exchange
|
|
19
|
+
@exchange ||= begin
|
|
20
|
+
@channel.topic(prefix(EXCHANGE_NAME), durable: true).tap do |ex|
|
|
21
|
+
log(:debug) do
|
|
22
|
+
"Created exchange #{ex.name} (type: #{ex.type}, " \
|
|
23
|
+
"durable: #{ex.durable?}, auto_delete: #{ex.auto_delete?})"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def queue(name)
|
|
30
|
+
@channel.queue(prefix(name), durable: true).tap do |queue|
|
|
31
|
+
log(:debug) do
|
|
32
|
+
"Create queue #{queue.name} (durable: #{queue.durable?}, " \
|
|
33
|
+
"auto_delete: #{queue.auto_delete?})"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def prefix(name)
|
|
39
|
+
if config[:prefix].present?
|
|
40
|
+
"#{config[:prefix]}-#{name}"
|
|
41
|
+
else
|
|
42
|
+
name
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def ack(delivery_tag)
|
|
47
|
+
@channel.ack delivery_tag
|
|
48
|
+
log(:debug) { "Acked message: #{delivery_tag}" }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def nack(delivery_tag)
|
|
52
|
+
@channel.nack delivery_tag, false, true
|
|
53
|
+
log(:debug) { "Nacked message: #{delivery_tag}" }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def reject(delivery_tag, requeue = true)
|
|
57
|
+
@channel.reject delivery_tag, requeue
|
|
58
|
+
log(:debug) { "Rejected message: #{delivery_tag}" }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def close
|
|
62
|
+
@channel.close if @channel.open?
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/lib/msgr/connection.rb
CHANGED
|
@@ -8,14 +8,13 @@ module Msgr
|
|
|
8
8
|
class Connection
|
|
9
9
|
include Logging
|
|
10
10
|
|
|
11
|
-
EXCHANGE_NAME = 'msgr'
|
|
12
|
-
|
|
13
11
|
attr_reader :uri, :config
|
|
14
12
|
|
|
15
13
|
def initialize(uri, config, dispatcher)
|
|
16
14
|
@uri = uri
|
|
17
15
|
@config = config
|
|
18
16
|
@dispatcher = dispatcher
|
|
17
|
+
@channels = []
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
def running?
|
|
@@ -38,12 +37,15 @@ module Msgr
|
|
|
38
37
|
connection
|
|
39
38
|
end
|
|
40
39
|
|
|
41
|
-
def channel
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
def channel(prefetch: 1)
|
|
41
|
+
channel = Msgr::Channel.new(config, connection)
|
|
42
|
+
channel.prefetch(prefetch)
|
|
43
|
+
@channels << channel
|
|
44
|
+
channel
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def exchange
|
|
48
|
+
@exchange ||= channel.exchange
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
def release
|
|
@@ -71,34 +73,6 @@ module Msgr
|
|
|
71
73
|
@bindings ||= []
|
|
72
74
|
end
|
|
73
75
|
|
|
74
|
-
def prefix(name)
|
|
75
|
-
if config[:prefix].present?
|
|
76
|
-
"#{config[:prefix]}-#{name}"
|
|
77
|
-
else
|
|
78
|
-
name
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def exchange
|
|
83
|
-
@exchange ||= begin
|
|
84
|
-
channel.topic(prefix(EXCHANGE_NAME), durable: true).tap do |ex|
|
|
85
|
-
log(:debug) do
|
|
86
|
-
"Created exchange #{ex.name} (type: #{ex.type}, " \
|
|
87
|
-
"durable: #{ex.durable?}, auto_delete: #{ex.auto_delete?})"
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def queue(name)
|
|
94
|
-
channel.queue(prefix(name), durable: true).tap do |queue|
|
|
95
|
-
log(:debug) do
|
|
96
|
-
"Create queue #{queue.name} (durable: #{queue.durable?}, " \
|
|
97
|
-
"auto_delete: #{queue.auto_delete?})"
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
76
|
def bind(routes)
|
|
103
77
|
if routes.empty?
|
|
104
78
|
log(:warn) do
|
|
@@ -110,23 +84,8 @@ module Msgr
|
|
|
110
84
|
end
|
|
111
85
|
end
|
|
112
86
|
|
|
113
|
-
def ack(delivery_tag)
|
|
114
|
-
channel.ack delivery_tag
|
|
115
|
-
log(:debug) { "Acked message: #{delivery_tag}" }
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def nack(delivery_tag)
|
|
119
|
-
channel.nack delivery_tag, false, true
|
|
120
|
-
log(:debug) { "Nacked message: #{delivery_tag}" }
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def reject(delivery_tag, requeue = true)
|
|
124
|
-
channel.reject delivery_tag, requeue
|
|
125
|
-
log(:debug) { "Rejected message: #{delivery_tag}" }
|
|
126
|
-
end
|
|
127
|
-
|
|
128
87
|
def close
|
|
129
|
-
|
|
88
|
+
@channels.each(&:close)
|
|
130
89
|
connection.close if @connection
|
|
131
90
|
log(:debug) { 'Closed.' }
|
|
132
91
|
end
|
data/lib/msgr/consumer.rb
CHANGED
|
@@ -9,6 +9,16 @@ module Msgr
|
|
|
9
9
|
delegate :action, to: :'@message.route'
|
|
10
10
|
delegate :consumer, to: :'@message.consumer'
|
|
11
11
|
|
|
12
|
+
class << self
|
|
13
|
+
def auto_ack?
|
|
14
|
+
@auto_ack || @auto_ack.nil?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def auto_ack=(val)
|
|
18
|
+
@auto_ack = val
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
12
22
|
def dispatch(message)
|
|
13
23
|
@message = message
|
|
14
24
|
|
data/lib/msgr/dispatcher.rb
CHANGED
|
@@ -37,8 +37,8 @@ module Msgr
|
|
|
37
37
|
|
|
38
38
|
consumer_class.new.dispatch message
|
|
39
39
|
|
|
40
|
-
# Acknowledge message unless it is already acknowledged.
|
|
41
|
-
message.ack unless message.acked?
|
|
40
|
+
# Acknowledge message unless it is already acknowledged or auto_ack is disabled.
|
|
41
|
+
message.ack unless message.acked? or not consumer_class.auto_ack?
|
|
42
42
|
rescue => error
|
|
43
43
|
message.nack unless message.acked?
|
|
44
44
|
|
data/lib/msgr/message.rb
CHANGED
|
@@ -4,8 +4,8 @@ module Msgr
|
|
|
4
4
|
class Message
|
|
5
5
|
attr_reader :delivery_info, :metadata, :payload, :route
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
8
|
-
@
|
|
7
|
+
def initialize(channel, delivery_info, metadata, payload, route)
|
|
8
|
+
@channel = channel
|
|
9
9
|
@delivery_info = delivery_info
|
|
10
10
|
@metadata = metadata
|
|
11
11
|
@payload = payload
|
|
@@ -40,7 +40,7 @@ module Msgr
|
|
|
40
40
|
return if acked?
|
|
41
41
|
|
|
42
42
|
@acked = true
|
|
43
|
-
@
|
|
43
|
+
@channel.ack delivery_info.delivery_tag
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# Send negative message acknowledge to broker unless
|
|
@@ -52,7 +52,7 @@ module Msgr
|
|
|
52
52
|
return if acked?
|
|
53
53
|
|
|
54
54
|
@acked = true
|
|
55
|
-
@
|
|
55
|
+
@channel.nack delivery_info.delivery_tag
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
data/lib/msgr/route.rb
CHANGED
data/lib/msgr.rb
CHANGED
|
@@ -24,8 +24,8 @@ describe Msgr::Dispatcher do
|
|
|
24
24
|
allow(t).to receive(:action).and_return 'index'
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
|
-
let(:
|
|
28
|
-
double(:
|
|
27
|
+
let(:channel) do
|
|
28
|
+
double(:channel).tap do |c|
|
|
29
29
|
allow(c).to receive(:ack)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
@@ -40,7 +40,7 @@ describe Msgr::Dispatcher do
|
|
|
40
40
|
allow(metadata).to receive(:content_type).and_return('text/plain')
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
|
-
let(:message) { Msgr::Message.new
|
|
43
|
+
let(:message) { Msgr::Message.new channel, delivery_info, metadata, payload, route }
|
|
44
44
|
let(:action) { -> { dispatcher.call message } }
|
|
45
45
|
|
|
46
46
|
it 'should consume message' do
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
class MsgrAutoAckConsumer < Msgr::Consumer
|
|
6
|
+
self.auto_ack = true
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class MsgrManualAckConsumer < Msgr::Consumer
|
|
13
|
+
self.auto_ack = false
|
|
14
|
+
|
|
15
|
+
def index
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe Msgr::Dispatcher do
|
|
20
|
+
let(:config) { {} }
|
|
21
|
+
let(:args) { [config] }
|
|
22
|
+
let(:dispatcher) { Msgr::Dispatcher.new(*args) }
|
|
23
|
+
subject { dispatcher }
|
|
24
|
+
|
|
25
|
+
describe 'dispatch' do
|
|
26
|
+
it 'should ack messages automatically if auto_ack is enabled' do
|
|
27
|
+
route_db = double('Route', :consumer => 'MsgrAutoAckConsumer', :action => :index)
|
|
28
|
+
msg_db = double('Message', :route => route_db, :acked? => false)
|
|
29
|
+
expect(msg_db).to receive(:ack)
|
|
30
|
+
expect(msg_db).not_to receive(:nack)
|
|
31
|
+
|
|
32
|
+
dispatcher.dispatch(msg_db)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'should not ack messages if auto_ack is disabled' do
|
|
36
|
+
route_db = double('Route', :consumer => 'MsgrManualAckConsumer', :action => :index)
|
|
37
|
+
msg_db = double('Message', :route => route_db, :acked? => false)
|
|
38
|
+
expect(msg_db).not_to receive(:ack)
|
|
39
|
+
expect(msg_db).not_to receive(:nack)
|
|
40
|
+
|
|
41
|
+
dispatcher.dispatch(msg_db)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/spec/msgr/msgr_spec.rb
CHANGED
|
@@ -16,6 +16,14 @@ class MsgrTestConsumer < Msgr::Consumer
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
class MsgrPrefetchTestConsumer < Msgr::Consumer
|
|
20
|
+
self.auto_ack = false
|
|
21
|
+
|
|
22
|
+
def index
|
|
23
|
+
Receiver.batch message
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
19
27
|
describe Msgr do
|
|
20
28
|
let(:queue) { Queue.new }
|
|
21
29
|
let(:client) { Msgr::Client.new size: 1, prefix: SecureRandom.hex(2) }
|
|
@@ -24,6 +32,7 @@ describe Msgr do
|
|
|
24
32
|
client.routes.configure do
|
|
25
33
|
route 'test.index', to: 'msgr_test#index'
|
|
26
34
|
route 'test.error', to: 'msgr_test#error'
|
|
35
|
+
route 'test.batch', to: 'msgr_prefetch_test#index', prefetch: 2
|
|
27
36
|
end
|
|
28
37
|
|
|
29
38
|
client.start
|
|
@@ -49,4 +58,27 @@ describe Msgr do
|
|
|
49
58
|
|
|
50
59
|
Timeout.timeout(4) { queue.pop }
|
|
51
60
|
end
|
|
61
|
+
|
|
62
|
+
it 'should receive 2 messages when prefetch is set to 2' do
|
|
63
|
+
expect(Receiver).to receive(:batch).twice { |msg| queue << msg }
|
|
64
|
+
|
|
65
|
+
2.times { client.publish 'Payload', to: 'test.batch' }
|
|
66
|
+
|
|
67
|
+
2.times { Timeout.timeout(4) { queue.pop } }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'should not bulk ack all unacknowledged messages when acknowledging the last one' do
|
|
71
|
+
expect(Receiver).to receive(:batch).exactly(3).times { |msg| queue << msg }
|
|
72
|
+
|
|
73
|
+
2.times { client.publish 'Payload', to: 'test.batch' }
|
|
74
|
+
|
|
75
|
+
messages = 2.times.map { Timeout.timeout(4) { queue.pop } }
|
|
76
|
+
messages[1].ack
|
|
77
|
+
messages[0].nack
|
|
78
|
+
|
|
79
|
+
# Test whether the nacked message gets redelivered. In this case, it was not acked when acknowledging the other message
|
|
80
|
+
message = Timeout.timeout(4) { queue.pop }
|
|
81
|
+
expect(message.payload).to eq(messages[0].payload)
|
|
82
|
+
expect(message.delivery_info.redelivered).to eq(true)
|
|
83
|
+
end
|
|
52
84
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: msgr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.15.2.1.
|
|
4
|
+
version: 0.15.2.1.b178
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jan Graichen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-12-
|
|
11
|
+
date: 2017-12-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -93,6 +93,7 @@ files:
|
|
|
93
93
|
- gemfiles/Gemfile.rails-master
|
|
94
94
|
- lib/msgr.rb
|
|
95
95
|
- lib/msgr/binding.rb
|
|
96
|
+
- lib/msgr/channel.rb
|
|
96
97
|
- lib/msgr/client.rb
|
|
97
98
|
- lib/msgr/connection.rb
|
|
98
99
|
- lib/msgr/consumer.rb
|
|
@@ -139,6 +140,7 @@ files:
|
|
|
139
140
|
- spec/msgr/msgr/client_spec.rb
|
|
140
141
|
- spec/msgr/msgr/connection_spec.rb
|
|
141
142
|
- spec/msgr/msgr/consumer_spec.rb
|
|
143
|
+
- spec/msgr/msgr/dispatcher_spec.rb
|
|
142
144
|
- spec/msgr/msgr/route_spec.rb
|
|
143
145
|
- spec/msgr/msgr/routes_spec.rb
|
|
144
146
|
- spec/msgr/msgr_spec.rb
|
|
@@ -202,6 +204,7 @@ test_files:
|
|
|
202
204
|
- spec/msgr/msgr/client_spec.rb
|
|
203
205
|
- spec/msgr/msgr/connection_spec.rb
|
|
204
206
|
- spec/msgr/msgr/consumer_spec.rb
|
|
207
|
+
- spec/msgr/msgr/dispatcher_spec.rb
|
|
205
208
|
- spec/msgr/msgr/route_spec.rb
|
|
206
209
|
- spec/msgr/msgr/routes_spec.rb
|
|
207
210
|
- spec/msgr/msgr_spec.rb
|