bunny 2.19.0 → 2.20.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.
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