hot_bunnies 2.0.0.pre8-java → 2.0.0.pre9-java

Sign up to get free protection for your applications and to get access to all the features.
data/lib/hot_bunnies.rb CHANGED
@@ -6,10 +6,17 @@ require 'ext/rabbitmq-client'
6
6
 
7
7
  require 'hot_bunnies/version'
8
8
  require 'hot_bunnies/exceptions'
9
+ require 'hot_bunnies/thread_pools'
9
10
  require 'hot_bunnies/session'
10
11
 
12
+ # HotBunnies is a JRuby client for RabbitMQ built on top of the official Java client.
13
+ #
14
+ # @see HotBunnies.connect
15
+ # @see HotBunnies::Session
16
+ # @see HotBunnies::Channel
11
17
  module HotBunnies
12
18
  # Delegates to {HotBunnies::Session.connect}
19
+ # @see HotBunnies::Session.connect
13
20
  def self.connect(*args)
14
21
  Session.connect(*args)
15
22
  end
@@ -2,9 +2,121 @@
2
2
  require "hot_bunnies/shutdown_listener"
3
3
 
4
4
  module HotBunnies
5
+ # ## Channels in RabbitMQ
6
+ #
7
+ # To quote {http://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf AMQP 0.9.1 specification}:
8
+ #
9
+ # AMQP 0.9.1 is a multi-channelled protocol. Channels provide a way to multiplex
10
+ # a heavyweight TCP/IP connection into several light weight connections.
11
+ # This makes the protocol more “firewall friendly” since port usage is predictable.
12
+ # It also means that traffic shaping and other network QoS features can be easily employed.
13
+ # Channels are independent of each other and can perform different functions simultaneously
14
+ # with other channels, the available bandwidth being shared between the concurrent activities.
15
+ #
16
+ #
17
+ # ## Opening Channels
18
+ #
19
+ # Channels can be opened either via `HotBunnies::Session#create_channel` (sufficient in the majority
20
+ # of cases) or by instantiating `HotBunnies::Channel` directly:
21
+ #
22
+ # @example Using {HotBunnies::Session#create_channel}:
23
+ # conn = HotBunnies.new
24
+ # conn.start
25
+ #
26
+ # ch = conn.create_channel
27
+ #
28
+ # This will automatically allocate a channel id.
29
+ #
30
+ # ## Closing Channels
31
+ #
32
+ # Channels are closed via {HotBunnies::Channel#close}. Channels that get a channel-level exception are
33
+ # closed, too. Closed channels can no longer be used. Attempts to use them will raise
34
+ # {HotBunnies::ChannelAlreadyClosed}.
35
+ #
36
+ # @example
37
+ #
38
+ # ch = conn.create_channel
39
+ # ch.close
40
+ #
41
+ # ## Higher-level API
42
+ #
43
+ # HotBunnies offers two sets of methods on {HotBunnies::Channel}: known as higher-level and lower-level
44
+ # APIs, respectively. Higher-level API mimics {http://rubyamqp.info amqp gem} API where
45
+ # exchanges and queues are objects (instance of {HotBunnies::Exchange} and {HotBunnies::Queue}, respectively).
46
+ # Lower-level API is built around AMQP 0.9.1 methods (commands), where queues and exchanges are
47
+ # passed as strings (à la RabbitMQ Java client, {http://clojurerabbitmq.info Langohr} and Pika).
48
+ #
49
+ # ### Queue Operations In Higher-level API
50
+ #
51
+ # * {HotBunnies::Channel#queue} is used to declare queues. The rest of the API is in {HotBunnies::Queue}.
52
+ #
53
+ #
54
+ # ### Exchange Operations In Higher-level API
55
+ #
56
+ # * {HotBunnies::Channel#topic} declares a topic exchange. The rest of the API is in {HotBunnies::Exchange}.
57
+ # * {HotBunnies::Channel#direct} declares a direct exchange.
58
+ # * {HotBunnies::Channel#fanout} declares a fanout exchange.
59
+ # * {HotBunnies::Channel#headers} declares a headers exchange.
60
+ # * {HotBunnies::Channel#default_exchange}
61
+ # * {HotBunnies::Channel#exchange} is used to declare exchanges with type specified as a symbol or string.
62
+ #
63
+ #
64
+ # ## Channel Qos (Prefetch Level)
65
+ #
66
+ # It is possible to control how many messages at most a consumer will be given (before it acknowledges
67
+ # or rejects previously consumed ones). This setting is per channel and controlled via {HotBunnies::Channel#prefetch}.
68
+ #
69
+ #
70
+ # ## Channel IDs
71
+ #
72
+ # Channels are identified by their ids which are integers. HotBunnies takes care of allocating and
73
+ # releasing them as channels are opened and closed. It is almost never necessary to specify
74
+ # channel ids explicitly.
75
+ #
76
+ # There is a limit on the maximum number of channels per connection, usually 65536. Note
77
+ # that allocating channels is very cheap on both client and server so having tens, hundreds
78
+ # or even thousands of channels is possible.
79
+ #
80
+ # ## Channels and Error Handling
81
+ #
82
+ # Channel-level exceptions are more common than connection-level ones and often indicate
83
+ # issues applications can recover from (such as consuming from or trying to delete
84
+ # a queue that does not exist).
85
+ #
86
+ # With HotBunnies, channel-level exceptions are raised as Ruby exceptions, for example,
87
+ # {HotBunnies::NotFound}, that provide access to the underlying `channel.close` method
88
+ # information.
89
+ #
90
+ # @example Handling 404 NOT_FOUND
91
+ # begin
92
+ # ch.queue_delete("queue_that_should_not_exist#{rand}")
93
+ # rescue HotBunnies::NotFound => e
94
+ # puts "Channel-level exception! Code: #{e.channel_close.reply_code}, message: #{e.channel_close.reply_text}"
95
+ # end
96
+ #
97
+ # @example Handling 406 PRECONDITION_FAILED
98
+ # begin
99
+ # ch2 = conn.create_channel
100
+ # q = "hotbunnies.examples.recovery.q#{rand}"
101
+ #
102
+ # ch2.queue_declare(q, :durable => false)
103
+ # ch2.queue_declare(q, :durable => true)
104
+ # rescue HotBunnies::PreconditionFailed => e
105
+ # puts "Channel-level exception! Code: #{e.channel_close.reply_code}, message: #{e.channel_close.reply_text}"
106
+ # ensure
107
+ # conn.create_channel.queue_delete(q)
108
+ # end
109
+ #
110
+ # @see HotBunnies::Session#create_channel
111
+ # @see http://www.rabbitmq.com/tutorials/amqp-concepts.html AMQP 0.9.1 Model Concepts Guide
112
+ # @see http://hotbunnies.info/articles/getting_started.html Getting Started with RabbitMQ Using HotBunnies
113
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers
114
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing
5
115
  class Channel
