bunny 2.19.0 → 2.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -32
  3. data/lib/bunny/channel.rb +86 -10
  4. data/lib/bunny/consumer.rb +2 -2
  5. data/lib/bunny/delivery_info.rb +1 -1
  6. data/lib/bunny/queue.rb +33 -2
  7. data/lib/bunny/session.rb +1 -1
  8. data/lib/bunny/transport.rb +30 -1
  9. data/lib/bunny/version.rb +1 -1
  10. data/lib/bunny.rb +45 -4
  11. metadata +4 -144
  12. data/spec/config/enabled_plugins +0 -1
  13. data/spec/config/rabbitmq.conf +0 -13
  14. data/spec/higher_level_api/integration/basic_ack_spec.rb +0 -230
  15. data/spec/higher_level_api/integration/basic_cancel_spec.rb +0 -142
  16. data/spec/higher_level_api/integration/basic_consume_spec.rb +0 -357
  17. data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +0 -54
  18. data/spec/higher_level_api/integration/basic_get_spec.rb +0 -80
  19. data/spec/higher_level_api/integration/basic_nack_spec.rb +0 -82
  20. data/spec/higher_level_api/integration/basic_publish_spec.rb +0 -74
  21. data/spec/higher_level_api/integration/basic_qos_spec.rb +0 -57
  22. data/spec/higher_level_api/integration/basic_reject_spec.rb +0 -152
  23. data/spec/higher_level_api/integration/basic_return_spec.rb +0 -33
  24. data/spec/higher_level_api/integration/channel_close_spec.rb +0 -66
  25. data/spec/higher_level_api/integration/channel_open_spec.rb +0 -57
  26. data/spec/higher_level_api/integration/connection_recovery_spec.rb +0 -483
  27. data/spec/higher_level_api/integration/connection_spec.rb +0 -589
  28. data/spec/higher_level_api/integration/connection_stop_spec.rb +0 -83
  29. data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +0 -128
  30. data/spec/higher_level_api/integration/dead_lettering_spec.rb +0 -75
  31. data/spec/higher_level_api/integration/exchange_bind_spec.rb +0 -31
  32. data/spec/higher_level_api/integration/exchange_declare_spec.rb +0 -237
  33. data/spec/higher_level_api/integration/exchange_delete_spec.rb +0 -105
  34. data/spec/higher_level_api/integration/exchange_unbind_spec.rb +0 -40
  35. data/spec/higher_level_api/integration/exclusive_queue_spec.rb +0 -28
  36. data/spec/higher_level_api/integration/heartbeat_spec.rb +0 -49
  37. data/spec/higher_level_api/integration/message_properties_access_spec.rb +0 -95
  38. data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +0 -24
  39. data/spec/higher_level_api/integration/publisher_confirms_spec.rb +0 -191
  40. data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +0 -87
  41. data/spec/higher_level_api/integration/queue_bind_spec.rb +0 -109
  42. data/spec/higher_level_api/integration/queue_declare_spec.rb +0 -285
  43. data/spec/higher_level_api/integration/queue_delete_spec.rb +0 -41
  44. data/spec/higher_level_api/integration/queue_purge_spec.rb +0 -30
  45. data/spec/higher_level_api/integration/queue_unbind_spec.rb +0 -54
  46. data/spec/higher_level_api/integration/read_only_consumer_spec.rb +0 -60
  47. data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +0 -36
  48. data/spec/higher_level_api/integration/tls_connection_spec.rb +0 -255
  49. data/spec/higher_level_api/integration/toxiproxy_spec.rb +0 -76
  50. data/spec/higher_level_api/integration/tx_commit_spec.rb +0 -21
  51. data/spec/higher_level_api/integration/tx_rollback_spec.rb +0 -21
  52. data/spec/higher_level_api/integration/with_channel_spec.rb +0 -25
  53. data/spec/issues/issue100_spec.rb +0 -42
  54. data/spec/issues/issue141_spec.rb +0 -43
  55. data/spec/issues/issue202_spec.rb +0 -15
  56. data/spec/issues/issue224_spec.rb +0 -40
  57. data/spec/issues/issue465_spec.rb +0 -32
  58. data/spec/issues/issue549_spec.rb +0 -30
  59. data/spec/issues/issue609_spec.rb +0 -84
  60. data/spec/issues/issue78_spec.rb +0 -72
  61. data/spec/issues/issue83_spec.rb +0 -30
  62. data/spec/issues/issue97_attachment.json +0 -1
  63. data/spec/issues/issue97_spec.rb +0 -175
  64. data/spec/lower_level_api/integration/basic_cancel_spec.rb +0 -83
  65. data/spec/lower_level_api/integration/basic_consume_spec.rb +0 -99
  66. data/spec/spec_helper.rb +0 -47
  67. data/spec/stress/channel_close_stress_spec.rb +0 -64
  68. data/spec/stress/channel_open_stress_spec.rb +0 -84
  69. data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +0 -28
  70. data/spec/stress/concurrent_consumers_stress_spec.rb +0 -71
  71. data/spec/stress/concurrent_publishers_stress_spec.rb +0 -54
  72. data/spec/stress/connection_open_close_spec.rb +0 -52
  73. data/spec/stress/merry_go_round_spec.rb +0 -105
  74. data/spec/toxiproxy_helper.rb +0 -28
  75. data/spec/unit/bunny_spec.rb +0 -15
  76. data/spec/unit/concurrent/atomic_fixnum_spec.rb +0 -35
  77. data/spec/unit/concurrent/condition_spec.rb +0 -82
  78. data/spec/unit/concurrent/linked_continuation_queue_spec.rb +0 -35
  79. data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +0 -73
  80. data/spec/unit/exchange_recovery_spec.rb +0 -39
  81. data/spec/unit/version_delivery_tag_spec.rb +0 -28
