hot_bunnies 2.0.0.pre10-java → 2.0.0.pre11-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -118,17 +118,18 @@ module HotBunnies
118
118
  attr_reader :consumers
119
119
 
120
120
  # @private
121
- def initialize(session, delegate)
121
+ def initialize(session, delegate, thread_pool)
122
122
  @connection = session
123
123
  @delegate = delegate
124
+ @thread_pool = thread_pool
124
125
 
125
- @exchanges = ConcurrentHashMap.new
126
- @queues = ConcurrentHashMap.new
126
+ @exchanges = JavaConcurrent::ConcurrentHashMap.new
127
+ @queues = JavaConcurrent::ConcurrentHashMap.new
127
128
  # we keep track of consumers in part to gracefully shut down their
128
129
  # executors when the channel is closed. This frees library users
129
130
  # from having to worry about this. MK.
130
- @consumers = ConcurrentHashMap.new
131
- @shutdown_hooks = ConcurrentSkipListSet.new
131
+ @consumers = JavaConcurrent::ConcurrentHashMap.new
132
+ @shutdown_hooks = JavaConcurrent::ConcurrentSkipListSet.new
132
133
  @recoveries_counter = JavaConcurrent::AtomicInteger.new(0)
133
134
 
134
135
  on_shutdown do |ch, cause|
@@ -136,35 +137,19 @@ module HotBunnies
136
137
  end
137
138
  end
138
139
 
139
- # @return [HotBunnies::Session] Connection this channel is on
140
- def client
141
- @connection
142
- end
143
-
144
140
  # @return [HotBunnies::Session] Connection this channel is on
145
141
  def session
146
142
  @connection
147
143
  end
148
-
149
- # @return [HotBunnies::Session] Connection this channel is on
150
- def connection
151
- @connection
152
- end
153
-
154
- # @return [Integer] Channel id
155
- def id
156
- @delegate.channel_number
157
- end
158
-
159
- # @return [Integer] Channel id
160
- def number
161
- @delegate.channel_number
162
- end
144
+ alias client session
145
+ alias connection session
163
146
 
164
147
  # @return [Integer] Channel id
165
148
  def channel_number
166
149
  @delegate.channel_number
167
150
  end
151
+ alias id channel_number
152
+ alias number channel_number
168
153
 
169
154
  # Closes the channel.
170
155
  #
@@ -418,7 +403,7 @@ module HotBunnies
418
403
  # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions guide
419
404
  # @api public
420
405
  def queue(name, options={})
421
- dq = Queue.new(self, name, options).tap do |q|
406
+ dq = Queue.new(self, name, @thread_pool, options).tap do |q|
422
407
  q.declare!
423
408
  end
424
409
 
@@ -1,5 +1,4 @@
1
1
  require "hot_bunnies/thread_pools"
2
2
 
3
3
  require "hot_bunnies/consumers/base"
4
- require "hot_bunnies/consumers/non_blocking"
5
4
  require "hot_bunnies/consumers/blocking"
@@ -5,10 +5,11 @@ module HotBunnies
5
5
  attr_accessor :consumer_tag
6
6
  attr_accessor :auto_ack
7
7
 
8
- def initialize(channel, queue)
8
+ def initialize(channel, queue, opts)
9
9
  super(channel)
10
10
  @channel = channel
11
11
  @queue = queue
12
+ @opts = opts
12
13
  @auto_ack = true
13
14
 
14
15
  @cancelling = JavaConcurrent::AtomicBoolean.new
@@ -54,6 +55,11 @@ module HotBunnies
54
55
  end
55
56
 
56
57
  def start
58
+ # no-op
59
+ end
60
+
61
+ def gracefully_shut_down
62
+ # no-op
57
63
  end
58
64
 
59
65
  def deliver(headers, message)
@@ -74,12 +80,33 @@ module HotBunnies
74
80
 
75
81
  # @private
76
82
  def recover_from_network_failure
77
- @consumer_tag = @channel.basic_consume(@queue.name, @auto_ack, self)
78
-
79
83
  @terminated.set(false)
80
84
  @cancelled.set(false)
85
+ @consumer_tag = @channel.basic_consume(@queue.name, @auto_ack, self)
81
86
 
82
87
  @consumer_tag
83
88
  end
84
89
  end
90
+
91
+ class CallbackConsumer < BaseConsumer
92
+ def initialize(channel, queue, opts, callback)
93
+ raise ArgumentError, "callback must not be nil!" if callback.nil?
94
+
95
+ super(channel, queue, opts)
96
+ @callback = callback
97
+ @callback_arity = @callback.arity
98
+ end
99
+
100
+ def deliver(headers, message)
101
+ if @callback_arity == 2
102
+ @callback.call(headers, message)
103
+ else
104
+ @callback.call(message)
105
+ end
106
+ end
107
+
108
+ def cancel
109
+ @channel.basic_cancel(consumer_tag)
110
+ end
111
+ end
85
112
  end