6
- attr_reader :session, :consumers
116
+ # @return [Array<HotBunnies::Consumer>] Consumers on this channel
117
+ attr_reader :consumers
7
118
 
119
+ # @private
8
120
  def initialize(session, delegate)
9
121
  @connection = session
10
122
  @delegate = delegate
@@ -19,26 +131,41 @@ module HotBunnies
19
131
  end
20
132
  end
21
133
 
134
+ # @return [HotBunnies::Session] Connection this channel is on
22
135
  def client
23
136
  @connection
24
137
  end
25
138
 
139
+ # @return [HotBunnies::Session] Connection this channel is on
140
+ def session
141
+ @connection
142
+ end
143
+
144
+ # @return [HotBunnies::Session] Connection this channel is on
26
145
  def connection
27
146
  @connection
28
147
  end
29
148
 
149
+ # @return [Integer] Channel id
30
150
  def id
31
151
  @delegate.channel_number
32
152
  end
33
153
 
154
+ # @return [Integer] Channel id
34
155
  def number
35
156
  @delegate.channel_number
36
157
  end
37
158
 
159
+ # @return [Integer] Channel id
38
160
  def channel_number
39
161
  @delegate.channel_number
40
162
  end
41
163
 
164
+ # Closes the channel.
165
+ #
166
+ # Closed channels can no longer be used. Closed channel id is
167
+ # returned back to the pool of available ids and may be used by
168
+ # a different channel opened later.
42
169
  def close(code = 200, reason = "Goodbye")
43
170
  v = @delegate.close(code, reason)
44
171
 
@@ -60,40 +187,125 @@ module HotBunnies
60
187
 
61
188
  # @group Exchanges
62
189
 
190
+ # Declares a headers exchange or looks it up in the cache of previously
191
+ # declared exchanges.
192
+ #
193
+ # @param [String] name Exchange name
194
+ # @param [Hash] opts Exchange parameters
195
+ #
196
+ # @option options [String,Symbol] :type (:direct) Exchange type, e.g. :fanout or "x-consistent-hash"
197
+ # @option options [Boolean] :durable (false) Should the exchange be durable?
198
+ # @option options [Boolean] :auto_delete (false) Should the exchange be automatically deleted when no longer in use?
199
+ # @option options [Hash] :arguments ({}) Optional exchange arguments
200
+ #
201
+ # @return [HotBunnies::Exchange] Exchange instance
202
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing guide
203
+ # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions to AMQP 0.9.1 guide
63
204
  def exchange(name, options={})
64
205
  Exchange.new(self, name, options).tap do |x|
65
206
  x.declare!
66
207
  end
67
208
  end
68
209
 
210
+ # Declares a fanout exchange or looks it up in the cache of previously
211
+ # declared exchanges.
212
+ #
213
+ # @param [String] name Exchange name
214
+ # @param [Hash] opts Exchange parameters
215
+ #
216
+ # @option opts [Boolean] :durable (false) Should the exchange be durable?
217
+ # @option opts [Boolean] :auto_delete (false) Should the exchange be automatically deleted when no longer in use?
218
+ # @option opts [Hash] :arguments ({}) Optional exchange arguments (used by RabbitMQ extensions)
219
+ #
220
+ # @return [HotBunnies::Exchange] Exchange instance
221
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing guide
222
+ # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions to AMQP 0.9.1 guide
223
+ # @api public
69
224
  def fanout(name, opts = {})
70
225
  Exchange.new(self, name, opts.merge(:type => "fanout")).tap do |x|
71
226
  x.declare!
72
227
  end
73
228
  end
74
229
 
230
+ # Declares a direct exchange or looks it up in the cache of previously
231
+ # declared exchanges.
232
+ #
233
+ # @param [String] name Exchange name
234
+ # @param [Hash] opts Exchange parameters
235
+ #
236
+ # @option opts [Boolean] :durable (false) Should the exchange be durable?
237
+ # @option opts [Boolean] :auto_delete (false) Should the exchange be automatically deleted when no longer in use?
238
+ # @option opts [Hash] :arguments ({}) Optional exchange arguments (used by RabbitMQ extensions)
239
+ #
240
+ # @return [HotBunnies::Exchange] Exchange instance
241
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing guide
242
+ # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions to AMQP 0.9.1 guide
243
+ # @api public
75
244
  def direct(name, opts = {})
76
245
  Exchange.new(self, name, opts.merge(:type => "direct")).tap do |x|
77
246
  x.declare!
78
247
  end
79
248
  end
80
249
 
250
+ # Declares a topic exchange or looks it up in the cache of previously
251
+ # declared exchanges.
252
+ #
253
+ # @param [String] name Exchange name
254
+ # @param [Hash] opts Exchange parameters
255
+ #
256
+ # @option opts [Boolean] :durable (false) Should the exchange be durable?
257
+ # @option opts [Boolean] :auto_delete (false) Should the exchange be automatically deleted when no longer in use?
258
+ # @option opts [Hash] :arguments ({}) Optional exchange arguments (used by RabbitMQ extensions)
259
+ #
260
+ # @return [HotBunnies::Exchange] Exchange instance
261
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing guide
262
+ # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions to AMQP 0.9.1 guide
263
+ # @api public
81
264
  def topic(name, opts = {})
82
265
  Exchange.new(self, name, opts.merge(:type => "topic")).tap do |x|
83
266
  x.declare!
84
267
  end
85
268
  end
86
269
 
