bunny 0.9.0.pre10 → 0.9.0.pre11

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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +4 -7
  4. data/ChangeLog.md +79 -0
  5. data/Gemfile +3 -1
  6. data/README.md +1 -1
  7. data/benchmarks/basic_publish/with_128K_messages.rb +35 -0
  8. data/benchmarks/basic_publish/with_1k_messages.rb +35 -0
  9. data/benchmarks/basic_publish/with_4K_messages.rb +35 -0
  10. data/benchmarks/basic_publish/with_64K_messages.rb +35 -0
  11. data/benchmarks/channel_open.rb +28 -0
  12. data/benchmarks/queue_declare.rb +29 -0
  13. data/benchmarks/queue_declare_and_bind.rb +29 -0
  14. data/benchmarks/queue_declare_bind_and_delete.rb +29 -0
  15. data/benchmarks/write_vs_write_nonblock.rb +49 -0
  16. data/bunny.gemspec +3 -3
  17. data/lib/bunny.rb +2 -0
  18. data/lib/bunny/channel.rb +31 -35
  19. data/lib/bunny/concurrent/continuation_queue.rb +10 -0
  20. data/lib/bunny/concurrent/linked_continuation_queue.rb +4 -2
  21. data/lib/bunny/exceptions.rb +5 -2
  22. data/lib/bunny/heartbeat_sender.rb +6 -4
  23. data/lib/bunny/queue.rb +3 -0
  24. data/lib/bunny/{main_loop.rb → reader_loop.rb} +5 -8
  25. data/lib/bunny/session.rb +93 -48
  26. data/lib/bunny/socket.rb +37 -3
  27. data/lib/bunny/test_kit.rb +26 -0
  28. data/lib/bunny/transport.rb +39 -33
  29. data/lib/bunny/version.rb +1 -1
  30. data/profiling/basic_publish/with_4K_messages.rb +33 -0
  31. data/spec/higher_level_api/integration/consistent_hash_exchange_spec.rb +10 -11
  32. data/spec/higher_level_api/integration/queue_declare_spec.rb +55 -13
  33. data/spec/issues/issue100_spec.rb +29 -27
  34. data/spec/issues/issue78_spec.rb +54 -52
  35. data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +0 -22
  36. data/spec/stress/concurrent_consumers_stress_spec.rb +2 -1
  37. data/spec/stress/concurrent_publishers_stress_spec.rb +7 -10
  38. data/spec/stress/long_running_consumer_spec.rb +83 -0
  39. data/spec/unit/concurrent/condition_spec.rb +7 -5
  40. data/spec/unit/concurrent/linked_continuation_queue_spec.rb +35 -0
  41. metadata +48 -44
@@ -1,73 +1,75 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Bunny::Queue, "#subscribe" do
4
- let(:connection1) do
5
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
6
- c.start
7
- c
8
- end
9
- let(:connection2) do
10
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
11
- c.start
12
- c
13
- end
3
+ unless ENV["CI"]
4
+ describe Bunny::Queue, "#subscribe" do
5
+ let(:connection1) do
6
+ c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
7
+ c.start
8
+ c
9
+ end
10
+ let(:connection2) do
11
+ c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed")
12
+ c.start
13
+ c
14
+ end
14
15
 
15
- after :all do
16
- connection1.close if connection1.open?
17
- connection2.close if connection2.open?
18
- end
16
+ after :all do
17
+ connection1.close if connection1.open?
18
+ connection2.close if connection2.open?
19
+ end
19
20
 
20
21
 
21
- context "with an empty queue" do
22
- it "consumes messages" do
23
- delivered_data = []
22
+ context "with an empty queue" do
23
+ it "consumes messages" do
24
+ delivered_data = []
24
25
 
25
- ch1 = connection1.create_channel
26
- ch2 = connection1.create_channel
26
+ ch1 = connection1.create_channel
27
+ ch2 = connection1.create_channel
27
28
 
28
- q = ch1.queue("", :exclusive => true)
29
- q.subscribe(:ack => false, :block => false) do |delivery_info, properties, payload|
30
- delivered_data << payload
31
- end
32
- sleep 0.5
29
+ q = ch1.queue("", :exclusive => true)
30
+ q.subscribe(:ack => false, :block => false) do |delivery_info, properties, payload|
31
+ delivered_data << payload
32
+ end
33
+ sleep 0.5
33
34
 