@@ -1,483 +0,0 @@
1
- require "spec_helper"
2
- require "rabbitmq/http/client"
3
-
4
- require "bunny/concurrent/condition"
5
-
6
- describe "Connection recovery" do
7
- let(:http_client) { RabbitMQ::HTTP::Client.new("http://127.0.0.1:15672") }
8
- let(:logger) { Logger.new($stderr).tap {|logger| logger.level = ENV["BUNNY_LOG_LEVEL"] || Logger::WARN } }
9
- let(:recovery_interval) { 0.2 }
10
-
11
- it "reconnects after grace period" do
12
- with_open do |c|
13
- close_all_connections!
14
- wait_for_recovery_with { connections.any? }
15
- end
16
- end
17
-
18
- it "reconnects after grace period (with multiple hosts)" do
19
- with_open_multi_host do |c|
20
- close_all_connections!
21
- wait_for_recovery_with { connections.any? }
22
- end
23
- end
24
-
25
- it "reconnects after grace period (with multiple hosts, including a broken one)" do
26
- with_open_multi_broken_host do |c|
27
- close_all_connections!
28
- wait_for_recovery_with { connections.any? }
29
- end
30
- end
31
-
32
- it "recovers channels" do
33
- with_open do |c|
34
- ch1 = c.create_channel
35
- ch2 = c.create_channel
36
- sleep 1.5
37
- close_all_connections!
38
- sleep 0.5
39
- poll_until { channels.count == 2 }
40
- expect(ch1).to be_open
41
- expect(ch2).to be_open
42
- end
43
- end
44
-
45
- it "provides a recovery completion callback" do
46
- with_open do |c|
47
- latch = Bunny::Concurrent::Condition.new
48
- c.after_recovery_completed do
49
- latch.notify
50
- end
51
-
52
- ch = c.create_channel
53
- sleep 1.0
54
- close_all_connections!
55
- poll_until { c.open? && ch.open? }
56
- poll_until { latch.none_threads_waiting? }
57
- end
58
- end
59
-
60
- it "recovers channels (with multiple hosts)" do
61
- with_open_multi_host do |c|
62
- ch1 = c.create_channel
63
- ch2 = c.create_channel
64
- sleep 1.5
65
- close_all_connections!
66
- sleep 0.5
67
- poll_until { channels.count == 2 }
68
- expect(ch1).to be_open
69
- expect(ch2).to be_open
70
- end
71
- end
72
-
73
- it "recovers channels (with multiple hosts, including a broken one)" do
74
- with_open_multi_broken_host do |c|
75
- ch1 = c.create_channel
76
- ch2 = c.create_channel
77
- sleep 1.5
78
- close_all_connections!
79
- sleep 0.5
80
- poll_until { channels.count == 2 }
81
- expect(ch1).to be_open
82
- expect(ch2).to be_open
83
- end
84
- end
85
-
86
- it "recovers basic.qos prefetch setting" do
87
- with_open do |c|
88
- ch = c.create_channel
89
- ch.prefetch(11)
90
- expect(ch.prefetch_count).to eq 11
91
- expect(ch.prefetch_global).to be false
92
- sleep 1.5
93
- close_all_connections!
94
- sleep 0.5
95
- wait_for_recovery_with { connections.any? }
96
- expect(ch).to be_open
97
- expect(ch.prefetch_count).to eq 11
98
- expect(ch.prefetch_global).to be false
99
- end
100
- end
101
-
102
- it "recovers basic.qos prefetch global setting" do
103
- with_open do |c|
104
- ch = c.create_channel
105
- ch.prefetch(42, true)
106
- expect(ch.prefetch_count).to eq 42
107
- expect(ch.prefetch_global).to be true
108
- sleep 1.5
109
- close_all_connections!
110
- sleep 0.5
111
- wait_for_recovery_with { connections.any? }
112
- expect(ch).to be_open
113
- expect(ch.prefetch_count).to eq 42
114
- expect(ch.prefetch_global).to be true
115
- end
116
- end
117
-
118
- it "recovers publisher confirms setting" do
119
- with_open do |c|
120
- ch = c.create_channel
121
- ch.confirm_select
122
- expect(ch).to be_using_publisher_confirms
123
- sleep 1.5
124
- close_all_connections!
125
- sleep 0.5
126
- wait_for_recovery_with { connections.any? }
127
- expect(ch).to be_open
128
- expect(ch).to be_using_publisher_confirms
129
- end
130
- end
131
-
132
- it "recovers transactionality setting" do
133
- with_open do |c|
134
- ch = c.create_channel
135
- ch.tx_select
136
- expect(ch).to be_using_tx
137
- sleep 1.5
138
- close_all_connections!
139
- sleep 0.5
140
- wait_for_recovery_with { connections.any? }
141
- expect(ch).to be_open
142
- expect(ch).to be_using_tx
143
- end
144
- end
145
-
146
- it "recovers client-named queues" do
147
- with_open do |c|
148
- ch = c.create_channel
149
- q = ch.queue("bunny.tests.recovery.client-named#{rand}")
150
- close_all_connections!
151
- wait_for_recovery_with { connections.any? }
152
- expect(ch).to be_open
153
- ensure_queue_recovery(ch, q)
154
- q.delete
155
- end
156
- end
157
-
158
- # a very simplistic test for queues inspired by #422
159
- it "recovers client-named queues declared with no_declare: true" do
160
- with_open do |c|
161
- ch = c.create_channel
162
- ch2 = c.create_channel
163
-
164
- n = rand
165
- s = "bunny.tests.recovery.client-named#{n}"
166
-
167
- q = ch.queue(s)
168
- q2 = ch2.queue(s, no_declare: true)
169
-
170
- close_all_connections!
171
- wait_for_recovery_with { connections.any? }
172
- expect(ch).to be_open
173
- ensure_queue_recovery(ch, q)
174
- q.delete
175
- end
176
- end
177
-
178
- # a test for #422
179
- it "recovers client-named queues declared with passive: true" do
180
- with_open do |c|
181
- ch = c.create_channel
182
- ch2 = c.create_channel
183
-
184
- n = rand
185
- s = "bunny.tests.recovery.client-named#{n}"
186
-
187
- q = ch.queue(s)
188
- q2 = ch2.queue(s, passive: true)
189
-
190
- close_all_connections!
191
- wait_for_recovery_with { connections.any? }
192
- expect(ch).to be_open
193
- ensure_queue_recovery(ch, q)
194
- ensure_queue_recovery(ch, q2)
195
- q.delete
196
- end
197
- end
198
-
199
- it "recovers server-named queues" do
200
- with_open do |c|
201
- ch = c.create_channel
202
- q = ch.queue("", exclusive: true)
203
- close_all_connections!
204
- wait_for_recovery_with { connections.any? }
205
- expect(ch).to be_open
206
- ensure_queue_recovery(ch, q)
207
- end
208
- end
209
-
210
- it "recovers queue bindings" do
211
- with_open do |c|
212
- ch = c.create_channel
213
- x = ch.fanout("amq.fanout")
214
- q = ch.queue("", exclusive: true)
215
- q.bind(x)
216
- close_all_connections!
217
- wait_for_recovery_with { connections.any? }
218
- expect(ch).to be_open
219
- ensure_queue_binding_recovery(ch, x, q)
220
- end
221
- end
222
-
223
- it "recovers exchanges and their bindings" do
224
- with_open do |c|
225
- ch = c.create_channel
226
- source = ch.fanout("source.exchange.recovery.example", auto_delete: true)
227
- destination = ch.fanout("destination.exchange.recovery.example", auto_delete: true)
228
-
229
- destination.bind(source)
230
-
231
- # Exchanges won't get auto-deleted on connection loss unless they have
232
- # had an exclusive queue bound to them.
233
- dst_queue = ch.queue("", exclusive: true)
234
- dst_queue.bind(destination, routing_key: "")
235
-
236
- src_queue = ch.queue("", exclusive: true)
237
- src_queue.bind(source, routing_key: "")
238
-
239
- close_all_connections!
240
-
241
- wait_for_recovery_with { connections.any? && exchange_names_in_vhost("/").include?(source.name) }
242
- ch.confirm_select
243
-
244
- source.publish("msg", routing_key: "")
245
- ch.wait_for_confirms
246
- expect(dst_queue.message_count).to eq 1
247
- destination.delete
248
- end
249
- end
250
-
251
- it "recovers passively declared exchanges and their bindings" do
252
- with_open do |c|
253
- ch = c.create_channel
254
- ch.confirm_select
255
-
256
- source = ch.fanout("amq.fanout", passive: true)
257
- destination = ch.fanout("destination.exchange.recovery.example", auto_delete: true)
258
-
259
- destination.bind(source)
260
-
261
- # Exchanges won't get auto-deleted on connection loss unless they have
262
- # had an exclusive queue bound to them.
263
- dst_queue = ch.queue("", exclusive: true)
264
- dst_queue.bind(destination, routing_key: "")
265
-
266
- src_queue = ch.queue("", exclusive: true)
267
- src_queue.bind(source, routing_key: "")
268
-
269
- close_all_connections!
270
-
271
- wait_for_recovery_with { connections.any? }
272
-
273
- source.publish("msg", routing_key: "")
274
- ch.wait_for_confirms
275
-
276
- expect(dst_queue.message_count).to eq 1
277
- destination.delete
278
- end
279
- end
280
-
281
- # this is a simplistic test that primarily execises the code path from #412
282
- it "recovers exchanges that were declared with passive = true" do
283
- with_open do |c|
284
- ch = c.create_channel
285
- ch2 = c.create_channel
286
- source = ch.fanout("source.exchange.recovery.example", auto_delete: true)
287
- destination = ch.fanout("destination.exchange.recovery.example", auto_delete: true)
288
-
289
- source2 = ch2.fanout("source.exchange.recovery.example", no_declare: true)
290
-
291
- destination.bind(source)
292
-
293
- # Exchanges won't get auto-deleted on connection loss unless they have
294
- # had an exclusive queue bound to them.
295
- dst_queue = ch.queue("", exclusive: true)
296
- dst_queue.bind(destination, routing_key: "")
297
-
298
- src_queue = ch.queue("", exclusive: true)
299
- src_queue.bind(source, routing_key: "")
300
-
301
- close_all_connections!
302
-
303
- wait_for_recovery_with { connections.any? && exchange_names_in_vhost("/").include?(source.name) }
304
-
305
- ch2.confirm_select
306
-
307
- source2.publish("msg", routing_key: "")
308
- ch2.wait_for_confirms
309
- expect(dst_queue.message_count).to eq 1
310
- end
311
- end
312
-
313
- it "recovers allocated channel ids" do
314
- with_open do |c|
315
- q = "queue#{Time.now.to_i}"
316
- 10.times { c.create_channel }
317
- expect(c.queue_exists?(q)).to eq false
318
- close_all_connections!
319
- wait_for_recovery_with { channels.any? }
320
- # make sure the connection isn't closed shortly after
321
- # due to "second 'channel.open' seen". MK.
322
- expect(c).to be_open
323
- sleep 0.1
324
- expect(c).to be_open
325
- sleep 0.1
326
- expect(c).to be_open
327
- end
328
- end
329
-
330
- it "recovers consumers" do
331
- with_open do |c|
332
- delivered = false
333
-
334
- ch = c.create_channel
335
- ch.confirm_select
336
- q = ch.queue("", exclusive: true)
337
- q.subscribe do |_, _, _|
338
- delivered = true
339
- end
340
- close_all_connections!
341
- wait_for_recovery_with { connections.any? }
342
- expect(ch).to be_open
343
-
344
- q.publish("")
345
- ch.wait_for_confirms
346
-
347
- poll_until { delivered }
348
- end
349
- end
350
-
351
- it "recovers all consumers" do
352
- n = 32
353
-
354
- with_open do |c|
355
- ch = c.create_channel
356
- q = ch.queue("", exclusive: true)
357
- n.times { q.subscribe { |_, _, _| } }
358
- close_all_connections!
359
- wait_for_recovery_with { connections.any? }
360
- expect(ch).to be_open
361
- sleep 0.5
362
-
363
- expect(q.consumer_count).to eq n
364
- end
365
- end
366
-
367
- it "recovers all queues" do
368
- n = 32
369
-
370
- qs = []
371
-
372
- with_open do |c|
373
- ch = c.create_channel
374
-
375
- n.times do
376
- qs << ch.queue("", exclusive: true)
377
- end
378
- close_all_connections!
379
- wait_for_recovery_with { queue_names.include?(qs.first.name) }
380
- sleep 0.5
381
- expect(ch).to be_open
382
-
383
- qs.each do |q|
384
- ch.queue_declare(q.name, passive: true)
385
- end
386
- end
387
- end
388
-
389
- def exchange_names_in_vhost(vhost)
390
- http_client.list_exchanges(vhost).map {|e| e["name"]}
391
- end
392
-
393
- def connections
394
- http_client.list_connections
395
- end
396
-
397
- def channels
398
- http_client.list_channels
399
- end
400
-
401
- def queue_names
402
- http_client.list_queues.map {|q| q["name"]}
403
- end
404
-
405
- def close_all_connections!
406
- # let whatever actions were taken before
407
- # this call a chance to propagate, e.g. to make
408
- # sure that connections are accounted for in the
409
- # stats DB.
410
- #
411
- # See bin/ci/before_build for management plugin
412
- # pre-configuration.
413
- #
414
- # MK.
415
- sleep 1.1
416
- connections.each do |conn_info|
417
- close_ignoring_permitted_exceptions(conn_info.name)
418
- end
419
- end
420
-
421
- def close_ignoring_permitted_exceptions(connection_name)
422
- http_client.close_connection(connection_name)
423
- rescue Bunny::ConnectionForced, Faraday::ResourceNotFound
424
- # ignored
425
- end
426
-
427
- def wait_for_recovery_with(&probe)
428
- poll_until &probe
429
- end
430
-
431
- def poll_while(&probe)
432
- Bunny::TestKit.poll_while(&probe)
433
- end
434
-
435
- def poll_until(&probe)
436
- Bunny::TestKit.poll_until(&probe)
437
- end
438
-
439
- def with_open(c = Bunny.new(network_recovery_interval: recovery_interval,
440
- recover_from_connection_close: true,
441
- logger: logger), &block)
442
- c.start
443
- block.call(c)
444
- ensure
445
- c.close(false) rescue nil
446
- end
447
-
448
- def with_open_multi_host(&block)
449
- c = Bunny.new(hosts: ["127.0.0.1", "localhost"],
450
- network_recovery_interval: recovery_interval,
451
- recover_from_connection_close: true,
452
- logger: logger)
453
- with_open(c, &block)
454
- end
455
-
456
- def with_open_multi_broken_host(&block)
457
- c = Bunny.new(hosts: ["broken", "127.0.0.1", "localhost"],
458
- hosts_shuffle_strategy: Proc.new { |hosts| hosts }, # We do not shuffle for these tests so we always hit the broken host
459
- network_recovery_interval: recovery_interval,
460
- recover_from_connection_close: true,
461
- logger: logger)
462
- with_open(c, &block)
463
- end
464
-
465
- def ensure_queue_recovery(ch, q)
466
- ch.confirm_select
467
- q.purge
468
- x = ch.default_exchange
469
- x.publish("msg", routing_key: q.name)
470
- ch.wait_for_confirms
471
- expect(q.message_count).to eq 1
472
- q.purge
473
- end
474
-
475
- def ensure_queue_binding_recovery(ch, x, q, routing_key = "")
476
- ch.confirm_select
477
- q.purge
478
- x.publish("msg", routing_key: routing_key)
479
- ch.wait_for_confirms
480
- expect(q.message_count).to eq 1
481
- q.purge
482
- end
483
- end