270
+ # Declares a headers exchange or looks it up in the cache of previously
271
+ # declared exchanges.
272
+ #
273
+ # @param [String] name Exchange name
274
+ # @param [Hash] opts Exchange parameters
275
+ #
276
+ # @option opts [Boolean] :durable (false) Should the exchange be durable?
277
+ # @option opts [Boolean] :auto_delete (false) Should the exchange be automatically deleted when no longer in use?
278
+ # @option opts [Hash] :arguments ({}) Optional exchange arguments
279
+ #
280
+ # @return [HotBunnies::Exchange] Exchange instance
281
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing guide
282
+ # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions to AMQP 0.9.1 guide
283
+ # @api public
87
284
  def headers(name, opts = {})
88
285
  Exchange.new(self, name, opts.merge(:type => "headers")).tap do |x|
89
286
  x.declare!
90
287
  end
91
288
  end
92
289
 
290
+ # Provides access to the default exchange
291
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing guide
292
+ # @api public
93
293
  def default_exchange
94
294
  @default_exchange ||= self.exchange("", :durable => true, :auto_delete => false, :type => "direct")
95
295
  end
96
296
 
297
+ # Declares a echange using echange.declare AMQP 0.9.1 method.
298
+ #
299
+ # @param [String] name Exchange name
300
+ # @param [Boolean] durable (false) Should information about this echange be persisted to disk so that it
301
+ # can survive broker restarts? Typically set to true for long-lived exchanges.
302
+ # @param [Boolean] auto_delete (false) Should this echange be deleted when it is no longer used?
303
+ # @param [Boolean] passive (false) If true, exchange will be checked for existence. If it does not
304
+ # exist, {Bunny::NotFound} will be raised.
305
+ #
306
+ # @return RabbitMQ response
307
+ # @see http://hotbunnies.info/articles/echanges.html Exchanges and Publishing guide
308
+ # @api public
97
309
  def exchange_declare(name, type, durable = false, auto_delete = false, arguments = nil)
98
310
  @delegate.exchange_declare(name, type, durable, auto_delete, arguments)
99
311
  end
@@ -103,42 +315,120 @@ module HotBunnies
103
315
 
104
316
  # @group Queues
105
317
 
318
+ # Declares a queue or looks it up in the per-channel cache.
319
+ #
320
+ # @param [String] name Queue name. Pass an empty string to declare a server-named queue (make RabbitMQ generate a unique name).
321
+ # @param [Hash] options Queue properties and other options
322
+ #
323
+ # @option options [Boolean] :durable (false) Should this queue be durable?
324
+ # @option options [Boolean] :auto-delete (false) Should this queue be automatically deleted when the last consumer disconnects?
325
+ # @option options [Boolean] :exclusive (false) Should this queue be exclusive (only can be used by this connection, removed when the connection is closed)?
326
+ # @option options [Boolean] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
327
+ #
328
+ # @return [HotBunnies::Queue] Queue that was declared or looked up in the cache
329
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
330
+ # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions guide
331
+ # @api public
106
332
  def queue(name, options={})
107
333
  Queue.new(self, name, options).tap do |q|
108
334
  q.declare!
109
335
  end
110
336
  end
111
337
 
338
+ # Declares a queue using queue.declare AMQP 0.9.1 method.
339
+ #
340
+ # @param [String] name Queue name
341
+ #
342
+ # @param [Boolean] durable (false) Should information about this queue be persisted to disk so that it
343
+ # can survive broker restarts? Typically set to true for long-lived queues.
344
+ # @param [Boolean] auto_delete (false) Should this queue be deleted when the last consumer is cancelled?
345
+ # @param [Boolean] exclusive (false) Should only this connection be able to use this queue?
346
+ # If true, the queue will be automatically deleted when this
347
+ # connection is closed
348
+ # @param [Boolean] passive (false) If true, queue will be checked for existence. If it does not
349
+ # exist, {Bunny::NotFound} will be raised.
350
+ #
351
+ # @return RabbitMQ response
352
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
353
+ # @api public
112
354
  def queue_declare(name, durable, exclusive, auto_delete, arguments = {})
113
355
  converting_rjc_exceptions_to_ruby do
114
356
  @delegate.queue_declare(name, durable, exclusive, auto_delete, arguments)
115
357
  end
116
358
  end
117
359
 
360
+ # Checks if a queue exists using queue.declare AMQP 0.9.1 method.
361
+ # If it does not, a channel exception will be raised.
362
+ #
363
+ # @param [String] name Queue name
364
+ #
365
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
366
+ # @api public
118
367
  def queue_declare_passive(name)
119
368
  converting_rjc_exceptions_to_ruby do
120
369
  @delegate.queue_declare_passive(name)
121
370
  end
122
371
  end
123
372
 
373
+ # Deletes a queue using queue.delete AMQP 0.9.1 method
374
+ #
375
+ # @param [String] name Queue name
376
+ #
377
+ # @param [Boolean] if_empty (false) Should this queue be deleted only if it has no messages?
378
+ # @param [Boolean] if_unused (false) Should this queue be deleted only if it has no consumers?
379
+ #
380
+ # @return RabbitMQ response
381
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
382
+ # @api public
124
383
  def queue_delete(name, if_empty = false, if_unused = false)
125
384
  converting_rjc_exceptions_to_ruby do
126
385
  @delegate.queue_delete(name, if_empty, if_unused)
127
386
  end
128
387
  end
129
388
 
389
+ # Binds a queue to an exchange using queue.bind AMQP 0.9.1 method
390
+ #
391
+ # @param [String] name Queue name
392
+ # @param [String] exchange Exchange name
393
+ #
394
+ # @param [String] routing_key Routing key used for binding
395
+ # @param [Hash] arguments (nil) Optional arguments
396
+ #
397
+ # @return RabbitMQ response
398
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
399
+ # @see http://hotbunnies.info/articles/bindings.html Bindings guide
400
+ # @api public
130
401
  def queue_bind(queue, exchange, routing_key, arguments = nil)
131
402
  converting_rjc_exceptions_to_ruby do
132
403
  @delegate.queue_bind(queue, exchange, routing_key, arguments)
133
404
  end
134
405
  end
135
406
 
