message-driver 0.3.0 → 0.4.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 +4 -4
- data/.rubocop.yml +18 -0
- data/.rubocop_todo.yml +160 -0
- data/.travis.yml +5 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile +9 -8
- data/Guardfile +14 -7
- data/README.md +2 -0
- data/Rakefile +16 -10
- data/examples/basic_producer_and_consumer/Gemfile +2 -2
- data/examples/basic_producer_and_consumer/common.rb +3 -3
- data/examples/basic_producer_and_consumer/consumer.rb +5 -5
- data/examples/basic_producer_and_consumer/producer.rb +7 -7
- data/features/CHANGELOG.md +5 -0
- data/features/message_consumers/transactional_ack_consumers.feature +1 -0
- data/features/rabbitmq_specific_features/publisher_acknowledgements.feature +51 -0
- data/features/step_definitions/error_handling_steps.rb +2 -2
- data/features/step_definitions/logging_steps.rb +4 -4
- data/features/step_definitions/message_consumers_steps.rb +8 -8
- data/features/step_definitions/rabbitmq_specific_steps.rb +10 -0
- data/features/step_definitions/steps.rb +15 -15
- data/features/support/env.rb +3 -0
- data/features/support/firewall_helper.rb +5 -6
- data/features/support/message_table_matcher.rb +3 -4
- data/features/support/no_error_matcher.rb +3 -3
- data/features/support/test_runner.rb +11 -3
- data/features/support/transforms.rb +1 -1
- data/lib/message-driver.rb +1 -1
- data/lib/message_driver.rb +0 -1
- data/lib/message_driver/adapters/base.rb +10 -10
- data/lib/message_driver/adapters/bunny_adapter.rb +57 -30
- data/lib/message_driver/adapters/in_memory_adapter.rb +4 -5
- data/lib/message_driver/adapters/stomp_adapter.rb +4 -6
- data/lib/message_driver/broker.rb +5 -4
- data/lib/message_driver/client.rb +6 -6
- data/lib/message_driver/destination.rb +2 -2
- data/lib/message_driver/errors.rb +1 -4
- data/lib/message_driver/logging.rb +1 -1
- data/lib/message_driver/message.rb +2 -2
- data/lib/message_driver/subscription.rb +1 -1
- data/lib/message_driver/version.rb +1 -1
- data/lib/{message_driver/vendor → vendor}/.document +0 -0
- data/lib/vendor/nesty.rb +1 -0
- data/lib/vendor/nesty/nested_error.rb +28 -0
- data/message-driver.gemspec +15 -14
- data/spec/integration/bunny/amqp_integration_spec.rb +43 -43
- data/spec/integration/bunny/bunny_adapter_spec.rb +117 -101
- data/spec/integration/in_memory/in_memory_adapter_spec.rb +35 -35
- data/spec/integration/stomp/stomp_adapter_spec.rb +42 -42
- data/spec/spec_helper.rb +4 -1
- data/spec/support/shared/adapter_examples.rb +7 -7
- data/spec/support/shared/client_ack_examples.rb +6 -6
- data/spec/support/shared/context_examples.rb +4 -4
- data/spec/support/shared/destination_examples.rb +10 -10
- data/spec/support/shared/subscription_examples.rb +29 -29
- data/spec/support/shared/transaction_examples.rb +10 -10
- data/spec/units/message_driver/adapters/base_spec.rb +19 -19
- data/spec/units/message_driver/broker_spec.rb +57 -58
- data/spec/units/message_driver/client_spec.rb +84 -84
- data/spec/units/message_driver/destination_spec.rb +4 -4
- data/spec/units/message_driver/message_spec.rb +19 -19
- data/spec/units/message_driver/subscription_spec.rb +4 -4
- data/test_lib/broker_config.rb +2 -2
- metadata +27 -6
- data/lib/message_driver/vendor/nesty.rb +0 -1
- data/lib/message_driver/vendor/nesty/nested_error.rb +0 -26
data/features/CHANGELOG.md
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
@bunny
|
2
|
+
Feature: Publisher Acknowledgements
|
3
|
+
|
4
|
+
RabbitMQ supports confirmation of published messages
|
5
|
+
See http://www.rabbitmq.com/confirms.html for details.
|
6
|
+
|
7
|
+
Verifying the publish of a single message and of a group of messages is
|
8
|
+
supported as described below.
|
9
|
+
|
10
|
+
Background:
|
11
|
+
Given I am connected to the broker
|
12
|
+
And I have a destination :publish_ack with no messages on it
|
13
|
+
|
14
|
+
Scenario: Publishing a single message with confirmations turned on
|
15
|
+
When I execute the following code
|
16
|
+
""""ruby
|
17
|
+
publish(:publish_ack, "Test Message", {}, confirm: true)
|
18
|
+
"""
|
19
|
+
|
20
|
+
Then I expect all the publishes to have been acknowledged
|
21
|
+
And I expect to find the following message on :publish_ack
|
22
|
+
| body |
|
23
|
+
| Test Message |
|
24
|
+
|
25
|
+
|
26
|
+
Scenario: Publishing a single message where confirmations are turned on by the destination
|
27
|
+
When I execute the following code
|
28
|
+
""""ruby
|
29
|
+
my_new_destination = MessageDriver::Client.dynamic_destination(:publish_ack, {}, {confirm: true})
|
30
|
+
my_new_destination.publish("Test Message")
|
31
|
+
"""
|
32
|
+
|
33
|
+
Then I expect all the publishes to have been acknowledged
|
34
|
+
And I expect to find the following message on :publish_ack
|
35
|
+
| body |
|
36
|
+
| Test Message |
|
37
|
+
|
38
|
+
|
39
|
+
Scenario: Publishing a batch of messages with confirmations turned on
|
40
|
+
When I execute the following code
|
41
|
+
""""ruby
|
42
|
+
with_message_transaction(type: :confirm_and_wait) do
|
43
|
+
50.times do |i|
|
44
|
+
publish(:publish_ack, "Test Message #{i}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
"""
|
48
|
+
|
49
|
+
Then I expect all the publishes to have been acknowledged
|
50
|
+
And I expect that we are not in transaction mode
|
51
|
+
And I expect to find 50 messages on :publish_ack
|
@@ -1,22 +1,22 @@
|
|
1
1
|
require 'logger'
|
2
2
|
|
3
|
-
LOG_FILE_NAME =
|
3
|
+
LOG_FILE_NAME = 'cucumber_log_file.log'
|
4
4
|
|
5
5
|
Given(/^I am logging to a log file(?: at the (#{STRING_OR_SYM}) level)?$/) do |level|
|
6
6
|
step "an empty file named \"#{LOG_FILE_NAME}\""
|
7
7
|
in_current_dir do
|
8
8
|
@logger = Logger.new(LOG_FILE_NAME)
|
9
9
|
end
|
10
|
-
step "I set the log level to #{level ||
|
10
|
+
step "I set the log level to #{level || 'info'}"
|
11
11
|
@orig_logger, MessageDriver.logger = MessageDriver.logger, @logger
|
12
12
|
end
|
13
13
|
|
14
14
|
Given(/^I set the log level to (#{STRING_OR_SYM})$/) do |level|
|
15
|
-
level = level ? level.to_s.upcase :
|
15
|
+
level = level ? level.to_s.upcase : 'INFO'
|
16
16
|
@logger.level = Logger::SEV_LABEL.find_index(level)
|
17
17
|
end
|
18
18
|
|
19
|
-
Then
|
19
|
+
Then 'the log file should contain:' do |string|
|
20
20
|
step "the file \"#{LOG_FILE_NAME}\" should contain:", string
|
21
21
|
end
|
22
22
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
Given
|
1
|
+
Given 'I have a message consumer' do |src|
|
2
2
|
test_runner.run_config_code(src)
|
3
3
|
expect(test_runner).to have_no_errors
|
4
4
|
end
|
@@ -7,18 +7,18 @@ Given(/^I subscribe to (#{STRING_OR_SYM}) with (#{STRING_OR_SYM})$/) do |destina
|
|
7
7
|
MessageDriver::Client[test_runner.broker_name].subscribe(destination, consumer)
|
8
8
|
end
|
9
9
|
|
10
|
-
Given
|
10
|
+
Given 'I create a subscription' do |src|
|
11
11
|
test_runner.run_test_code("@subscription = #{src}")
|
12
12
|
expect(test_runner).to have_no_errors
|
13
13
|
end
|
14
14
|
|
15
|
-
When
|
16
|
-
test_runner.run_test_code(
|
17
|
-
step
|
15
|
+
When 'I cancel the subscription' do
|
16
|
+
test_runner.run_test_code('@subscription.unsubscribe')
|
17
|
+
step 'I allow for processing'
|
18
18
|
end
|
19
19
|
|
20
|
-
When
|
21
|
-
step
|
22
|
-
step
|
20
|
+
When 'I let the subscription process' do
|
21
|
+
step 'I allow for processing'
|
22
|
+
step 'I cancel the subscription'
|
23
23
|
expect(test_runner).to have_no_errors
|
24
24
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Then 'I expect all the publishes to have been acknowledged' do
|
2
|
+
ctx = test_runner.fetch_current_adapter_context
|
3
|
+
expect(ctx.channel).to be_using_publisher_confirms
|
4
|
+
expect(ctx.channel.unconfirmed_set).to be_empty
|
5
|
+
end
|
6
|
+
|
7
|
+
Then 'I expect that we are not in transaction mode' do
|
8
|
+
ctx = test_runner.fetch_current_adapter_context
|
9
|
+
expect(ctx).not_to be_transactional
|
10
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
Given
|
1
|
+
Given 'I am connected to the broker' do
|
2
2
|
MessageDriver::Broker.configure(test_runner.broker_name, broker_config)
|
3
3
|
end
|
4
4
|
|
5
5
|
Given(/^I am connected to a broker named (#{STRING_OR_SYM})$/) do |broker_name|
|
6
6
|
test_runner.broker_name = broker_name
|
7
|
-
step
|
7
|
+
step 'I am connected to the broker'
|
8
8
|
end
|
9
9
|
|
10
|
-
Given
|
11
|
-
step
|
10
|
+
Given 'the following broker configuration' do |src|
|
11
|
+
step 'I am connected to the broker'
|
12
12
|
test_runner.run_config_code(src)
|
13
13
|
end
|
14
14
|
|
15
|
-
Given
|
15
|
+
Given 'I configure my broker as follows' do |src|
|
16
16
|
test_runner.run_config_code(src)
|
17
17
|
end
|
18
18
|
|
@@ -23,14 +23,14 @@ Given(/^I have a destination (#{STRING_OR_SYM})$/) do |destination|
|
|
23
23
|
end
|
24
24
|
|
25
25
|
Given(/^I have a destination (#{STRING_OR_SYM}) with no messages on it$/) do |destination|
|
26
|
-
dest = destination.
|
26
|
+
dest = destination.is_a?(Symbol) ? destination.inspect : destination.to_s
|
27
27
|
step "I have a destination #{dest}"
|
28
28
|
test_runner.purge_destination(destination)
|
29
29
|
end
|
30
30
|
|
31
31
|
Given(/^I have the following messages? on (#{STRING_OR_SYM})$/) do |destination, table|
|
32
32
|
test_runner.purge_destination(destination)
|
33
|
-
dest = destination.
|
33
|
+
dest = destination.is_a?(Symbol) ? destination.inspect : destination.to_s
|
34
34
|
step "I send the following messages to #{dest}", table
|
35
35
|
end
|
36
36
|
|
@@ -44,15 +44,15 @@ When(/^I send the following messages? to (#{STRING_OR_SYM})$/) do |destination,
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
When
|
47
|
+
When 'I execute the following code' do |src|
|
48
48
|
test_runner.run_test_code(src)
|
49
49
|
end
|
50
50
|
|
51
|
-
When
|
51
|
+
When 'I reset the context' do
|
52
52
|
MessageDriver::Client[test_runner.broker_name].current_adapter_context.invalidate
|
53
53
|
end
|
54
54
|
|
55
|
-
When
|
55
|
+
When 'I allow for processing' do
|
56
56
|
test_runner.pause_if_needed
|
57
57
|
end
|
58
58
|
|
@@ -70,7 +70,7 @@ Then(/^I expect to find the following (#{NUMBER}) messages? on (#{STRING_OR_SYM}
|
|
70
70
|
end
|
71
71
|
|
72
72
|
Then(/^I expect to find the following message on (#{STRING_OR_SYM})$/) do |destination, table|
|
73
|
-
dest = destination.
|
73
|
+
dest = destination.is_a?(Symbol) ? destination.inspect : destination.to_s
|
74
74
|
step "I expect to find the following 1 message on #{dest}", table
|
75
75
|
end
|
76
76
|
|
@@ -87,13 +87,13 @@ Then(/^I expect it to raise a (.*?) error$/) do |error_type|
|
|
87
87
|
test_runner.raised_error = nil
|
88
88
|
end
|
89
89
|
|
90
|
-
Then
|
90
|
+
Then 'I expect to have no errors' do
|
91
91
|
expect(test_runner).to have_no_errors
|
92
92
|
end
|
93
93
|
|
94
|
-
Then
|
95
|
-
step
|
96
|
-
step
|
94
|
+
Then 'I expect the following check to pass' do |src|
|
95
|
+
step 'I execute the following code', src
|
96
|
+
step 'I expect to have no errors'
|
97
97
|
end
|
98
98
|
|
99
99
|
Before do |current_scenario|
|
data/features/support/env.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module FirewallHelper
|
2
|
-
|
3
2
|
def self.port
|
4
3
|
BrokerConfig.current_adapter_port
|
5
4
|
end
|
@@ -7,18 +6,18 @@ module FirewallHelper
|
|
7
6
|
COMMANDS = {
|
8
7
|
darwin: {
|
9
8
|
setup: [
|
10
|
-
|
9
|
+
'lunchy stop rabbit'
|
11
10
|
],
|
12
11
|
teardown: [
|
13
|
-
|
12
|
+
'lunchy start rabbit'
|
14
13
|
]
|
15
14
|
},
|
16
15
|
linux: {
|
17
16
|
setup: [
|
18
|
-
|
17
|
+
'sudo service rabbitmq-server stop'
|
19
18
|
],
|
20
19
|
teardown: [
|
21
|
-
|
20
|
+
'sudo service rabbitmq-server start'
|
22
21
|
]
|
23
22
|
}
|
24
23
|
}
|
@@ -49,7 +48,7 @@ module FirewallHelper
|
|
49
48
|
end
|
50
49
|
|
51
50
|
def darwin?
|
52
|
-
system(
|
51
|
+
system('uname | grep Darwin')
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
@@ -4,10 +4,9 @@ RSpec::Matchers.define :match_message_table do |expected_tbl|
|
|
4
4
|
end
|
5
5
|
|
6
6
|
define_method :messages_to_hash do |messages|
|
7
|
-
messages.
|
8
|
-
expected_tbl.headers.
|
9
|
-
|
10
|
-
memo
|
7
|
+
messages.map do |msg|
|
8
|
+
expected_tbl.headers.each_with_object({}) do |method, hash|
|
9
|
+
hash[method] = msg.send(method)
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
RSpec::Matchers.define :have_no_errors do
|
2
2
|
match do |test_runner|
|
3
|
-
test_runner.raised_error
|
3
|
+
test_runner.raised_error.nil?
|
4
4
|
end
|
5
5
|
|
6
6
|
failure_message_for_should do |test_runner|
|
7
7
|
err = test_runner.raised_error
|
8
8
|
filtered = (err.backtrace || []).reject do |line|
|
9
|
-
Cucumber::Ast::StepInvocation::BACKTRACE_FILTER_PATTERNS.
|
9
|
+
Cucumber::Ast::StepInvocation::BACKTRACE_FILTER_PATTERNS.find { |p| line =~ p }
|
10
10
|
end
|
11
|
-
(["#{err.class}: #{err
|
11
|
+
(["#{err.class}: #{err}"]+filtered).join("\n ")
|
12
12
|
end
|
13
13
|
end
|
@@ -26,10 +26,14 @@ class TestRunner
|
|
26
26
|
destination = fetch_destination(destination_name)
|
27
27
|
pause_if_needed
|
28
28
|
result = []
|
29
|
-
|
29
|
+
loop do
|
30
30
|
msg = destination.pop_message
|
31
|
-
|
32
|
-
|
31
|
+
if msg.nil?
|
32
|
+
break
|
33
|
+
else
|
34
|
+
result << msg
|
35
|
+
end
|
36
|
+
end
|
33
37
|
result
|
34
38
|
end
|
35
39
|
|
@@ -53,6 +57,10 @@ class TestRunner
|
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
60
|
+
def fetch_current_adapter_context
|
61
|
+
MessageDriver::Client[self.broker_name].current_adapter_context
|
62
|
+
end
|
63
|
+
|
56
64
|
def publish_table_to_destination(destination, table)
|
57
65
|
table.hashes.each do |msg|
|
58
66
|
destination.publish(msg[:body], msg[:headers]||{}, msg[:properties]||{})
|
data/lib/message-driver.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require
|
1
|
+
require 'message_driver'
|
data/lib/message_driver.rb
CHANGED
@@ -9,8 +9,8 @@ module MessageDriver
|
|
9
9
|
@contexts ||= []
|
10
10
|
end
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
raise
|
12
|
+
def initialize(_broker, _configuration)
|
13
|
+
raise 'Must be implemented in subclass'
|
14
14
|
end
|
15
15
|
|
16
16
|
def new_context
|
@@ -20,7 +20,7 @@ module MessageDriver
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def build_context
|
23
|
-
raise
|
23
|
+
raise 'Must be implemented in subclass'
|
24
24
|
end
|
25
25
|
|
26
26
|
def reset_after_tests
|
@@ -47,20 +47,20 @@ module MessageDriver
|
|
47
47
|
@valid = true
|
48
48
|
end
|
49
49
|
|
50
|
-
def publish(
|
51
|
-
raise
|
50
|
+
def publish(_destination, _body, _headers={}, _properties={})
|
51
|
+
raise 'Must be implemented in subclass'
|
52
52
|
end
|
53
53
|
|
54
|
-
def pop_message(
|
55
|
-
raise
|
54
|
+
def pop_message(_destination, _options={})
|
55
|
+
raise 'Must be implemented in subclass'
|
56
56
|
end
|
57
57
|
|
58
|
-
def subscribe(
|
58
|
+
def subscribe(_destination, _options={}, &_consumer)
|
59
59
|
raise "#subscribe is not supported by #{adapter.class}"
|
60
60
|
end
|
61
61
|
|
62
|
-
def create_destination(
|
63
|
-
raise
|
62
|
+
def create_destination(_name, _dest_options={}, _message_props={})
|
63
|
+
raise 'Must be implemented in subclass'
|
64
64
|
end
|
65
65
|
|
66
66
|
def valid?
|
@@ -46,13 +46,13 @@ module MessageDriver
|
|
46
46
|
|
47
47
|
class QueueDestination < Destination
|
48
48
|
def after_initialize(adapter_context)
|
49
|
-
|
49
|
+
if @dest_options[:no_declare]
|
50
|
+
raise MessageDriver::Error, 'server-named queues must be declared, but you provided :no_declare => true' if @name.empty?
|
51
|
+
raise MessageDriver::Error, 'queues with bindings must be declared, but you provided :no_declare => true' if @dest_options[:bindings]
|
52
|
+
else
|
50
53
|
adapter_context.with_channel(false) do |ch|
|
51
54
|
bunny_queue(ch, true)
|
52
55
|
end
|
53
|
-
else
|
54
|
-
raise MessageDriver::Error, "server-named queues must be declared, but you provided :no_declare => true" if @name.empty?
|
55
|
-
raise MessageDriver::Error, "queues with bindings must be declared, but you provided :no_declare => true" if @dest_options[:bindings]
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -60,7 +60,7 @@ module MessageDriver
|
|
60
60
|
queue = channel.queue(@name, @dest_options)
|
61
61
|
if initialize
|
62
62
|
@name = queue.name
|
63
|
-
if bindings = @dest_options[:bindings]
|
63
|
+
if (bindings = @dest_options[:bindings])
|
64
64
|
bindings.each do |bnd|
|
65
65
|
raise MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
|
66
66
|
queue.bind(bnd[:source], bnd[:args]||{})
|
@@ -71,10 +71,10 @@ module MessageDriver
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def exchange_name
|
74
|
-
|
74
|
+
''
|
75
75
|
end
|
76
76
|
|
77
|
-
def routing_key(
|
77
|
+
def routing_key(_properties)
|
78
78
|
@name
|
79
79
|
end
|
80
80
|
|
@@ -93,14 +93,14 @@ module MessageDriver
|
|
93
93
|
|
94
94
|
class ExchangeDestination < Destination
|
95
95
|
def after_initialize(adapter_context)
|
96
|
-
if declare = @dest_options[:declare]
|
96
|
+
if (declare = @dest_options[:declare])
|
97
97
|
adapter_context.with_channel(false) do |ch|
|
98
98
|
type = declare.delete(:type)
|
99
|
-
raise MessageDriver::Error,
|
99
|
+
raise MessageDriver::Error, 'you must provide a valid exchange type' unless type
|
100
100
|
ch.exchange_declare(@name, type, declare)
|
101
101
|
end
|
102
102
|
end
|
103
|
-
if bindings = @dest_options[:bindings]
|
103
|
+
if (bindings = @dest_options[:bindings])
|
104
104
|
adapter_context.with_channel(false) do |ch|
|
105
105
|
bindings.each do |bnd|
|
106
106
|
raise MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
|
@@ -113,7 +113,7 @@ module MessageDriver
|
|
113
113
|
|
114
114
|
class Subscription < Subscription::Base
|
115
115
|
def start
|
116
|
-
raise MessageDriver::Error,
|
116
|
+
raise MessageDriver::Error, 'subscriptions are only supported with QueueDestinations' unless destination.is_a? QueueDestination
|
117
117
|
@sub_ctx = adapter.new_subscription_context(self)
|
118
118
|
@error_handler = options[:error_handler]
|
119
119
|
@ack_mode = case options[:ack]
|
@@ -141,10 +141,11 @@ module MessageDriver
|
|
141
141
|
end
|
142
142
|
|
143
143
|
private
|
144
|
+
|
144
145
|
def start_subscription
|
145
146
|
@sub_ctx.with_channel do |ch|
|
146
147
|
queue = destination.bunny_queue(@sub_ctx.channel)
|
147
|
-
if options.
|
148
|
+
if options.key? :prefetch_size
|
148
149
|
ch.prefetch(options[:prefetch_size])
|
149
150
|
end
|
150
151
|
@bunny_consumer = queue.subscribe(options.merge(manual_ack: true)) do |delivery_info, properties, payload|
|
@@ -213,7 +214,7 @@ module MessageDriver
|
|
213
214
|
def stop
|
214
215
|
begin
|
215
216
|
super
|
216
|
-
@connection.close
|
217
|
+
@connection.close unless @connection.nil?
|
217
218
|
rescue => e
|
218
219
|
logger.error "error while attempting connection close\n#{exception_to_str(e)}"
|
219
220
|
ensure
|
@@ -263,34 +264,48 @@ module MessageDriver
|
|
263
264
|
def begin_transaction(options={})
|
264
265
|
raise MessageDriver::TransactionError, "you can't begin another transaction, you are already in one!" if in_transaction?
|
265
266
|
@in_transaction = true
|
267
|
+
@in_confirms_transaction = true if options[:type] == :confirm_and_wait
|
266
268
|
end
|
267
269
|
|
268
270
|
def commit_transaction(channel_commit=false)
|
269
271
|
raise MessageDriver::TransactionError, "you can't finish the transaction unless you already in one!" if !in_transaction? && !channel_commit
|
270
272
|
begin
|
271
|
-
if
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
@
|
273
|
+
if @in_confirms_transaction
|
274
|
+
wait_for_confirms(@channel) unless @rollback_only
|
275
|
+
else
|
276
|
+
if is_transactional? && valid? && !@need_channel_reset
|
277
|
+
handle_errors do
|
278
|
+
if @rollback_only
|
279
|
+
@channel.tx_rollback
|
280
|
+
else
|
281
|
+
@channel.tx_commit
|
282
|
+
end
|
277
283
|
end
|
278
284
|
end
|
279
285
|
end
|
280
286
|
ensure
|
281
287
|
@rollback_only = false
|
282
288
|
@in_transaction = false
|
289
|
+
@in_confirms_transaction = false
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def wait_for_confirms(channel)
|
294
|
+
until channel.unconfirmed_set.empty?
|
295
|
+
channel.wait_for_confirms
|
283
296
|
end
|
284
297
|
end
|
298
|
+
private :wait_for_confirms
|
285
299
|
|
286
300
|
def rollback_transaction
|
287
301
|
@rollback_only = true
|
288
302
|
commit_transaction
|
289
303
|
end
|
290
304
|
|
291
|
-
def
|
305
|
+
def transactional?
|
292
306
|
@is_transactional
|
293
307
|
end
|
308
|
+
alias_method :is_transactional?, :transactional?
|
294
309
|
|
295
310
|
def in_transaction?
|
296
311
|
@in_transaction
|
@@ -298,8 +313,14 @@ module MessageDriver
|
|
298
313
|
|
299
314
|
def publish(destination, body, headers={}, properties={})
|
300
315
|
exchange, routing_key, props = *destination.publish_params(headers, properties)
|
316
|
+
confirm = props.delete(:confirm)
|
317
|
+
confirm = false if confirm.nil?
|
301
318
|
with_channel(true) do |ch|
|
319
|
+
if confirm == true
|
320
|
+
ch.confirm_select unless ch.using_publisher_confirms?
|
321
|
+
end
|
302
322
|
ch.basic_publish(body, exchange, routing_key, props)
|
323
|
+
ch.wait_for_confirms if confirm == true
|
303
324
|
end
|
304
325
|
end
|
305
326
|
|
@@ -309,7 +330,7 @@ module MessageDriver
|
|
309
330
|
with_channel(false) do |ch|
|
310
331
|
queue = ch.queue(destination.name, passive: true)
|
311
332
|
|
312
|
-
message = queue.pop(ack:
|
333
|
+
message = queue.pop(ack: options.fetch(:client_ack, false))
|
313
334
|
if message.nil? || message[0].nil?
|
314
335
|
nil
|
315
336
|
else
|
@@ -322,14 +343,14 @@ module MessageDriver
|
|
322
343
|
true
|
323
344
|
end
|
324
345
|
|
325
|
-
def ack_message(message,
|
346
|
+
def ack_message(message, _options={})
|
326
347
|
with_channel(true) do |ch|
|
327
348
|
ch.ack(message.delivery_tag)
|
328
349
|
end
|
329
350
|
end
|
330
351
|
|
331
352
|
def nack_message(message, options={})
|
332
|
-
requeue = options[:requeue].
|
353
|
+
requeue = options[:requeue].is_a?(FalseClass) ? false : true
|
333
354
|
with_channel(true) do |ch|
|
334
355
|
ch.reject(message.delivery_tag, requeue)
|
335
356
|
end
|
@@ -371,7 +392,7 @@ module MessageDriver
|
|
371
392
|
rescue Bunny::ChannelLevelException => e
|
372
393
|
@need_channel_reset = true
|
373
394
|
@rollback_only = true if in_transaction?
|
374
|
-
if e.
|
395
|
+
if e.is_a? Bunny::NotFound
|
375
396
|
raise MessageDriver::QueueNotFound.new(e.to_s, e)
|
376
397
|
else
|
377
398
|
raise MessageDriver::WrappedError.new(e.to_s, e)
|
@@ -389,12 +410,18 @@ module MessageDriver
|
|
389
410
|
|
390
411
|
def with_channel(require_commit=true)
|
391
412
|
raise MessageDriver::TransactionRollbackOnly if @rollback_only
|
392
|
-
raise MessageDriver::Error,
|
413
|
+
raise MessageDriver::Error, 'this adapter context is not valid!' unless valid?
|
393
414
|
@channel = adapter.connection.create_channel if @channel.nil?
|
394
415
|
reset_channel if @need_channel_reset
|
395
|
-
if in_transaction?
|
396
|
-
@
|
397
|
-
|
416
|
+
if in_transaction?
|
417
|
+
if @in_confirms_transaction
|
418
|
+
@channel.confirm_select unless @channel.using_publisher_confirmations?
|
419
|
+
else
|
420
|
+
unless is_transactional?
|
421
|
+
@channel.tx_select
|
422
|
+
@is_transactional = true
|
423
|
+
end
|
424
|
+
end
|
398
425
|
end
|
399
426
|
handle_errors do
|
400
427
|
result = yield @channel
|
@@ -430,10 +457,10 @@ module MessageDriver
|
|
430
457
|
end
|
431
458
|
|
432
459
|
def validate_bunny_version
|
433
|
-
required = Gem::Requirement.create('>= 1.
|
460
|
+
required = Gem::Requirement.create('>= 1.2.2')
|
434
461
|
current = Gem::Version.create(Bunny::VERSION)
|
435
462
|
unless required.satisfied_by? current
|
436
|
-
raise MessageDriver::Error,
|
463
|
+
raise MessageDriver::Error, 'bunny 1.2.2 or later is required for the bunny adapter'
|
437
464
|
end
|
438
465
|
end
|
439
466
|
end
|