34
- x = ch2.default_exchange
35
- x.publish("abc", :routing_key => q.name)
36
- sleep 0.7
35
+ x = ch2.default_exchange
36
+ x.publish("abc", :routing_key => q.name)
37
+ sleep 0.7
37
38
 
38
- delivered_data.should == ["abc"]
39
+ delivered_data.should == ["abc"]
39
40
 
40
- ch1.close
41
- ch2.close
41
+ ch1.close
42
+ ch2.close
43
+ end
42
44
  end
43
- end
44
45
 
45
- context "with a non-empty queue" do
46
- let(:queue_name) { "queue#{rand}" }
46
+ context "with a non-empty queue" do
47
+ let(:queue_name) { "queue#{rand}" }
47
48
 
48
- it "consumes messages" do
49
- delivered_data = []
49
+ it "consumes messages" do
50
+ delivered_data = []
50
51
 
51
- ch1 = connection1.create_channel
52
- ch2 = connection1.create_channel
52
+ ch1 = connection1.create_channel
53
+ ch2 = connection1.create_channel
53
54
 
54
- q = ch1.queue(queue_name, :exclusive => true)
55
- x = ch2.default_exchange
56
- 3.times do |i|
57
- x.publish("data#{i}", :routing_key => queue_name)
58
- end
59
- sleep 0.7
60
- q.message_count.should == 3
55
+ q = ch1.queue(queue_name, :exclusive => true)
56
+ x = ch2.default_exchange
57
+ 3.times do |i|
58
+ x.publish("data#{i}", :routing_key => queue_name)
59
+ end
60
+ sleep 0.7
61
+ q.message_count.should == 3
61
62
 
62
- q.subscribe(:ack => false, :block => false) do |delivery_info, properties, payload|
63
- delivered_data << payload
64
- end
65
- sleep 0.7
63
+ q.subscribe(:ack => false, :block => false) do |delivery_info, properties, payload|
64
+ delivered_data << payload
65
+ end
66
+ sleep 0.7
66
67
 
67
- delivered_data.should == ["data0", "data1", "data2"]
68
+ delivered_data.should == ["data0", "data1", "data2"]
68
69
 
69
- ch1.close
70
- ch2.close
70
+ ch1.close
71
+ ch2.close
72
+ end
71
73
  end
72
74
  end
73
75
  end
@@ -24,27 +24,5 @@ unless ENV["CI"]
24
24
  end
25
25
  end
26
26
  end
27
-
28
- context "in a multi-threaded scenario" do
29
- # actually, on MRI values greater than ~100 will eventually cause write
30
- # operations to fail with a timeout (1 second is not enough)
31
- # which will cause recovery to re-acquire @channel_mutex in Session.
32
- # Because Ruby's mutexes are not re-entrant, it will raise a ThreadError.
33
- #
34
- # But this already demonstrates that within these platform constraints,
35
- # Bunny is safe to use in such scenarios.
36
- let(:n) { 20 }
37
-
38
- it "works correctly" do
39
- n.times do
40
- t = Thread.new do
41
- ch = connection.create_channel
42
-
43
- ch.close
44
- end
45
- t.abort_on_exception = true
46
- end
47
- end
48
- end
49
27
  end
50
28
  end
@@ -4,7 +4,8 @@ require "spec_helper"
4
4
  unless ENV["CI"]
5
5
  describe "Concurrent consumers sharing a connection" do
6
6
  let(:connection) do
7
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :automatic_recovery => false)
7
+ c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed",
8
+ :automatic_recovery => false, :continuation_timeout => 6000)
8
9
  c.start
9
10
  c
10
11
  end
@@ -4,7 +4,7 @@ require "spec_helper"
4
4
  unless ENV["CI"]
5
5
  describe "Concurrent publishers sharing a connection" do
6
6
  let(:connection) do
7
- c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :automatically_recover => false)
7
+ c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :automatically_recover => false, :continuation_timeout => 20.0)
8
8
  c.start
9
9
  c
10
10
  end
@@ -13,8 +13,8 @@ unless ENV["CI"]
13
13
  connection.close
14
14
  end
15
15
 
16
- let(:n) { 32 }
17
- let(:m) { 1000 }
16
+ let(:concurrency) { 24 }
17
+ let(:rate) { 5_000 }
18
18
 
19
19
  it "successfully finish publishing" do
20
20
  ch = connection.create_channel