@@ -2,19 +2,15 @@ require "hot_bunnies/consumers/base"
2
2
 
3
3
  module HotBunnies
4
4
  class BlockingCallbackConsumer < CallbackConsumer
5
- include JavaConcurrent
6
-
7
5
  POISON = :__poison__
8
6
 
9
7
  def initialize(channel, queue, buffer_size, opts, callback)
10
- super(channel, queue, callback)
8
+ super(channel, queue, opts, callback)
11
9
  if buffer_size
12
- @internal_queue = ArrayBlockingQueue.new(buffer_size)
10
+ @internal_queue = JavaConcurrent::ArrayBlockingQueue.new(buffer_size)
13
11
  else
14
- @internal_queue = LinkedBlockingQueue.new
12
+ @internal_queue = JavaConcurrent::LinkedBlockingQueue.new
15
13
  end
16
-
17
- @opts = opts
18
14
  end
19
15
 
20
16
  def cancel
@@ -37,10 +33,10 @@ module HotBunnies
37
33
  if pair == POISON
38
34
  @cancelling.set(true)
39
35
  else
40
- callback(*pair)
36
+ @callback.call(*pair)
41
37
  end
42
38
  end
43
- rescue InterruptedException => e
39
+ rescue JavaConcurrent::InterruptedException => e
44
40
  interrupted = true
45
41
  end
46
42
  end
@@ -49,7 +45,7 @@ module HotBunnies
49
45
  if pair == POISON
50
46
  @cancelling.set(true)
51
47
  else
52
- callback(*pair)
48
+ @callback.call(*pair)
53
49
  end
54
50
  end
55
51
  end
@@ -65,7 +61,7 @@ module HotBunnies
65
61
  else
66
62
  begin
67
63
  @internal_queue.put(pair)
68
- rescue InterruptedException => e
64
+ rescue JavaConcurrent::InterruptedException => e
69
65
  JavaConcurrent::Thread.current_thread.interrupt
70
66
  end
71
67
  end
@@ -1,11 +1,9 @@
1
- module JavaConcurrent
2
- java_import 'java.lang.Thread'
3
- java_import 'java.lang.Runnable'
4
- java_import 'java.lang.InterruptedException'
5
- java_import 'java.util.concurrent.Executors'
6
- java_import 'java.util.concurrent.LinkedBlockingQueue'
7
- java_import 'java.util.concurrent.ArrayBlockingQueue'
8
- java_import 'java.util.concurrent.TimeUnit'
9
- java_import 'java.util.concurrent.atomic.AtomicBoolean'
10
- java_import 'java.util.concurrent.atomic.AtomicInteger'
11
- end
1
+ module HotBunnies
2
+ module JavaConcurrent
3
+ java_import 'java.lang.Thread'
4
+ java_import 'java.lang.Runnable'
5
+ java_import 'java.lang.InterruptedException'
6
+ include_package 'java.util.concurrent'
7
+ include_package 'java.util.concurrent.atomic'
8
+ end
9
+ end
@@ -29,9 +29,10 @@ module HotBunnies
29
29
  # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
30
30
  # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions guide
31
31
  # @api public
32
- def initialize(channel, name, options={})
32
+ def initialize(channel, name, thread_pool, options={})
33
33
  @channel = channel
34
34
  @name = name
35
+ @thread_pool = thread_pool
35
36
  @options = {:durable => false, :exclusive => false, :auto_delete => false, :passive => false, :arguments => Hash.new}.merge(options)
36
37
 
37
38
  @durable = @options[:durable]
@@ -158,29 +159,16 @@ module HotBunnies
158
159
  end
159
160
  alias pop get
160
161
 
161
- def build_consumer(opts, &block)
162
+ def build_consumer(opts = {}, &block)
162
163
  if opts[:block] || opts[:blocking]
163
164
  BlockingCallbackConsumer.new(@channel, self, opts[:buffer_size], opts, block)
164
165
  else
165
- esf = opts.fetch(:executor_factory, Proc.new {
166
- JavaConcurrent::Executors.new_single_thread_executor
167
- })
168
- es = opts.fetch(:executor, esf.call)
169
- AsyncCallbackConsumer.new(@channel, self, opts.merge(:executor => es, :executor_factory => esf), block)
166
+ CallbackConsumer.new(@channel, self, opts, block)
170
167
  end
171
168
  end
172
169
 
173
170
  def subscribe(opts = {}, &block)
174
- consumer = build_consumer(opts, &block)
175
-
176
- @consumer_tag = @channel.basic_consume(@name, !(opts[:ack] || opts[:manual_ack]), consumer)
177
- consumer.consumer_tag = @consumer_tag
178
-
179
- @default_consumer = consumer
180
- @channel.register_consumer(@consumer_tag, consumer)
181
- consumer.start
182
-
183
- consumer
171
+ subscribe_with(build_consumer(opts, &block))
184
172
  end
