message-driver 0.6.1 → 0.7.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 +20 -2
- data/.rubocop_todo.yml +15 -23
- data/.travis.yml +10 -22
- data/CHANGELOG.md +9 -0
- data/Gemfile +34 -24
- data/Guardfile +46 -29
- data/LICENSE +1 -1
- data/Rakefile +14 -6
- data/features/CHANGELOG.md +1 -0
- data/features/step_definitions/logging_steps.rb +3 -2
- data/features/support/firewall_helper.rb +2 -2
- data/features/support/no_error_matcher.rb +1 -1
- data/lib/message_driver/adapters/base.rb +115 -11
- data/lib/message_driver/adapters/bunny_adapter.rb +58 -46
- data/lib/message_driver/adapters/in_memory_adapter.rb +57 -35
- data/lib/message_driver/adapters/stomp_adapter.rb +10 -10
- data/lib/message_driver/broker.rb +16 -19
- data/lib/message_driver/client.rb +3 -7
- data/lib/message_driver/destination.rb +4 -4
- data/lib/message_driver/message.rb +3 -2
- data/lib/message_driver/middleware/block_middleware.rb +1 -1
- data/lib/message_driver/subscription.rb +1 -1
- data/lib/message_driver/version.rb +1 -1
- data/message-driver.gemspec +6 -6
- data/spec/integration/bunny/amqp_integration_spec.rb +6 -4
- data/spec/integration/bunny/bunny_adapter_spec.rb +1 -3
- data/spec/integration/in_memory/in_memory_adapter_spec.rb +46 -6
- data/spec/integration/stomp/stomp_adapter_spec.rb +0 -2
- data/spec/spec_helper.rb +6 -0
- data/spec/support/matchers/override_method_matcher.rb +7 -0
- data/spec/support/shared/adapter_examples.rb +3 -0
- data/spec/support/shared/client_ack_examples.rb +26 -4
- data/spec/support/shared/context_examples.rb +46 -0
- data/spec/support/shared/destination_examples.rb +28 -0
- data/spec/support/shared/subscription_examples.rb +6 -1
- data/spec/support/shared/transaction_examples.rb +35 -4
- data/spec/support/test_adapter.rb +19 -0
- data/spec/support/utils.rb +1 -5
- data/spec/units/message_driver/adapters/base_spec.rb +37 -31
- data/spec/units/message_driver/broker_spec.rb +1 -2
- data/spec/units/message_driver/client_spec.rb +3 -3
- data/spec/units/message_driver/destination_spec.rb +4 -2
- data/spec/units/message_driver/message_spec.rb +9 -3
- data/test_lib/broker_config.rb +0 -2
- data/test_lib/provider/base.rb +2 -6
- data/test_lib/provider/rabbitmq.rb +3 -3
- metadata +18 -16
- data/ci/travis_setup +0 -7
- data/features/CHANGELOG.md +0 -102
@@ -20,7 +20,7 @@ module FirewallHelper
|
|
20
20
|
'sudo service rabbitmq-server start'
|
21
21
|
]
|
22
22
|
}
|
23
|
-
}
|
23
|
+
}.freeze
|
24
24
|
|
25
25
|
def block_broker_port
|
26
26
|
run_commands(:setup)
|
@@ -35,7 +35,7 @@ module FirewallHelper
|
|
35
35
|
def run_commands(step)
|
36
36
|
COMMANDS[os][step].each do |cmd|
|
37
37
|
result = system(cmd)
|
38
|
-
|
38
|
+
raise "command `#{cmd}` failed!" unless result
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -6,7 +6,7 @@ RSpec::Matchers.define :have_no_errors do
|
|
6
6
|
failure_message do |test_runner|
|
7
7
|
err = test_runner.raised_error
|
8
8
|
filtered = (err.backtrace || []).reject do |line|
|
9
|
-
Cucumber::
|
9
|
+
Cucumber::Formatter::BACKTRACE_FILTER_PATTERNS.find { |p| line =~ p }
|
10
10
|
end
|
11
11
|
(["#{err.class}: #{err}"] + filtered).join("\n ")
|
12
12
|
end
|
@@ -10,7 +10,7 @@ module MessageDriver
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def initialize(_broker, _configuration)
|
13
|
-
|
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
|
-
|
23
|
+
raise 'Must be implemented in subclass'
|
24
24
|
end
|
25
25
|
|
26
26
|
def reset_after_tests
|
@@ -31,7 +31,7 @@ module MessageDriver
|
|
31
31
|
if @contexts
|
32
32
|
ctxs = @contexts
|
33
33
|
@contexts = []
|
34
|
-
ctxs.each
|
34
|
+
ctxs.each(&:invalidate)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -47,20 +47,56 @@ module MessageDriver
|
|
47
47
|
@valid = true
|
48
48
|
end
|
49
49
|
|
50
|
-
def publish(
|
51
|
-
|
50
|
+
def publish(destination, body, headers = {}, properties = {})
|
51
|
+
handle_publish(destination, body, headers, properties)
|
52
52
|
end
|
53
53
|
|
54
|
-
def pop_message(
|
55
|
-
|
54
|
+
def pop_message(destination, options = {})
|
55
|
+
handle_pop_message(destination, options)
|
56
56
|
end
|
57
57
|
|
58
|
-
def subscribe(
|
59
|
-
|
58
|
+
def subscribe(destination, options = {}, &consumer)
|
59
|
+
handle_subscribe(destination, options, &consumer)
|
60
60
|
end
|
61
61
|
|
62
|
-
def create_destination(
|
63
|
-
|
62
|
+
def create_destination(name, dest_options = {}, message_props = {})
|
63
|
+
handle_create_destination(name, dest_options, message_props)
|
64
|
+
end
|
65
|
+
|
66
|
+
def ack_message(message, options = {})
|
67
|
+
handle_ack_message(message, options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def nack_message(message, options = {})
|
71
|
+
handle_nack_message(message, options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def begin_transaction(options = {})
|
75
|
+
handle_begin_transaction(options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def commit_transaction(options = {})
|
79
|
+
handle_commit_transaction(options)
|
80
|
+
end
|
81
|
+
|
82
|
+
def rollback_transaction(options = {})
|
83
|
+
handle_rollback_transaction(options)
|
84
|
+
end
|
85
|
+
|
86
|
+
def message_count(destination)
|
87
|
+
handle_message_count(destination)
|
88
|
+
end
|
89
|
+
|
90
|
+
def consumer_count(destination)
|
91
|
+
handle_consumer_count(destination)
|
92
|
+
end
|
93
|
+
|
94
|
+
def in_transaction?
|
95
|
+
if supports_transactions?
|
96
|
+
raise 'must be implemented in subclass'
|
97
|
+
else
|
98
|
+
raise "#in_transaction? not supported by #{adapter.class}"
|
99
|
+
end
|
64
100
|
end
|
65
101
|
|
66
102
|
def valid?
|
@@ -82,6 +118,74 @@ module MessageDriver
|
|
82
118
|
def supports_subscriptions?
|
83
119
|
false
|
84
120
|
end
|
121
|
+
|
122
|
+
def handle_create_destination(_name, _dest_options = {}, _message_props = {})
|
123
|
+
raise 'Must be implemented in subclass'
|
124
|
+
end
|
125
|
+
|
126
|
+
def handle_publish(_destination, _body, _headers = {}, _properties = {})
|
127
|
+
raise 'Must be implemented in subclass'
|
128
|
+
end
|
129
|
+
|
130
|
+
def handle_pop_message(_destination, _options = {})
|
131
|
+
raise 'Must be implemented in subclass'
|
132
|
+
end
|
133
|
+
|
134
|
+
def handle_subscribe(_destination, _options = {}, &_consumer)
|
135
|
+
if supports_subscriptions?
|
136
|
+
raise 'Must be implemented in subclass'
|
137
|
+
else
|
138
|
+
raise "#subscribe is not supported by #{adapter.class}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def handle_ack_message(_message, _options = {})
|
143
|
+
if supports_client_acks?
|
144
|
+
raise 'Must be implemented in subclass'
|
145
|
+
else
|
146
|
+
raise "#ack_message is not supported by #{adapter.class}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def handle_nack_message(_message, _options = {})
|
151
|
+
if supports_client_acks?
|
152
|
+
raise 'Must be implemented in subclass'
|
153
|
+
else
|
154
|
+
raise "#nack_message is not supported by #{adapter.class}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def handle_begin_transaction(_options = {})
|
159
|
+
if supports_transactions?
|
160
|
+
raise 'Must be implemented in subclass'
|
161
|
+
else
|
162
|
+
raise "transactions are not supported by #{adapter.class}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def handle_commit_transaction(_options = {})
|
167
|
+
if supports_transactions?
|
168
|
+
raise 'Must be implemented in subclass'
|
169
|
+
else
|
170
|
+
raise "transactions are not supported by #{adapter.class}"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def handle_rollback_transaction(_options = {})
|
175
|
+
if supports_transactions?
|
176
|
+
raise 'Must be implemented in subclass'
|
177
|
+
else
|
178
|
+
raise "transactions are not supported by #{adapter.class}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def handle_message_count(destination)
|
183
|
+
raise "#message_count is not supported by #{destination.class}"
|
184
|
+
end
|
185
|
+
|
186
|
+
def handle_consumer_count(destination)
|
187
|
+
raise "#consumer_count is not supported by #{destination.class}"
|
188
|
+
end
|
85
189
|
end
|
86
190
|
end
|
87
191
|
end
|
@@ -25,7 +25,7 @@ module MessageDriver
|
|
25
25
|
raw_headers = properties[:headers]
|
26
26
|
raw_headers = {} if raw_headers.nil?
|
27
27
|
b, h, p = destination.middleware.on_consume(payload, raw_headers, properties)
|
28
|
-
super(ctx, b, h, p, raw_body)
|
28
|
+
super(ctx, destination, b, h, p, raw_body)
|
29
29
|
@delivery_info = delivery_info
|
30
30
|
end
|
31
31
|
|
@@ -59,10 +59,10 @@ module MessageDriver
|
|
59
59
|
def after_initialize(adapter_context)
|
60
60
|
if @dest_options[:no_declare]
|
61
61
|
if @name.empty?
|
62
|
-
|
62
|
+
raise MessageDriver::Error, 'server-named queues must be declared, but you provided :no_declare => true'
|
63
63
|
end
|
64
64
|
if @dest_options[:bindings]
|
65
|
-
|
65
|
+
raise MessageDriver::Error, 'queues with bindings must be declared, but you provided :no_declare => true'
|
66
66
|
end
|
67
67
|
else
|
68
68
|
adapter_context.with_channel(false) do |ch|
|
@@ -73,7 +73,7 @@ module MessageDriver
|
|
73
73
|
|
74
74
|
def bunny_queue(channel, options = {})
|
75
75
|
opts = @dest_options.dup
|
76
|
-
opts
|
76
|
+
opts[:passive] = options[:passive] if options.key? :passive
|
77
77
|
queue = channel.queue(@name, opts)
|
78
78
|
handle_queue_init(queue) if options.fetch(:init, false)
|
79
79
|
queue
|
@@ -83,7 +83,7 @@ module MessageDriver
|
|
83
83
|
@name = queue.name
|
84
84
|
if (bindings = @dest_options[:bindings])
|
85
85
|
bindings.each do |bnd|
|
86
|
-
|
86
|
+
raise MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
|
87
87
|
queue.bind(bnd[:source], bnd[:args] || {})
|
88
88
|
end
|
89
89
|
end
|
@@ -97,24 +97,24 @@ module MessageDriver
|
|
97
97
|
@name
|
98
98
|
end
|
99
99
|
|
100
|
-
def
|
101
|
-
|
100
|
+
def handle_message_count
|
101
|
+
current_adapter_context.with_channel(false) do |ch|
|
102
102
|
bunny_queue(ch, passive: true).message_count
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
106
|
def subscribe(options = {}, &consumer)
|
107
|
-
|
107
|
+
current_adapter_context.subscribe(self, options, &consumer)
|
108
108
|
end
|
109
109
|
|
110
|
-
def
|
111
|
-
|
110
|
+
def handle_consumer_count
|
111
|
+
current_adapter_context.with_channel(false) do |ch|
|
112
112
|
bunny_queue(ch, passive: true).consumer_count
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
116
|
def purge
|
117
|
-
|
117
|
+
current_adapter_context.with_channel(false) do |ch|
|
118
118
|
bunny_queue(ch).purge
|
119
119
|
end
|
120
120
|
end
|
@@ -125,14 +125,14 @@ module MessageDriver
|
|
125
125
|
if (declare = @dest_options[:declare])
|
126
126
|
adapter_context.with_channel(false) do |ch|
|
127
127
|
type = declare.delete(:type)
|
128
|
-
|
128
|
+
raise MessageDriver::Error, 'you must provide a valid exchange type' unless type
|
129
129
|
ch.exchange_declare(@name, type, declare)
|
130
130
|
end
|
131
131
|
end
|
132
132
|
if (bindings = @dest_options[:bindings])
|
133
133
|
adapter_context.with_channel(false) do |ch|
|
134
134
|
bindings.each do |bnd|
|
135
|
-
|
135
|
+
raise MessageDriver::Error, "binding #{bnd.inspect} must provide a source!" unless bnd[:source]
|
136
136
|
ch.exchange_bind(bnd[:source], @name, bnd[:args] || {})
|
137
137
|
end
|
138
138
|
end
|
@@ -145,8 +145,8 @@ module MessageDriver
|
|
145
145
|
|
146
146
|
def start
|
147
147
|
unless destination.is_a? QueueDestination
|
148
|
-
|
149
|
-
|
148
|
+
raise MessageDriver::Error,
|
149
|
+
'subscriptions are only supported with QueueDestinations'
|
150
150
|
end
|
151
151
|
@sub_ctx = adapter.new_subscription_context(self)
|
152
152
|
@error_handler = options[:error_handler]
|
@@ -158,7 +158,7 @@ module MessageDriver
|
|
158
158
|
when :transactional
|
159
159
|
TransactionalAckHandler.new(self)
|
160
160
|
else
|
161
|
-
|
161
|
+
raise MessageDriver::Error, "unrecognized :ack option #{options[:ack]}"
|
162
162
|
end
|
163
163
|
start_subscription
|
164
164
|
end
|
@@ -305,14 +305,14 @@ module MessageDriver
|
|
305
305
|
@require_commit = false
|
306
306
|
end
|
307
307
|
|
308
|
-
def
|
308
|
+
def handle_create_destination(name, dest_options = {}, message_props = {})
|
309
309
|
dest = case type = dest_options.delete(:type)
|
310
310
|
when :exchange
|
311
311
|
ExchangeDestination.new(adapter, name, dest_options, message_props)
|
312
312
|
when :queue, nil
|
313
313
|
QueueDestination.new(adapter, name, dest_options, message_props)
|
314
314
|
else
|
315
|
-
|
315
|
+
raise MessageDriver::Error, "invalid destination type #{type}"
|
316
316
|
end
|
317
317
|
dest.after_initialize(self)
|
318
318
|
dest
|
@@ -322,33 +322,29 @@ module MessageDriver
|
|
322
322
|
true
|
323
323
|
end
|
324
324
|
|
325
|
-
def
|
325
|
+
def handle_begin_transaction(options = {})
|
326
326
|
if in_transaction?
|
327
|
-
|
328
|
-
|
327
|
+
raise MessageDriver::TransactionError,
|
328
|
+
"you can't begin another transaction, you are already in one!"
|
329
329
|
end
|
330
330
|
@in_transaction = true
|
331
331
|
@in_confirms_transaction = true if options[:type] == :confirm_and_wait
|
332
332
|
end
|
333
333
|
|
334
|
-
def
|
334
|
+
def handle_commit_transaction(_ = nil)
|
335
335
|
if !in_transaction? && !@require_commit
|
336
|
-
|
337
|
-
|
336
|
+
raise MessageDriver::TransactionError,
|
337
|
+
"you can't finish the transaction unless you already in one!"
|
338
338
|
end
|
339
339
|
begin
|
340
340
|
if @in_confirms_transaction
|
341
|
-
unless @rollback_only || @channel.nil?
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
@channel.tx_rollback
|
349
|
-
else
|
350
|
-
@channel.tx_commit
|
351
|
-
end
|
341
|
+
@channel.wait_for_confirms unless @rollback_only || @channel.nil?
|
342
|
+
elsif is_transactional? && valid? && !@need_channel_reset && @require_commit
|
343
|
+
handle_errors do
|
344
|
+
if @rollback_only
|
345
|
+
@channel.tx_rollback
|
346
|
+
else
|
347
|
+
@channel.tx_commit
|
352
348
|
end
|
353
349
|
end
|
354
350
|
end
|
@@ -360,7 +356,7 @@ module MessageDriver
|
|
360
356
|
end
|
361
357
|
end
|
362
358
|
|
363
|
-
def
|
359
|
+
def handle_rollback_transaction(_ = nil)
|
364
360
|
@rollback_only = true
|
365
361
|
commit_transaction
|
366
362
|
end
|
@@ -368,13 +364,13 @@ module MessageDriver
|
|
368
364
|
def transactional?
|
369
365
|
@is_transactional
|
370
366
|
end
|
371
|
-
|
367
|
+
alias is_transactional? transactional?
|
372
368
|
|
373
369
|
def in_transaction?
|
374
370
|
@in_transaction
|
375
371
|
end
|
376
372
|
|
377
|
-
def
|
373
|
+
def handle_publish(destination, body, headers = {}, properties = {})
|
378
374
|
body, exchange, routing_key, props = *destination.publish_params(body, headers, properties)
|
379
375
|
confirm = props.delete(:confirm)
|
380
376
|
confirm = false if confirm.nil?
|
@@ -387,8 +383,8 @@ module MessageDriver
|
|
387
383
|
end
|
388
384
|
end
|
389
385
|
|
390
|
-
def
|
391
|
-
|
386
|
+
def handle_pop_message(destination, options = {})
|
387
|
+
raise MessageDriver::Error, "You can't pop a message off an exchange" if destination.is_a? ExchangeDestination
|
392
388
|
|
393
389
|
with_channel(false) do |ch|
|
394
390
|
queue = ch.queue(destination.name, passive: true)
|
@@ -406,13 +402,13 @@ module MessageDriver
|
|
406
402
|
true
|
407
403
|
end
|
408
404
|
|
409
|
-
def
|
405
|
+
def handle_ack_message(message, _options = {})
|
410
406
|
with_channel(true) do |ch|
|
411
407
|
ch.ack(message.delivery_tag)
|
412
408
|
end
|
413
409
|
end
|
414
410
|
|
415
|
-
def
|
411
|
+
def handle_nack_message(message, options = {})
|
416
412
|
requeue = options.fetch(:requeue, true)
|
417
413
|
with_channel(true) do |ch|
|
418
414
|
ch.reject(message.delivery_tag, requeue)
|
@@ -423,12 +419,28 @@ module MessageDriver
|
|
423
419
|
true
|
424
420
|
end
|
425
421
|
|
426
|
-
def
|
422
|
+
def handle_subscribe(destination, options = {}, &consumer)
|
427
423
|
sub = Subscription.new(adapter, destination, consumer, options)
|
428
424
|
sub.start
|
429
425
|
sub
|
430
426
|
end
|
431
427
|
|
428
|
+
def handle_message_count(destination)
|
429
|
+
if destination.respond_to?(:handle_message_count)
|
430
|
+
destination.handle_message_count
|
431
|
+
else
|
432
|
+
super
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def handle_consumer_count(destination)
|
437
|
+
if destination.respond_to?(:handle_consumer_count)
|
438
|
+
destination.handle_consumer_count
|
439
|
+
else
|
440
|
+
super
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
432
444
|
def invalidate(in_unsubscribe = false)
|
433
445
|
super()
|
434
446
|
unless @subscription.nil? || in_unsubscribe
|
@@ -488,8 +500,8 @@ module MessageDriver
|
|
488
500
|
end
|
489
501
|
|
490
502
|
def with_channel(require_commit = true)
|
491
|
-
|
492
|
-
|
503
|
+
raise MessageDriver::TransactionRollbackOnly if @rollback_only
|
504
|
+
raise MessageDriver::Error, 'this adapter context is not valid!' unless valid?
|
493
505
|
ensure_channel
|
494
506
|
@require_commit ||= require_commit
|
495
507
|
if in_transaction?
|
@@ -535,7 +547,7 @@ module MessageDriver
|
|
535
547
|
required = Gem::Requirement.create('>= 1.7.0')
|
536
548
|
current = Gem::Version.create(Bunny::VERSION)
|
537
549
|
unless required.satisfied_by? current
|
538
|
-
|
550
|
+
raise MessageDriver::Error, 'bunny 1.7.0 or later is required for the bunny adapter'
|
539
551
|
end
|
540
552
|
end
|
541
553
|
end
|