@@ -26,22 +26,22 @@ unless ENV["CI"]
26
26
  sleep 0.25
27
27
 
28
28
  chs = {}
29
- n.times do |i|
29
+ concurrency.times do |i|
30
30
  chs[i] = connection.create_channel
31
31
  end
32
32
 
33
33
  ts = []
34
34
 
35
- n.times do |i|
35
+ concurrency.times do |i|
36
36
  t = Thread.new do
37
37
  cht = chs[i]
38
38
  x = ch.default_exchange
39
39
 
40
40
  5.times do |i|
41
- m.times do
41
+ rate.times do
42
42
  x.publish(body, :routing_key => q.name)
43
43
  end
44
- puts "Published #{(i + 1) * m} messages..."
44
+ puts "Published #{(i + 1) * rate} messages..."
45
45
  end
46
46
  end
47
47
  t.abort_on_exception = true
@@ -52,9 +52,6 @@ unless ENV["CI"]
52
52
  ts.each do |t|
53
53
  t.join
54
54
  end
55
-
56
- sleep 4.0
57
- q.message_count.should == 5 * n * m
58
55
  end
59
56
  end
60
57
  end
@@ -0,0 +1,83 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "spec_helper"
3
+
4
+ unless ENV["CI"]
5
+ require "bunny/concurrent/condition"
6
+ require "bunny/test_kit"
7
+
8
+ describe "Long running [relatively to heartbeat interval] consumer that never publishes" do
9
+ let(:connection) do
10
+ c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :automatic_recovery => false, :heartbeat_interval => 6)
11
+ c.start
12
+ c
13
+ end
14
+
15
+ after :all do
16
+ connection.close
17
+ end
18
+
19
+ let(:target) { 512 * 1024 * 1024 }
20
+ let(:queue) { "bunny.stress.long_running_consumer.#{Time.now.to_i}" }
21
+
22
+ let(:rate) { 50 }
23
+ let(:s) { 4.0 }
24
+
25
+
26
+
27
+ it "does not skip heartbeats" do
28
+ finished = Bunny::Concurrent::Condition.new
29
+
30
+ ct = Thread.new do
31
+ t = 0
32
+ ch = connection.create_channel(nil, 6)
33
+ begin
34
+ q = ch.queue(queue, :exclusive => true)
35
+
36
+ q.bind("amq.fanout").subscribe do |_, _, payload|
37
+ t += payload.bytesize
38
+
39
+ if t >= target
40
+ puts "Hit the target, done with the test..."
41
+
42
+ finished.notify_all
43
+ else
44
+ puts "Consumed #{(t.to_f / target.to_f).round(3) * 100}% of data"
45
+ end
46
+ end
47
+ rescue Interrupt => e
48
+ ch.maybe_kill_consumer_work_pool!
49
+ ch.close
50
+ end
51
+ end
52
+ ct.abort_on_exception = true
53
+
54
+ pt = Thread.new do
55
+ t = 0
56
+ ch = connection.create_channel
57
+ begin
58
+ x = ch.fanout("amq.fanout")
59
+
60
+ loop do
61
+ break if t >= target
62
+
63
+ rate.times do |i|
64
+ msg = Bunny::TestKit.message_in_kb(96, 8192, i)
65
+ x.publish(msg)
66
+ t += msg.bytesize
67
+ end
68
+
69
+ sleep (s * rand)
70
+ end
71
+ rescue Interrupt => e
72
+ ch.close
73
+ end
74
+ end
75
+ pt.abort_on_exception = true
76
+
77
+ finished.wait
78
+
79
+ ct.raise Interrupt.new
80
+ pt.raise Interrupt.new
81
+ end
82
+ end
83
+ end
@@ -22,18 +22,19 @@ describe Bunny::Concurrent::Condition do
22
22
 
23
23
  describe "#notify" do
24
24
  it "notifies a single thread waiting on the latch" do
25
+ mutex = Mutex.new
25
26
  condition = described_class.new
26
27
  xs = []
27
28
 
28
29
  t1 = Thread.new do
29
30
  condition.wait
30
- xs << :notified1
31
+ mutex.synchronize { xs << :notified1 }
31
32
  end
32
33
  t1.abort_on_exception = true
33
34
 
34
35
  t2 = Thread.new do
35
36
  condition.wait
36
- xs << :notified2
37
+ mutex.synchronize { xs << :notified2 }
37
38
  end