407
+ # Unbinds a queue from an exchange using queue.unbind AMQP 0.9.1 method
408
+ #
409
+ # @param [String] name Queue name
410
+ # @param [String] exchange Exchange name
411
+ #
412
+ # @param [String] routing_key Routing key used for binding
413
+ # @param [Hash] arguments ({}) Optional arguments
414
+ #
415
+ # @return RabbitMQ response
416
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
417
+ # @see http://hotbunnies.info/articles/bindings.html Bindings guide
418
+ # @api public
136
419
  def queue_unbind(queue, exchange, routing_key, arguments = nil)
137
420
  converting_rjc_exceptions_to_ruby do
138
421
  @delegate.queue_unbind(queue, exchange, routing_key, arguments)
139
422
  end
140
423
  end
141
424
 
425
+ # Purges a queue (removes all messages from it) using queue.purge AMQP 0.9.1 method.
426
+ #
427
+ # @param [String] name Queue name
428
+ #
429
+ # @return RabbitMQ response
430
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
431
+ # @api public
142
432
  def queue_purge(name)
143
433
  converting_rjc_exceptions_to_ruby do
144
434
  @delegate.queue_purge(name)
@@ -150,6 +440,30 @@ module HotBunnies
150
440
 
151
441
  # @group basic.*
152
442
 
443
+ # Publishes a message using basic.publish AMQP 0.9.1 method.
444
+ #
445
+ # @param [String] exchange Exchange to publish to
446
+ # @param [String] routing_key Routing key
447
+ # @param [String] body Message payload. It will never be modified by Bunny or RabbitMQ in any way.
448
+ # @option opts [Boolean] :mandatory Should the message be returned if it cannot be routed to any queue?
449
+ #
450
+ # @param [Hash] properties Message properties
451
+ #
452
+ # @option properties [Boolean] :persistent Should the message be persisted to disk?
453
+ # @option properties [Integer] :timestamp A timestamp associated with this message
454
+ # @option properties [Integer] :expiration Expiration time after which the message will be deleted
455
+ # @option properties [String] :type Message type, e.g. what type of event or command this message represents. Can be any string
456
+ # @option properties [String] :reply_to Queue name other apps should send the response to
457
+ # @option properties [String] :content_type Message content type (e.g. application/json)
458
+ # @option properties [String] :content_encoding Message content encoding (e.g. gzip)
459
+ # @option properties [String] :correlation_id Message correlated to this one, e.g. what request this message is a reply for
460
+ # @option properties [Integer] :priority Message priority, 0 to 9. Not used by RabbitMQ, only applications
461
+ # @option properties [String] :message_id Any message identifier
462
+ # @option properties [String] :user_id Optional user ID. Verified by RabbitMQ against the actual connection username
463
+ # @option properties [String] :app_id Optional application ID
464
+ #
465
+ # @return [HotBunnies::Channel] Self
466
+ # @api public
153
467
  def basic_publish(exchange, routing_key, mandatory, properties, body)
154
468
  converting_rjc_exceptions_to_ruby do
155
469
  @delegate.basic_publish(exchange, routing_key, mandatory, false, BasicPropertiesBuilder.build_properties_from(properties || Hash.new), body)
@@ -181,10 +495,24 @@ module HotBunnies
181
495
  end
182
496
  end
183
497
 
498
+ # Sets how many messages will be given to consumers on this channel before they
499
+ # have to acknowledge or reject one of the previously consumed messages
500
+ #
501
+ # @param [Integer] prefetch_count Prefetch (QoS setting) for this channel
502
+ # @see http://hotbunnies.info/articles/exchanges.html Exchanges and Publishing guide
503
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
504
+ # @api public
184
505
  def prefetch=(n)
185
506
  basic_qos(n)
186
507
  end
187
508
 
509
+ # Acknowledges a message. Acknowledged messages are completely removed from the queue.
510
+ #
511
+ # @param [Integer] delivery_tag Delivery tag to acknowledge
512
+ # @param [Boolean] multiple (false) Should all unacknowledged messages up to this be acknowledged as well?
513
+ # @see #nack
514
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
515
+ # @api public
188
516
  def ack(delivery_tag, multiple = false)
189
517
  converting_rjc_exceptions_to_ruby do
190
518
  basic_ack(delivery_tag, multiple)
@@ -192,24 +520,120 @@ module HotBunnies
192
520
  end
193
521
  alias acknowledge ack
194
522
 
523
+ # Rejects a message. A rejected message can be requeued or
524
+ # dropped by RabbitMQ.
525
+ #
526
+ # @param [Integer] delivery_tag Delivery tag to reject
527
+ # @param [Boolean] requeue Should this message be requeued instead of dropping it?
528
+ # @see #ack
529
+ # @see #nack
530
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
531
+ # @api public
195
532
  def reject(delivery_tag, requeue = false)
196
533
  converting_rjc_exceptions_to_ruby do
197
534
  basic_reject(delivery_tag, requeue)
198
535
  end
199
536
  end
200
537
 
538
+ # Rejects a message. A rejected message can be requeued or
539
+ # dropped by RabbitMQ. This method is similar to {Bunny::Channel#reject} but
540
+ # supports rejecting multiple messages at once, and is usually preferred.
541
+ #
542
+ # @param [Integer] delivery_tag Delivery tag to reject
543
+ # @param [Boolean] multiple (false) Should all unacknowledged messages up to this be rejected as well?
544
+ # @param [Boolean] requeue (false) Should this message be requeued instead of dropping it?
545
+ # @see #ack
546
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
547
+ # @api public
201
548
  def nack(delivery_tag, multiple = false, requeue = false)
202
549
  converting_rjc_exceptions_to_ruby do
203
550
  basic_nack(delivery_tag, multiple, requeue)
204
551
  end
205
552
  end
206
553
 