185
173
 
186
174
  def subscribe_with(consumer, opts = {})
@@ -189,8 +177,8 @@ module HotBunnies
189
177
 
190
178
  @default_consumer = consumer
191
179
  @channel.register_consumer(@consumer_tag, consumer)
192
- consumer.start
193
180
 
181
+ consumer.start
194
182
  consumer
195
183
  end
196
184
 
@@ -5,8 +5,6 @@ require "set"
5
5
  module HotBunnies
6
6
  java_import com.rabbitmq.client.ConnectionFactory
7
7
  java_import com.rabbitmq.client.Connection
8
- java_import java.util.concurrent.ConcurrentHashMap
9
- java_import java.util.concurrent.ConcurrentSkipListSet
10
8
 
11
9
  # Connection to a RabbitMQ node.
12
10
  #
@@ -73,20 +71,19 @@ module HotBunnies
73
71
  new(cf, options)
74
72
  end
75
73
 
76
- # @private
77
- attr_reader :thread
78
74
  # @return [Array<HotBunnies::Channel>] Channels opened on this connection
79
75
  attr_reader :channels
80
76
 
81
77
 
82
78
  # @private
83
79
  def initialize(connection_factory, opts = {})
84
- @cf = connection_factory
85
- @connection = converting_rjc_exceptions_to_ruby do
80
+ @cf = connection_factory
81
+ @executor_factory = opts[:executor_factory]
82
+ @connection = converting_rjc_exceptions_to_ruby do
86
83
  self.new_connection
87
84
  end
88
- @channels = ConcurrentHashMap.new
89
- @thread = Thread.current
85
+ @channels = JavaConcurrent::ConcurrentHashMap.new
86
+ @thread_pool = ThreadPools.dynamically_growing
90
87
 
91
88
  # should automatic recovery from network failures be used?
92
89
  @automatically_recover = if opts[:automatically_recover].nil? && opts[:automatic_recovery].nil?
@@ -95,7 +92,7 @@ module HotBunnies
95
92
  opts[:automatically_recover] || opts[:automatic_recovery]
96
93
  end
97
94
  @network_recovery_interval = opts.fetch(:network_recovery_interval, DEFAULT_NETWORK_RECOVERY_INTERVAL)
98
- @shutdown_hooks = ConcurrentSkipListSet.new
95
+ @shutdown_hooks = JavaConcurrent::ConcurrentSkipListSet.new
99
96
 
100
97
  if @automatically_recover
101
98
  self.add_automatic_recovery_hook
@@ -118,7 +115,7 @@ module HotBunnies
118
115
  @connection.create_channel
119
116
  end
120
117
 
121
- ch = Channel.new(self, jc)
118
+ ch = Channel.new(self, jc, @thread_pool)
122
119
  register_channel(ch)
123
120
 
124
121
  ch
@@ -129,6 +126,11 @@ module HotBunnies
129
126
  ch.close
130
127
  end
131
128
 
129
+ @thread_pool.shutdown
130
+ unless @thread_pool.await_termination(5, JavaConcurrent::TimeUnit::SECONDS)
131
+ @thread_pool.shutdown_now
132
+ end
133
+
132
134
  @connection.close
133
135
  end
134
136
 
@@ -169,6 +171,7 @@ module HotBunnies
169
171
  @connection = converting_rjc_exceptions_to_ruby do
170
172
  self.new_connection
171
173
  end
174
+ @thread_pool = ThreadPools.dynamically_growing
172
175
  self.recover_shutdown_hooks
173
176
 
174
177
  @channels.each do |id, ch|
@@ -319,7 +322,12 @@ module HotBunnies
319
322
  # @private
320
323
  def new_connection
321
324
  converting_rjc_exceptions_to_ruby do
322
- @cf.new_connection
325
+ if @executor_factory
326
+ ex = @executor_factory.call
327
+ @cf.new_connection(ex)
328
+ else
329
+ @cf.new_connection
330
+ end
323
331
  end
324
332
  end
325
333
  end
@@ -1,6 +1,4 @@
1
1
  module HotBunnies
2
- import java.util.concurrent.Executors
3
-
4
2
  # A slighly more Ruby developer-friendly way of instantiating various
5
3
  # JDK executors (thread pools).
6
4
  class ThreadPools
@@ -11,14 +9,14 @@ module HotBunnies
11
9
  raise ArgumentError.new("n must be a positive integer!") unless Integer === n
12
10
  raise ArgumentError.new("n must be a positive integer!") unless n > 0
13
11
 
14
- Executors.new_fixed_thread_pool(n)
12
+ JavaConcurrent::Executors.new_fixed_thread_pool(n)
15
13
  end