38
39
  t2.abort_on_exception = true
39
40
 
@@ -45,16 +46,17 @@ describe Bunny::Concurrent::Condition do
45
46
  end
46
47
 
47
48
  describe "#notify_all" do
48
- let(:n) { 20 }
49
+ let(:n) { 120 }
49
50
 
50
51
  it "notifies all the threads waiting on the latch" do
52
+ mutex = Mutex.new
51
53
  condition = described_class.new
52
- @xs = []
54
+ @xs = []
53
55
 
54
56
  n.times do |i|
55
57
  t = Thread.new do
56
58
  condition.wait
57
- @xs << "notified#{i + 1}".to_sym
59
+ mutex.synchronize { @xs << "notified#{i + 1}".to_sym }
58
60
  end
59
61
  t.abort_on_exception = true
60
62
  end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+
3
+ if defined?(JRUBY_VERSION)
4
+ require "bunny/concurrent/linked_continuation_queue"
5
+
6
+ describe Bunny::Concurrent::LinkedContinuationQueue do
7
+ describe "#poll with a timeout that is never reached" do
8
+ it "blocks until the value is available, then returns it" do
9
+ # force subject evaluation
10
+ cq = subject
11
+ t = Thread.new do
12
+ cq.push(10)
13
+ end
14
+ t.abort_on_exception = true
15
+
16
+ v = subject.poll(500)
17
+ v.should == 10
18
+ end
19
+ end
20
+
21
+ describe "#poll with a timeout that is reached" do
22
+ it "raises an exception" do
23
+ # force subject evaluation
24
+ cq = subject
25
+ t = Thread.new do
26
+ sleep 1.5
27
+ cq.push(10)
28
+ end
29
+ t.abort_on_exception = true
30
+
31
+ lambda { subject.poll(500) }.should raise_error(::Timeout::Error)
32
+ end
33
+ end
34
+ end
35
+ end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bunny
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0.pre10
5
- prerelease: 6
4
+ version: 0.9.0.pre11
6
5
  platform: ruby
7
6
  authors:
8
7
  - Chris Duncan
@@ -10,53 +9,55 @@ authors:
10
9
  - Jakub Stastny aka botanicus
11
10
  - Michael S. Klishin
12
11
  - Stefan Kaes
13
- autorequire:
12
+ autorequire:
14
13
  bindir: bin
15
14
  cert_chain: []
16
- date: 2013-05-02 00:00:00.000000000 Z
15
+ date: 2013-05-14 00:00:00.000000000 Z
17
16
  dependencies:
18
17
  - !ruby/object:Gem::Dependency
19
18
  name: amq-protocol
20
- version_requirements: !ruby/object:Gem::Requirement
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: 1.4.0
25
- none: false
26
19
  requirement: !ruby/object:Gem::Requirement
27
20
  requirements:
28
- - - ">="
21
+ - - '>='
29
22
  - !ruby/object:Gem::Version
30
- version: 1.4.0
31
- none: false
32
- prerelease: false
23
+ version: 1.6.0
33
24
  type: :runtime
34
- description: Easy to use synchronous Ruby client for RabbitMQ
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - '>='
29
+ - !ruby/object:Gem::Version
30
+ version: 1.6.0
31
+ description: Popular easy to use Ruby client for RabbitMQ
35
32
  email:
36
- - !binary |-
37
- Y2VsbGRlZUBnbWFpbC5jb20=
38
- - !binary |-
39
- ZXJpY0A1c3RvcHMuY29t
40
- - !binary |-
41
- c3Rhc3RueUAxMDFpZGVhcy5jeg==
42
- - !binary |-
43
- bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=
44
- - !binary |-
45
- c2thZXNAcmFpbHNleHByZXNzLmRl
33
+ - celldee@gmail.com
34
+ - eric@5stops.com
35
+ - stastny@101ideas.cz
36
+ - michael@novemberain.com
37
+ - skaes@railsexpress.de
46
38
  executables: []
47
39
  extensions: []
48
40
  extra_rdoc_files:
49
41
  - README.md
50
42
  files:
51
- - ".gitignore"
52
- - ".rspec"
53
- - ".ruby-version"
54
- - ".travis.yml"
55
- - ".yardopts"
43
+ - .gitignore
44
+ - .rspec
45
+ - .ruby-version
46
+ - .travis.yml
47
+ - .yardopts
56
48
  - ChangeLog.md