554
+ # Rejects or requeues a message.
555
+ #
556
+ # @param [Integer] delivery_tag Delivery tag obtained from delivery info
557
+ # @param [Boolean] requeue Should the message be requeued?
558
+ # @return [NilClass] nil
559
+ #
560
+ # @example Requeue a message
561
+ # conn = Bunny.new
562
+ # conn.start
563
+ #
564
+ # ch = conn.create_channel
565
+ # q.subscribe do |delivery_info, properties, payload|
566
+ # # requeue the message
567
+ # ch.basic_reject(delivery_info.delivery_tag, true)
568
+ # end
569
+ #
570
+ # @example Reject a message
571
+ # conn = Bunny.new
572
+ # conn.start
573
+ #
574
+ # ch = conn.create_channel
575
+ # q.subscribe do |delivery_info, properties, payload|
576
+ # # requeue the message
577
+ # ch.basic_reject(delivery_info.delivery_tag, false)
578
+ # end
579
+ #
580
+ # @example Requeue a message fetched via basic.get
581
+ # conn = Bunny.new
582
+ # conn.start
583
+ #
584
+ # ch = conn.create_channel
585
+ # # we assume the queue exists and has messages
586
+ # delivery_info, properties, payload = ch.basic_get("bunny.examples.queue3", :ack => true)
587
+ # ch.basic_reject(delivery_info.delivery_tag, true)
588
+ #
589
+ # @see #basic_nack
590
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
591
+ # @api public
592
+ def basic_reject(delivery_tag, requeue)
593
+ converting_rjc_exceptions_to_ruby do
594
+ @delegate.basic_reject(delivery_tag, requeue)
595
+ end
596
+ end
597
+
598
+ def basic_ack(delivery_tag, multiple)
599
+ converting_rjc_exceptions_to_ruby do
600
+ @delegate.basic_ack(delivery_tag, multiple)
601
+ end
602
+ end
603
+
604
+ # Rejects or requeues messages just like {Bunny::Channel#basic_reject} but can do so
605
+ # with multiple messages at once.
606
+ #
607
+ # @param [Integer] delivery_tag Delivery tag obtained from delivery info
608
+ # @param [Boolean] requeue Should the message be requeued?
609
+ # @param [Boolean] multiple Should all deliveries up to this one be rejected/requeued?
610
+ # @return [NilClass] nil
611
+ #
612
+ # @see http://hotbunnies.info/articles/queues.html Queues and Consumers guide
613
+ # @see http://hotbunnies.info/articles/extensions.html RabbitMQ Extensions guide
614
+ # @api public
615
+ def basic_nack(delivery_tag, multiple = false, requeue = false)
616
+ converting_rjc_exceptions_to_ruby do
617
+ @delegate.basic_nack(delivery_tag, multiple, requeue)
618
+ end
619
+ end
620
+
621
+ # Redeliver unacknowledged messages
622
+ #
623
+ # @param [Boolean] requeue Should messages be requeued?
624
+ # @return RabbitMQ response
625
+ # @api public
207
626
  def basic_recover(requeue = true)
208
627
  converting_rjc_exceptions_to_ruby do
209
628
  @delegate.basic_recover(requeue)
210
629
  end
211
630
  end
212
631
 
632
+ # Redeliver unacknowledged messages
633
+ #
634
+ # @param [Boolean] requeue Should messages be requeued?
635
+ # @return RabbitMQ response
636
+ # @api public
213
637
  def basic_recover_async(requeue = true)
214
638
  converting_rjc_exceptions_to_ruby do
215
639
  @delegate.basic_recover_async(requeue)
@@ -1,209 +1,5 @@
1
- module HotBunnies
2
- import com.rabbitmq.client.DefaultConsumer
1
+ require "hot_bunnies/thread_pools"
3
2
 