16
14
 
17
15
  # Returns a new thread pool (JDK executor) of a fixed size of 1.
18
16
  #
19
17
  # @return A thread pool (JDK executor)
20
18
  def self.single_threaded
21
- Executors.new_single_thread_executor
19
+ JavaConcurrent::Executors.new_single_thread_executor
22
20
  end
23
21
 
24
22
  # Returns a new thread pool (JDK executor) that will create new
@@ -26,7 +24,7 @@ module HotBunnies
26
24
  #
27
25
  # @return A thread pool (JDK executor)
28
26
  def self.dynamically_growing
29
- Executors.new_cached_thread_pool
27
+ JavaConcurrent::Executors.new_cached_thread_pool
30
28
  end
31
29
  end
32
30
  end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module HotBunnies
4
- VERSION = "2.0.0.pre10"
4
+ VERSION = "2.0.0.pre11"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot_bunnies
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre10
4
+ version: 2.0.0.pre11
5
5
  prerelease: 6
6
6
  platform: java
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-08-11 00:00:00.000000000 Z
13
+ date: 2013-08-20 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: RabbitMQ client for JRuby built around the official RabbitMQ Java client
16
16
  email:
@@ -26,7 +26,6 @@ files:
26
26
  - lib/hot_bunnies/consumers.rb
27
27
  - lib/hot_bunnies/consumers/base.rb
28
28
  - lib/hot_bunnies/consumers/blocking.rb
29
- - lib/hot_bunnies/consumers/non_blocking.rb
30
29
  - lib/hot_bunnies/exceptions.rb
31
30
  - lib/hot_bunnies/exchange.rb
32
31
  - lib/hot_bunnies/juc.rb
@@ -1,93 +0,0 @@
1
- require "hot_bunnies/consumers/base"
2
-
3
- module HotBunnies
4
- class CallbackConsumer < BaseConsumer
5
- def initialize(channel, queue, callback)
6
- raise ArgumentError, "callback must not be nil!" if callback.nil?
7
-
8
- super(channel, queue)
9
- @callback = callback
10
- @callback_arity = @callback.arity
11
- end
12
-
13
- def callback(headers, message)
14
- if @callback_arity == 2
15
- @callback.call(headers, message)
16
- else
17
- @callback.call(message)
18
- end
19
- end
20
- end
21
-
22
- class AsyncCallbackConsumer < CallbackConsumer
23
- def initialize(channel, queue, opts, callback)
24
- super(channel, queue, callback)
25
-
26
- # during connection recovery, the executor may be shut down, e.g. due to
27
- # an exception. So we need a way to create a duplicate. Unfortunately, since
28
- # the executor can be passed as an argument, we cannot know how it was
29
- # instantiated. Instead we require a lambda to produce instance of an executor
30
- # as a workaround. MK.
31
- @executor_factory = opts.fetch(:executor_factory, Proc.new {
32
- JavaConcurrent::Executors.new_single_thread_executor
33
- })
34
- @executor = opts.fetch(:executor, @executor_factory.call)
35
- @executor_submit = @executor.java_method(:submit, [JavaConcurrent::Runnable.java_class])
36
- @opts = opts
37
- end
38
-
39
- def deliver(headers, message)
40
- unless @executor.shutdown?
41
- @executor_submit.call do
42
- begin
43
- callback(headers, message)
44
- rescue Exception, java.lang.Throwable => e
45
- # TODO: logging
46
- $stderr.puts "Unhandled exception in consumer #{@consumer_tag}: #{e}"
47
- end
48
- end
49
- end
50
- end
51
-
52
- def cancel
53
- @cancelling.set(true)
54
- response = channel.basic_cancel(consumer_tag)
55
- @cancelled.set(true)
56
- @terminated.set(true)
57
-
58
- gracefully_shutdown
59
-
60
- response
61
- end
62
-
63
- def handleCancel(consumer_tag)
64
- super(consumer_tag)
65
-
66
- gracefully_shutdown
67
- end
68
-
69
- def shutdown!
70
- @executor.shutdown_now if @executor
71
- end
72
- alias shut_down! shutdown!
73
-
74
- def gracefully_shut_down
75
- unless @executor.await_termination(1, JavaConcurrent::TimeUnit::SECONDS)
76
- @executor.shutdown_now
77
- end
78
- @terminated.set(true)
79
- end
80
- alias maybe_shut_down_executor gracefully_shut_down
81
- alias gracefully_shutdown gracefully_shut_down
82
-
83
-
84
- # @private
85
- def recover_from_network_failure
86
- # ensure we have a functioning executor. MK.
87
- @executor = @executor_factory.call
88
- @executor_submit = @executor.java_method(:submit, [JavaConcurrent::Runnable.java_class])
89
-
90
- super
91
- end
92
- end
93
- end