57
49
  - Gemfile
58
50
  - LICENSE
59
51
  - README.md
52
+ - benchmarks/basic_publish/with_128K_messages.rb
53
+ - benchmarks/basic_publish/with_1k_messages.rb
54
+ - benchmarks/basic_publish/with_4K_messages.rb
55
+ - benchmarks/basic_publish/with_64K_messages.rb
56
+ - benchmarks/channel_open.rb
57
+ - benchmarks/queue_declare.rb
58
+ - benchmarks/queue_declare_and_bind.rb
59
+ - benchmarks/queue_declare_bind_and_delete.rb
60
+ - benchmarks/write_vs_write_nonblock.rb
60
61
  - bin/ci/before_build.sh
61
62
  - bunny.gemspec
62
63
  - examples/connection/authentication_failure.rb
@@ -104,16 +105,18 @@ files:
104
105
  - lib/bunny/exchange.rb
105
106
  - lib/bunny/framing.rb
106
107
  - lib/bunny/heartbeat_sender.rb
107
- - lib/bunny/main_loop.rb
108
108
  - lib/bunny/message_properties.rb
109
109
  - lib/bunny/queue.rb
110
+ - lib/bunny/reader_loop.rb
110
111
  - lib/bunny/return_info.rb
111
112
  - lib/bunny/session.rb
112
113
  - lib/bunny/socket.rb
113
114
  - lib/bunny/ssl_socket.rb
114
115
  - lib/bunny/system_timer.rb
116
+ - lib/bunny/test_kit.rb
115
117
  - lib/bunny/transport.rb
116
118
  - lib/bunny/version.rb
119
+ - profiling/basic_publish/with_4K_messages.rb
117
120
  - spec/compatibility/queue_declare_spec.rb
118
121
  - spec/higher_level_api/integration/basic_ack_spec.rb
119
122
  - spec/higher_level_api/integration/basic_cancel_spec.rb
@@ -162,36 +165,35 @@ files:
162
165
  - spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb
163
166
  - spec/stress/concurrent_consumers_stress_spec.rb
164
167
  - spec/stress/concurrent_publishers_stress_spec.rb
168
+ - spec/stress/long_running_consumer_spec.rb
165
169
  - spec/unit/bunny_spec.rb
166
170
  - spec/unit/concurrent/condition_spec.rb
171
+ - spec/unit/concurrent/linked_continuation_queue_spec.rb
167
172
  - spec/unit/transport_spec.rb
168
173
  homepage: http://github.com/ruby-amqp/bunny
169
174
  licenses:
170
175
  - MIT
171
- post_install_message:
176
+ metadata: {}
177
+ post_install_message:
172
178
  rdoc_options: []
173
179
  require_paths:
174
180
  - lib
175
181
  required_ruby_version: !ruby/object:Gem::Requirement
176
182
  requirements:
177
- - - ">="
183
+ - - '>='
178
184
  - !ruby/object:Gem::Version
179
- version: !binary |-
180
- MA==
181
- none: false
185
+ version: '0'
182
186
  required_rubygems_version: !ruby/object:Gem::Requirement
183
187
  requirements:
184
- - - !binary |-
185
- Pg==
188
+ - - '>'
186
189
  - !ruby/object:Gem::Version
187
190
  version: 1.3.1
188
- none: false
189
191
  requirements: []
190
- rubyforge_project:
191
- rubygems_version: 1.8.24
192
- signing_key:
193
- specification_version: 3
194
- summary: Easy to use synchronous Ruby client for RabbitMQ
192
+ rubyforge_project:
193
+ rubygems_version: 2.0.3
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: Popular easy to use Ruby client for RabbitMQ
195
197
  test_files:
196
198
  - spec/compatibility/queue_declare_spec.rb
197
199
  - spec/higher_level_api/integration/basic_ack_spec.rb
@@ -241,7 +243,9 @@ test_files:
241
243
  - spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb
242
244
  - spec/stress/concurrent_consumers_stress_spec.rb
243
245
  - spec/stress/concurrent_publishers_stress_spec.rb
246
+ - spec/stress/long_running_consumer_spec.rb
244
247
  - spec/unit/bunny_spec.rb
245
248
  - spec/unit/concurrent/condition_spec.rb
249
+ - spec/unit/concurrent/linked_continuation_queue_spec.rb
246
250
  - spec/unit/transport_spec.rb
247
251
  has_rdoc: true