4
- class BaseConsumer < DefaultConsumer
5
- attr_accessor :consumer_tag
6
-
7
- def initialize(channel)
8
- super(channel)
9
- @channel = channel
10
-
11
- @cancelling = JavaConcurrent::AtomicBoolean.new
12
- @cancelled = JavaConcurrent::AtomicBoolean.new
13
-
14
- @terminated = JavaConcurrent::AtomicBoolean.new
15
- end
16
-
17
- def handleDelivery(consumer_tag, envelope, properties, body)
18
- body = String.from_java_bytes(body)
19
- headers = Headers.new(channel, consumer_tag, envelope, properties)
20
-
21
- deliver(headers, body)
22
- end
23
-
24
- def handleCancel(consumer_tag)
25
- @cancelled.set(true)
26
- @channel.unregister_consumer(consumer_tag)
27
-
28
- if f = @opts[:on_cancellation]
29
- case f.arity
30
- when 0 then
31
- f.call
32
- when 1 then
33
- f.call(self)
34
- when 2 then
35
- f.call(@channel, self)
36
- when 3 then
37
- f.call(@channel, self, consumer_tag)
38
- else
39
- f.call(@channel, self, consumer_tag)
40
- end
41
- end
42
-
43
- @terminated.set(true)
44
- end
45
-
46
- def handleCancelOk(consumer_tag)
47
- @cancelled.set(true)
48
- @channel.unregister_consumer(consumer_tag)
49
-
50
- @terminated.set(true)
51
- end
52
-
53
- def start
54
- end
55
-
56
- def deliver(headers, message)
57
- raise NotImplementedError, 'To be implemented by a subclass'
58
- end
59
-
60
- def cancel
61
- @cancelling.set(true)
62
- response = channel.basic_cancel(consumer_tag)
63
- @cancelled.set(true)
64
- @terminated.set(true)
65
-
66
- response
67
- end
68
-
69
- def cancelled?
70
- @cancelling.get || @cancelled.get
71
- end
72
-
73
- def active?
74
- !terminated?
75
- end
76
-
77
- def terminated?
78
- @terminated.get
79
- end
80
- end
81
-
82
-
83
- class CallbackConsumer < BaseConsumer
84
- def initialize(channel, callback)
85
- raise ArgumentError, "callback must not be nil!" if callback.nil?
86
-
87
- super(channel)
88
- @callback = callback
89
- @callback_arity = @callback.arity
90
- end
91
-
92
- def callback(headers, message)
93
- if @callback_arity == 2
94
- @callback.call(headers, message)
95
- else
96
- @callback.call(message)
97
- end
98
- end
99
- end
100
-
101
- class AsyncCallbackConsumer < CallbackConsumer
102
- def initialize(channel, opts, callback, executor)
103
- super(channel, callback)
104
- @executor = executor
105
- @executor_submit = executor.java_method(:submit, [JavaConcurrent::Runnable.java_class])
106
- @opts = opts
107
- end
108
-
109
- def deliver(headers, message)
110
- unless @executor.shutdown?
111
- @executor_submit.call do
112
- begin
113
- callback(headers, message)
114
- rescue Exception => e
115
- $stderr.puts "Unhandled exception in consumer #{@consumer_tag}: #{e.message}"
116
- end
117
- end
118
- end
119
- end
120
-
121
- def cancel
122
- super
123
-
124
- gracefully_shutdown
125
- end
126
-
127
- def handleCancel(consumer_tag)
128
- super(consumer_tag)
129
-
130
- gracefully_shutdown
131
- end
132
-
133
- def shutdown!
134
- @executor.shutdown_now if @executor
135
- end
136
- alias shut_down! shutdown!
137
-
138
- def gracefully_shut_down
139
- unless @executor.await_termination(1, JavaConcurrent::TimeUnit::SECONDS)
140
- @executor.shutdown_now
141
- end
142
- @terminated.set(true)
143
- end
144
- alias maybe_shut_down_executor gracefully_shut_down
145
- alias gracefully_shutdown gracefully_shut_down
146
- end
147
-
148
- class BlockingCallbackConsumer < CallbackConsumer
149
- include JavaConcurrent
150
-
151
- POISON = :__poison__
152
-
153
- def initialize(channel, buffer_size, opts, callback)
154
- super(channel, callback)
155
- if buffer_size
156
- @internal_queue = ArrayBlockingQueue.new(buffer_size)
157
- else
158
- @internal_queue = LinkedBlockingQueue.new
159
- end
160
-
161
- @opts = opts
162
- end
163
-
164
- def start
165
- interrupted = false
166
- until (@cancelling.get || @cancelled.get) || JavaConcurrent::Thread.current_thread.interrupted?
167
- begin
168
- pair = @internal_queue.take
169
- if pair
170
- if pair == POISON
171
- @cancelling.set(true)
172
- else
173
- callback(*pair)
174
- end
175
- end
176
- rescue InterruptedException => e
177
- interrupted = true
178
- end
179
- end
180
- while (pair = @internal_queue.poll)
181
- callback(*pair)
182
- end
183
- @terminated.set(true)
184
- if interrupted
185
- JavaConcurrent::Thread.current_thread.interrupt
186
- end
187
- end
188
-
189
- def deliver(*pair)
190
- if (@cancelling.get || @cancelled.get) || JavaConcurrent::Thread.current_thread.interrupted?
191
- @internal_queue.offer(pair)
192
- else
193
- begin
194
- @internal_queue.put(pair)
195
- rescue InterruptedException => e
196
- JavaConcurrent::Thread.current_thread.interrupt
197
- end
198
- end
199
- end
200
-
201
- def gracefully_shut_down
202
- @cancelling.set(true)
203
- @internal_queue.offer(POISON)
204
-
205
- @terminated.set(true)
206
- end
207
-
208
- end
209
- end
3
+ require "hot_bunnies/consumers/base"
4
+ require "hot_bunnies/consumers/non_blocking"
5
+ require "hot_bunnies/consumers/blocking"
@@ -0,0 +1,72 @@
1
+ module HotBunnies
2
+ import com.rabbitmq.client.DefaultConsumer
3
+
4
+ class BaseConsumer < DefaultConsumer
5
+ attr_accessor :consumer_tag
6
+
7
+ def initialize(channel)
8
+ super(channel)
9
+ @channel = channel
10
+
11
+ @cancelling = JavaConcurrent::AtomicBoolean.new
12
+ @cancelled = JavaConcurrent::AtomicBoolean.new
13
+
14
+ @terminated = JavaConcurrent::AtomicBoolean.new
15
+ end
16
+
17
+ def handleDelivery(consumer_tag, envelope, properties, body)
18
+ body = String.from_java_bytes(body)
19
+ headers = Headers.new(channel, consumer_tag, envelope, properties)
20
+
21
+ deliver(headers, body)
22
+ end
23
+
24
+ def handleCancel(consumer_tag)
25
+ @cancelled.set(true)
26
+ @channel.unregister_consumer(consumer_tag)
27
+
28
+ if f = @opts[:on_cancellation]
29
+ case f.arity
30
+ when 0 then
31
+ f.call
32
+ when 1 then
33
+ f.call(self)
34
+ when 2 then
35
+ f.call(@channel, self)
36
+ when 3 then
37
+ f.call(@channel, self, consumer_tag)
38
+ else
39
+ f.call(@channel, self, consumer_tag)
40
+ end
41
+ end
42
+
43
+ @terminated.set(true)
44
+ end
45
+
46
+ def handleCancelOk(consumer_tag)
47
+ @cancelled.set(true)
48
+ @channel.unregister_consumer(consumer_tag)
49
+
50
+ @terminated.set(true)
51
+ end
52
+
53
+ def start
54
+ end
55
+
56
+ def deliver(headers, message)
57
+ raise NotImplementedError, 'To be implemented by a subclass'
58
+ end
59
+
60
+ def cancelled?
61
+ @cancelling.get || @cancelled.get
62
+ end
63
+
64
+ def active?
65
+ !terminated?
66
+ end
67
+
68
+ def terminated?
69
+ @terminated.get
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,82 @@
1
+ require "hot_bunnies/consumers/base"
2
+
3
+ module HotBunnies
4
+ class BlockingCallbackConsumer < CallbackConsumer
5
+ include JavaConcurrent
6
+
7
+ POISON = :__poison__
8
+
9
+ def initialize(channel, buffer_size, opts, callback)
10
+ super(channel, callback)
11
+ if buffer_size
12
+ @internal_queue = ArrayBlockingQueue.new(buffer_size)
13
+ else
14
+ @internal_queue = LinkedBlockingQueue.new
15
+ end
16
+
17
+ @opts = opts
18
+ end
19
+
20
+ def cancel
21
+ @cancelling.set(true)
22
+ response = channel.basic_cancel(consumer_tag)
23
+ @cancelled.set(true)
24
+
25
+ @internal_queue.offer(POISON)
26
+ @terminated.set(true)
27
+
28
+ response
29
+ end
30
+
31
+ def start
32
+ interrupted = false
33
+ until (@cancelling.get || @cancelled.get) || JavaConcurrent::Thread.current_thread.interrupted?
34
+ begin
35
+ pair = @internal_queue.take
36
+ if pair
37
+ if pair == POISON
38
+ @cancelling.set(true)
39
+ else
40
+ callback(*pair)
41
+ end
42
+ end
43
+ rescue InterruptedException => e
44
+ interrupted = true
45
+ end
46
+ end
47
+ while (pair = @internal_queue.poll)
48
+ if pair
49
+ if pair == POISON
50
+ @cancelling.set(true)
51
+ else
52
+ callback(*pair)
53
+ end
54
+ end
55
+ end
56
+ @terminated.set(true)
57
+ if interrupted
58
+ JavaConcurrent::Thread.current_thread.interrupt
59
+ end
60
+ end
61
+
62
+ def deliver(*pair)
63
+ if (@cancelling.get || @cancelled.get) || JavaConcurrent::Thread.current_thread.interrupted?
64
+ @internal_queue.offer(pair)
65
+ else
66
+ begin
67
+ @internal_queue.put(pair)
68
+ rescue InterruptedException => e
69
+ JavaConcurrent::Thread.current_thread.interrupt
70
+ end
71
+ end
72
+ end
73
+
74
+ def gracefully_shut_down
75
+ @cancelling.set(true)
76
+ @internal_queue.offer(POISON)
77
+
78
+ @terminated.set(true)
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,73 @@
1
+ require "hot_bunnies/consumers/base"
2
+
3
+ module HotBunnies
4
+ class CallbackConsumer < BaseConsumer
5
+ def initialize(channel, callback)
6
+ raise ArgumentError, "callback must not be nil!" if callback.nil?
7
+
8
+ super(channel)
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, opts, callback, executor)
24
+ super(channel, callback)
25
+ @executor = executor
26
+ @executor_submit = executor.java_method(:submit, [JavaConcurrent::Runnable.java_class])
27
+ @opts = opts
28
+ end
29
+
30
+ def deliver(headers, message)
31
+ unless @executor.shutdown?
32
+ @executor_submit.call do
33
+ begin
34
+ callback(headers, message)
35
+ rescue Exception => e
36
+ $stderr.puts "Unhandled exception in consumer #{@consumer_tag}: #{e.message}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def cancel
43
+ @cancelling.set(true)
44
+ response = channel.basic_cancel(consumer_tag)
45
+ @cancelled.set(true)
46
+ @terminated.set(true)
47
+
48
+ gracefully_shutdown
49
+
50
+ response
51
+ end
52
+
53
+ def handleCancel(consumer_tag)
54
+ super(consumer_tag)
55
+
56
+ gracefully_shutdown
57
+ end
58
+
59
+ def shutdown!
60
+ @executor.shutdown_now if @executor
61
+ end
62
+ alias shut_down! shutdown!
63
+
64
+ def gracefully_shut_down
65
+ unless @executor.await_termination(1, JavaConcurrent::TimeUnit::SECONDS)
66
+ @executor.shutdown_now
67
+ end
68
+ @terminated.set(true)
69
+ end
70
+ alias maybe_shut_down_executor gracefully_shut_down
71
+ alias gracefully_shutdown gracefully_shut_down
72
+ end
73
+ end
@@ -6,6 +6,16 @@ module HotBunnies
6
6
  java_import com.rabbitmq.client.Connection
7
7
  java_import java.util.concurrent.ConcurrentHashMap
8
8
 
9
+ # Connection to a RabbitMQ node.
10
+ #
11
+ # Used to open and close connections and open (create) new channels.
12
+ #
13
+ # @see .connect
14
+ # @see #create_channel
15
+ # @see #close
16
+ # @api public
17
+ # @see http://hotbunnies.info/articles/getting_started.html Getting Started guide
18
+ # @see http://hotbunnies.info/articles/connecting.html Connecting to RabbitMQ guide
9
19
  class Session
10
20
 
11
21
  #
@@ -14,13 +24,26 @@ module HotBunnies
14
24
 
15
25
  # Connects to a RabbitMQ node.
16
26
  #
27
+ # @param [Hash] options Connection options
28
+ #
29
+ # @option options [String] :host ("127.0.0.1") Hostname or IP address to connect to
30
+ # @option options [Integer] :port (5672) Port RabbitMQ listens on
31
+ # @option options [String] :username ("guest") Username
32
+ # @option options [String] :password ("guest") Password
33
+ # @option options [String] :vhost ("/") Virtual host to use
34
+ # @option options [Integer] :heartbeat (600) Heartbeat interval. 0 means no heartbeat.
35
+ # @option options [Boolean] :tls (false) Set to true to use TLS/SSL connection. This will switch port to 5671 by default.
36
+ #
37
+ # @see http://hotbunnies.info/articles/connecting.html Connecting to RabbitMQ guide
38
+ #
39
+ #
17
40
  # @api public
18
41
  def self.connect(options={})
19
42
  cf = ConnectionFactory.new
20
43
 
21
44
  cf.uri = options[:uri] if options[:uri]
22
45
  cf.host = hostname_from(options) if include_host?(options)
23
- cf.port = options[:port] if options[:port]
46
+ cf.port = options[:port].to_i if options[:port]
24
47
  cf.virtual_host = vhost_from(options) if include_vhost?(options)
25
48
  cf.connection_timeout = timeout_from(options) if include_timeout?(options)
26
49
  cf.username = username_from(options) if include_username?(options)
@@ -45,9 +68,13 @@ module HotBunnies
45
68
  new(cf)
46
69
  end
47
70
 
48
- attr_reader :thread, :channels
71
+ # @private
72
+ attr_reader :thread
73
+ # @return [Array<HotBunnies::Channel>] Channels opened on this connection
74
+ attr_reader :channels
49
75
 
50
76
 
77
+ # @private
51
78
  def initialize(connection_factory)
52
79
  @cf = connection_factory
53
80
  @connection = converting_rjc_exceptions_to_ruby do
@@ -58,6 +85,15 @@ module HotBunnies
58
85
  @thread = Thread.current
59
86
  end
60
87
 
88
+ # Opens a new channel.
89
+ #
90
+ # @param [Integer] (nil): Channel number. Pass nil to let HotBunnies allocate an available number
91
+ # in a safe way.
92
+ #
93
+ # @return [HotBunnies::Channel] Newly created channel
94
+ # @see HotBunnies::Channel
95
+ # @see http://hotbunnies.info/articles/getting_started.html Getting Started guide
96
+ # @api public
61
97
  def create_channel(n = nil)
62
98
  jc = if n
63
99
  @connection.create_channel(n)
@@ -86,7 +122,7 @@ module HotBunnies
86
122
  sh
87
123
  end
88
124
 
89
-
125
+ # Flushes the socket used by this connection.
90
126
  def flush
91
127
  @connection.flush
92
128
  end
@@ -95,6 +131,7 @@ module HotBunnies
95
131
  @connection.heartbeat = n
96
132
  end
97
133
 
134
+ # No-op, exists for better API compatibility with Bunny.
98
135
  def start
99
136
  # no-op
100
137
  #
@@ -125,64 +162,79 @@ module HotBunnies
125
162
  @channels[ch.channel_number] = ch
126
163
  end
127
164
 
165
+ # @private
128
166
  def unregister_channel(ch)
129
167
  @channels.delete(ch.channel_number)
130
168
  end
131
169
 
132
170
  protected
133
171
 
172
+ # @private
134
173
  def self.hostname_from(options)
135
174
  options[:host] || options[:hostname] || ConnectionFactory.DEFAULT_HOST
136
175
  end
137
176
 
177
+ # @private
138
178
  def self.include_host?(options)
139
179
  !!(options[:host] || options[:hostname])
140
180
  end
141
181
 
182
+ # @private
142
183
  def self.vhost_from(options)
143
184
  options[:virtual_host] || options[:vhost] || ConnectionFactory.DEFAULT_VHOST
144
185
  end
145
186
 
187
+ # @private
146
188
  def self.include_vhost?(options)
147
189
  !!(options[:virtual_host] || options[:vhost])
148
190
  end
149
191
 
192
+ # @private
150
193
  def self.timeout_from(options)
151
194
  options[:connection_timeout] || options[:timeout]
152
195
  end
153
196
 
197
+ # @private
154
198
  def self.include_timeout?(options)
155
199
  !!(options[:connection_timeout] || options[:timeout])
156
200
  end
157
201
 
202
+ # @private
158
203
  def self.username_from(options)
159
204
  options[:username] || options[:user] || ConnectionFactory.DEFAULT_USER
160
205
  end
161
206
 
207
+ # @private
162
208
  def self.heartbeat_from(options)
163
209
  options[:heartbeat_interval] || options[:requested_heartbeat] || ConnectionFactory.DEFAULT_HEARTBEAT
164
210
  end
165
211
 
212
+ # @private
166
213
  def self.connection_timeout_from(options)
167
214
  options[:connection_timeout_interval] || options[:connection_timeout] || ConnectionFactory.DEFAULT_CONNECTION_TIMEOUT
168
215
  end
169
216
 
217
+ # @private
170
218
  def self.include_username?(options)
171
219
  !!(options[:username] || options[:user])
172
220
  end
173
221
 
222
+ # @private
174
223
  def self.password_from(options)
175
224
  options[:password] || options[:pass] || ConnectionFactory.DEFAULT_PASS
176
225
  end
177
226
 
227
+ # @private
178
228
  def self.include_password?(options)
179
229
  !!(options[:password] || options[:pass])
180
230
  end
181
231
 
232
+ # @private
182
233
  def self.include_heartbeat?(options)
183
234
  !!(options[:heartbeat_interval] || options[:requested_heartbeat] || options[:heartbeat])
184
235
  end
185
236
 
237
+ # @private
186
238
  def self.include_connection_timeout?(options)
187
239
  !!(options[:connection_timeout_interval] || options[:connection_timeout])
188
240
  end
@@ -203,6 +255,7 @@ module HotBunnies
203
255
  end
204
256
  end
205
257
 
258
+ # @private
206
259
  def new_connection
207
260
  converting_rjc_exceptions_to_ruby do
208
261
  @cf.new_connection
@@ -0,0 +1,32 @@
1
+ module HotBunnies
2
+ import java.util.concurrent.Executors
3
+
4
+ # A slighly more Ruby developer-friendly way of instantiating various
5
+ # JDK executors (thread pools).
6
+ class ThreadPools
7
+ # Returns a new thread pool (JDK executor) of a fixed size.
8
+ #
9
+ # @return A thread pool (JDK executor)
10
+ def self.fixed_of_size(n)
11
+ raise ArgumentError.new("n must be a positive integer!") unless Integer === n
12
+ raise ArgumentError.new("n must be a positive integer!") unless n > 0
13
+
14
+ Executors.new_fixed_thread_pool(n)
15
+ end
16
+
17
+ # Returns a new thread pool (JDK executor) of a fixed size of 1.
18
+ #
19
+ # @return A thread pool (JDK executor)
20
+ def self.single_threaded
21
+ Executors.new_single_thread_executor
22
+ end
23
+
24
+ # Returns a new thread pool (JDK executor) that will create new
25
+ # threads as needed.
26
+ #
27
+ # @return A thread pool (JDK executor)
28
+ def self.dynamically_growing
29
+ Executors.new_cached_thread_pool
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module HotBunnies
4
- VERSION = "2.0.0.pre8"
4
+ VERSION = "2.0.0.pre9"
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.pre8
4
+ version: 2.0.0.pre9
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-07-04 00:00:00.000000000 Z
13
+ date: 2013-07-11 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:
@@ -24,6 +24,9 @@ files:
24
24
  - lib/hot_bunnies.rb
25
25
  - lib/hot_bunnies/channel.rb
26
26
  - lib/hot_bunnies/consumers.rb
27
+ - lib/hot_bunnies/consumers/base.rb
28
+ - lib/hot_bunnies/consumers/blocking.rb
29
+ - lib/hot_bunnies/consumers/non_blocking.rb
27
30
  - lib/hot_bunnies/exceptions.rb
28
31
  - lib/hot_bunnies/exchange.rb
29
32
  - lib/hot_bunnies/juc.rb
@@ -31,6 +34,7 @@ files:
31
34
  - lib/hot_bunnies/queue.rb
32
35
  - lib/hot_bunnies/session.rb
33
36
  - lib/hot_bunnies/shutdown_listener.rb
37
+ - lib/hot_bunnies/thread_pools.rb
34
38
  - lib/hot_bunnies/version.rb
35
39
  homepage: http://hotbunnies.info
36
40
  licenses: []