bunny 0.5.3 → 0.6.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 (41) hide show
  1. data/{README → README.rdoc} +9 -2
  2. data/bunny.gemspec +12 -7
  3. data/examples/simple_08.rb +1 -1
  4. data/examples/simple_09.rb +1 -1
  5. data/examples/simple_ack_08.rb +1 -1
  6. data/examples/simple_ack_09.rb +1 -1
  7. data/examples/simple_consumer_08.rb +6 -14
  8. data/examples/simple_consumer_09.rb +6 -14
  9. data/examples/simple_fanout_08.rb +2 -2
  10. data/examples/simple_fanout_09.rb +2 -2
  11. data/examples/simple_headers_08.rb +1 -1
  12. data/examples/simple_headers_09.rb +1 -1
  13. data/examples/simple_topic_08.rb +4 -4
  14. data/examples/simple_topic_09.rb +4 -4
  15. data/lib/bunny.rb +23 -15
  16. data/lib/bunny/channel08.rb +8 -2
  17. data/lib/bunny/channel09.rb +8 -2
  18. data/lib/bunny/client08.rb +67 -24
  19. data/lib/bunny/client09.rb +88 -48
  20. data/lib/bunny/exchange08.rb +55 -43
  21. data/lib/bunny/exchange09.rb +67 -54
  22. data/lib/bunny/queue08.rb +79 -137
  23. data/lib/bunny/queue09.rb +79 -141
  24. data/lib/bunny/subscription08.rb +85 -0
  25. data/lib/bunny/subscription09.rb +85 -0
  26. data/lib/qrack/client.rb +29 -10
  27. data/lib/qrack/protocol/spec08.rb +1 -0
  28. data/lib/qrack/protocol/spec09.rb +1 -0
  29. data/lib/qrack/qrack08.rb +1 -0
  30. data/lib/qrack/qrack09.rb +1 -0
  31. data/lib/qrack/queue.rb +1 -1
  32. data/lib/qrack/subscription.rb +102 -0
  33. data/spec/spec_08/bunny_spec.rb +6 -0
  34. data/spec/spec_08/connection_spec.rb +12 -0
  35. data/spec/spec_08/exchange_spec.rb +19 -3
  36. data/spec/spec_08/queue_spec.rb +87 -13
  37. data/spec/spec_09/bunny_spec.rb +7 -1
  38. data/spec/spec_09/connection_spec.rb +12 -0
  39. data/spec/spec_09/exchange_spec.rb +19 -3
  40. data/spec/spec_09/queue_spec.rb +94 -21
  41. metadata +11 -6
@@ -18,6 +18,7 @@ Queues must be attached to at least one exchange in order to receive messages fr
18
18
  @client = client
19
19
  @opts = opts
20
20
  @delivery_tag = nil
21
+ @subscription = nil
21
22
 
22
23
  # Queues without a given name are named by the server and are generally
23
24
  # bound to the process that created them.
@@ -39,7 +40,8 @@ Queues must be attached to at least one exchange in order to receive messages fr
39
40
  )
40
41
 
41
42
  method = client.next_method
42
- raise Bunny::ProtocolError, "Error declaring queue #{name}" unless method.is_a?(Qrack::Protocol::Queue::DeclareOk)
43
+
44
+ client.check_response(method, Qrack::Protocol::Queue::DeclareOk, "Error declaring queue #{name}")
43
45
 
44
46
  @name = method.queue
45
47
  client.queues[@name] = self
@@ -63,8 +65,12 @@ ask to confirm a single message or a set of messages up to and including a speci
63
65
  =end
64
66
 
65
67
  def ack(opts={})
66
- # If delivery tag is nil then set it to 1 to prevent errors
67
- self.delivery_tag = 1 if self.delivery_tag.nil?
68
+ # Set delivery tag
69
+ if delivery_tag.nil? and opts[:delivery_tag].nil?
70
+ raise Bunny::AcknowledgementError, "No delivery tag received"
71
+ else
72
+ self.delivery_tag = opts[:delivery_tag] if delivery_tag.nil?
73
+ end
68
74
 
69
75
  client.send_frame(
70
76
  Qrack::Protocol::Basic::Ack.new({:delivery_tag => delivery_tag, :multiple => false}.merge(opts))
@@ -104,10 +110,11 @@ bound to the direct exchange '' by default. If error occurs, a _Bunny_::_Protoco
104
110
  :routing_key => opts.delete(:key),
105
111
  :nowait => false }.merge(opts))
106
112
  )
113
+
114
+ method = client.next_method
107
115
 
108
- raise Bunny::ProtocolError,
109
- "Error binding queue #{name}" unless
110
- client.next_method.is_a?(Qrack::Protocol::Queue::BindOk)
116
+ client.check_response(method, Qrack::Protocol::Queue::BindOk,
117
+ "Error binding queue: #{name} to exchange: #{exchange}")
111
118
 
112
119
  # return message
113
120
  :bind_ok
@@ -144,10 +151,10 @@ from queues if successful. If an error occurs raises _Bunny_::_ProtocolError_.
144
151
  client.send_frame(
145
152
  Qrack::Protocol::Queue::Delete.new({ :queue => name, :nowait => false }.merge(opts))
146
153
  )
154
+
155
+ method = client.next_method
147
156
 
148
- raise Bunny::ProtocolError,
149
- "Error deleting queue #{name}" unless
150
- client.next_method.is_a?(Qrack::Protocol::Queue::DeleteOk)
157
+ client.check_response(method, Qrack::Protocol::Queue::DeleteOk, "Error deleting queue #{name}")
151
158
 
152
159
  client.queues.delete(name)
153
160
 
@@ -162,26 +169,29 @@ from queues if successful. If an error occurs raises _Bunny_::_ProtocolError_.
162
169
  Gets a message from a queue in a synchronous way. If error occurs, raises _Bunny_::_ProtocolError_.
163
170
 
164
171
  ==== OPTIONS:
165
-
166
- * <tt>:header => true or false (_default_)</tt> - If set to _true_,
167
- hash <tt>{:header, :delivery_details, :payload}</tt> is returned.
168
- * <tt>:no_ack => true (_default_) or false</tt> - If set to _true_, the server does not expect an
169
- acknowledgement message from the client. If set to _false_, the server expects an acknowledgement
172
+
173
+ * <tt>:ack => false (_default_) or true</tt> - If set to _false_, the server does not expect an
174
+ acknowledgement message from the client. If set to _true_, the server expects an acknowledgement
170
175
  message from the client and will re-queue the message if it does not receive one within a time specified
171
176
  by the server.
172
177
 
173
178
  ==== RETURNS:
174
179
 
175
- If <tt>:header => true</tt> returns hash <tt>{:header, :delivery_details, :payload}</tt>. <tt>:delivery_details</tt> is
176
- a hash <tt>{:delivery_tag, :redelivered, :exchange, :routing_key, :message_count}</tt>. If
177
- <tt>:header => false</tt> only the message payload is returned.
180
+ Hash <tt>{:header, :payload, :delivery_details}</tt>. <tt>:delivery_details</tt> is
181
+ a hash <tt>{:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}</tt>.
182
+
183
+ If the queue is empty the returned hash will contain the values -
184
+
185
+ :header => nil
186
+ :payload => :queue_empty
187
+ :delivery_details => nil
188
+
189
+ N.B. If a block is provided then the hash will be passed into the block and the return value
190
+ will be nil.
178
191
 
179
192
  =end
180
193
 
181
- def pop(opts = {})
182
-
183
- # do we want the message header?
184
- hdr = opts.delete(:header)
194
+ def pop(opts = {}, &blk)
185
195
 
186
196
  # do we want to have to provide an acknowledgement?
187
197
  ack = opts.delete(:ack)
@@ -196,25 +206,32 @@ a hash <tt>{:delivery_tag, :redelivered, :exchange, :routing_key, :message_count
196
206
  method = client.next_method
197
207
 
198
208
  if method.is_a?(Qrack::Protocol::Basic::GetEmpty) then
199
- return :queue_empty
209
+ queue_empty = true
200
210
  elsif !method.is_a?(Qrack::Protocol::Basic::GetOk)
201
211
  raise Bunny::ProtocolError, "Error getting message from queue #{name}"
202
212
  end
203
213
 
204
- # get delivery tag to use for acknowledge
205
- self.delivery_tag = method.delivery_tag if ack
214
+ if !queue_empty
215
+ # get delivery tag to use for acknowledge
216
+ self.delivery_tag = method.delivery_tag if ack
206
217
 
207
- header = client.next_payload
218
+ header = client.next_payload
208
219
 
209
- # If maximum frame size is smaller than message payload body then message
210
- # will have a message header and several message bodies
211
- msg = ''
212
- while msg.length < header.size
213
- msg += client.next_payload
220
+ # If maximum frame size is smaller than message payload body then message
221
+ # will have a message header and several message bodies
222
+ msg = ''
223
+ while msg.length < header.size
224
+ msg += client.next_payload
225
+ end
226
+
227
+ msg_hash = {:header => header, :payload => msg, :delivery_details => method.arguments}
228
+
229
+ else
230
+ msg_hash = {:header => nil, :payload => :queue_empty, :delivery_details => nil}
214
231
  end
215
-
216
- # Return message with additional info if requested
217
- hdr ? {:header => header, :payload => msg, :delivery_details => method.arguments} : msg
232
+
233
+ # Pass message hash to block or return message hash
234
+ blk ? blk.call(msg_hash) : msg_hash
218
235
 
219
236
  end
220
237
 
@@ -242,8 +259,10 @@ without any formal "undo" mechanism. If an error occurs raises _Bunny_::_Protoco
242
259
  client.send_frame(
243
260
  Qrack::Protocol::Queue::Purge.new({ :queue => name, :nowait => false }.merge(opts))
244
261
  )
262
+
263
+ method = client.next_method
245
264
 
246
- raise Bunny::ProtocolError, "Error purging queue #{name}" unless client.next_method.is_a?(Qrack::Protocol::Queue::PurgeOk)
265
+ client.check_response(method, Qrack::Protocol::Queue::PurgeOk, "Error purging queue #{name}")
247
266
 
248
267
  # return confirmation
249
268
  :purge_ok
@@ -266,99 +285,14 @@ Returns hash {:message_count, :consumer_count}.
266
285
  {:message_count => method.message_count, :consumer_count => method.consumer_count}
267
286
  end
268
287
 
269
- =begin rdoc
270
-
271
- === DESCRIPTION:
272
-
273
- Asks the server to start a "consumer", which is a transient request for messages from a specific
274
- queue. Consumers last as long as the channel they were created on, or until the client cancels them
275
- with an _unsubscribe_. Every time a message reaches the queue it is passed to the _blk_ for
276
- processing. If error occurs, _Bunny_::_ProtocolError_ is raised.
277
-
278
- ==== OPTIONS:
279
- * <tt>:header => true or false (_default_)</tt> - If set to _true_, hash is delivered for each message
280
- <tt>{:header, :delivery_details, :payload}</tt>.
281
- * <tt>:consumer_tag => '_tag_'</tt> - Specifies the identifier for the consumer. The consumer tag is
282
- local to a connection, so two clients can use the same consumer tags. If this field is empty the
283
- queue name is used.
284
- * <tt>:no_ack=> true (_default_) or false</tt> - If set to _true_, the server does not expect an
285
- acknowledgement message from the client. If set to _false_, the server expects an acknowledgement
286
- message from the client and will re-queue the message if it does not receive one within a time specified
287
- by the server.
288
- * <tt>:exclusive => true or false (_default_)</tt> - Request exclusive consumer access, meaning
289
- only this consumer can access the queue.
290
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
291
- * <tt>:timeout => number of seconds - The subscribe loop will continue to wait for
292
- messages until terminated (Ctrl-C or kill command) or this timeout interval is reached.
293
- * <tt>:message_max => max number messages to process</tt> - When the required number of messages
294
- is processed subscribe loop is exited.
295
-
296
- ==== RETURNS:
297
-
298
- If <tt>:header => true</tt> returns hash <tt>{:header, :delivery_details, :payload}</tt> for each message.
299
- <tt>:delivery_details</tt> is a hash <tt>{:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}</tt>.
300
- If <tt>:header => false</tt> only message payload is returned.
301
- If <tt>:timeout => > 0</tt> is reached Qrack::ClientTimeout is raised
302
-
303
- =end
304
288
 
305
- def subscribe(opts = {}, &blk)
306
- # Get maximum amount of messages to process
307
- message_max = opts[:message_max] || nil
308
- return if message_max == 0
309
-
310
- # If a consumer tag is not passed in the server will generate one
311
- consumer_tag = opts[:consumer_tag] || nil
312
-
313
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
314
- # response from the server causing an error.
315
- opts.delete(:nowait)
316
-
317
- # do we want the message header?
318
- hdr = opts.delete(:header)
319
-
320
- # do we want to have to provide an acknowledgement?
321
- ack = opts.delete(:ack)
322
-
323
- client.send_frame(
324
- Qrack::Protocol::Basic::Consume.new({ :queue => name,
325
- :consumer_tag => consumer_tag,
326
- :no_ack => !ack,
327
- :nowait => false }.merge(opts))
328
- )
329
-
330
- raise Bunny::ProtocolError,
331
- "Error subscribing to queue #{name}" unless
332
- client.next_method.is_a?(Qrack::Protocol::Basic::ConsumeOk)
333
-
334
- # Initialize message counter
335
- counter = 0
336
-
337
- loop do
338
- method = client.next_method(:timeout => opts[:timeout])
339
-
340
- # get delivery tag to use for acknowledge
341
- self.delivery_tag = method.delivery_tag if ack
342
-
343
- header = client.next_payload
344
-
345
- # If maximum frame size is smaller than message payload body then message
346
- # will have a message header and several message bodies
347
- msg = ''
348
- while msg.length < header.size
349
- msg += client.next_payload
350
- end
351
-
352
- # pass the message and related info, if requested, to the block for processing
353
- blk.call(hdr ? {:header => header, :payload => msg, :delivery_details => method.arguments} : msg)
354
-
355
- # Increment message counter
356
- counter += 1
357
-
358
- # Exit loop if message_max condition met
359
- break if !message_max.nil? and counter == message_max
360
- end
289
+ def subscribe(opts = {}, &blk)
290
+ # Create subscription
291
+ s = Bunny::Subscription.new(client, self, opts)
292
+ s.start(&blk)
361
293
 
294
+ # Reset when subscription finished
295
+ @subscription = nil
362
296
  end
363
297
 
364
298
  =begin rdoc
@@ -380,20 +314,28 @@ the server will not send any more messages for that consumer.
380
314
  =end
381
315
 
382
316
  def unsubscribe(opts = {})
383
- consumer_tag = opts[:consumer_tag] || name
317
+ # Default consumer_tag from subscription if not passed in
318
+ consumer_tag = subscription ? subscription.consumer_tag : opts[:consumer_tag]
384
319
 
385
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
386
- # response from the server causing an error
387
- opts.delete(:nowait)
320
+ # Must have consumer tag to tell server what to unsubscribe
321
+ raise Bunny::UnsubscribeError,
322
+ "No consumer tag received" if !consumer_tag
388
323
 
389
- client.send_frame( Qrack::Protocol::Basic::Cancel.new({ :consumer_tag => consumer_tag }.merge(opts)))
324
+ # Cancel consumer
325
+ client.send_frame( Qrack::Protocol::Basic::Cancel.new(:consumer_tag => consumer_tag,
326
+ :nowait => false))
327
+
328
+ method = client.next_method
329
+
330
+ client.check_response(method, Qrack::Protocol::Basic::CancelOk,
331
+ "Error unsubscribing from queue #{name}")
390
332
 
391
- raise Bunny::ProtocolError,
392
- "Error unsubscribing from queue #{name}" unless
393
- client.next_method.is_a?(Qrack::Protocol::Basic::CancelOk)
333
+ # Reset subscription
334
+ @subscription = nil
394
335
 
395
- # return confirmation
336
+ # Return confirmation
396
337
  :unsubscribe_ok
338
+
397
339
  end
398
340
 
399
341
  =begin rdoc
@@ -428,9 +370,9 @@ Removes a queue binding from an exchange. If error occurs, a _Bunny_::_ProtocolE
428
370
  )
429
371
  )
430
372
 
431
- raise Bunny::ProtocolError,
432
- "Error unbinding queue #{name}" unless
433
- client.next_method.is_a?(Qrack::Protocol::Queue::UnbindOk)
373
+ method = client.next_method
374
+
375
+ client.check_response(method, Qrack::Protocol::Queue::UnbindOk, "Error unbinding queue #{name}")
434
376
 
435
377
  # return message
436
378
  :unbind_ok
@@ -40,7 +40,8 @@ Queues must be attached to at least one exchange in order to receive messages fr
40
40
  )
41
41
 
42
42
  method = client.next_method
43
- raise Bunny::ProtocolError, "Error declaring queue #{name}" unless method.is_a?(Qrack::Protocol09::Queue::DeclareOk)
43
+
44
+ client.check_response(method, Qrack::Protocol09::Queue::DeclareOk, "Error declaring queue #{name}")
44
45
 
45
46
  @name = method.queue
46
47
  client.queues[@name] = self
@@ -64,8 +65,12 @@ ask to confirm a single message or a set of messages up to and including a speci
64
65
  =end
65
66
 
66
67
  def ack(opts={})
67
- # If delivery tag is nil then set it to 1 to prevent errors
68
- self.delivery_tag = 1 if self.delivery_tag.nil?
68
+ # Set delivery tag
69
+ if delivery_tag.nil? and opts[:delivery_tag].nil?
70
+ raise Bunny::AcknowledgementError, "No delivery tag received"
71
+ else
72
+ self.delivery_tag = opts[:delivery_tag] if delivery_tag.nil?
73
+ end
69
74
 
70
75
  client.send_frame(
71
76
  Qrack::Protocol09::Basic::Ack.new({:delivery_tag => delivery_tag, :multiple => false}.merge(opts))
@@ -107,9 +112,10 @@ bound to the direct exchange '' by default. If error occurs, a _Bunny_::_Protoco
107
112
  :reserved_1 => 0 }.merge(opts))
108
113
  )
109
114
 
110
- raise Bunny::ProtocolError,
111
- "Error binding queue #{name}" unless
112
- client.next_method.is_a?(Qrack::Protocol09::Queue::BindOk)
115
+ method = client.next_method
116
+
117
+ client.check_response(method, Qrack::Protocol09::Queue::BindOk,
118
+ "Error binding queue: #{name} to exchange: #{exchange}")
113
119
 
114
120
  # return message
115
121
  :bind_ok
@@ -147,9 +153,9 @@ from queues if successful. If an error occurs raises _Bunny_::_ProtocolError_.
147
153
  Qrack::Protocol09::Queue::Delete.new({ :queue => name, :nowait => false, :reserved_1 => 0 }.merge(opts))
148
154
  )
149
155
 
150
- raise Bunny::ProtocolError,
151
- "Error deleting queue #{name}" unless
152
- client.next_method.is_a?(Qrack::Protocol09::Queue::DeleteOk)
156
+ method = client.next_method
157
+
158
+ client.check_response(method, Qrack::Protocol09::Queue::DeleteOk, "Error deleting queue #{name}")
153
159
 
154
160
  client.queues.delete(name)
155
161
 
@@ -164,26 +170,29 @@ from queues if successful. If an error occurs raises _Bunny_::_ProtocolError_.
164
170
  Gets a message from a queue in a synchronous way. If error occurs, raises _Bunny_::_ProtocolError_.
165
171
 
166
172
  ==== OPTIONS:
167
-
168
- * <tt>:header => true or false (_default_)</tt> - If set to _true_,
169
- hash <tt>{:header, :delivery_details, :payload}</tt> is returned.
170
- * <tt>:no_ack => true (_default_) or false</tt> - If set to _true_, the server does not expect an
171
- acknowledgement message from the client. If set to _false_, the server expects an acknowledgement
173
+
174
+ * <tt>:ack => false (_default_) or true</tt> - If set to _false_, the server does not expect an
175
+ acknowledgement message from the client. If set to _true_, the server expects an acknowledgement
172
176
  message from the client and will re-queue the message if it does not receive one within a time specified
173
177
  by the server.
174
178
 
175
179
  ==== RETURNS:
176
180
 
177
- If <tt>:header => true</tt> returns hash <tt>{:header, :delivery_details, :payload}</tt>. <tt>:delivery_details</tt> is
178
- a hash <tt>{:delivery_tag, :redelivered, :exchange, :routing_key, :message_count}</tt>. If
179
- <tt>:header => false</tt> only the message payload is returned.
181
+ Hash <tt>{:header, :payload, :delivery_details}</tt>. <tt>:delivery_details</tt> is
182
+ a hash <tt>{:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}</tt>.
183
+
184
+ If the queue is empty the returned hash will contain the values -
185
+
186
+ :header => nil
187
+ :payload => :queue_empty
188
+ :delivery_details => nil
189
+
190
+ N.B. If a block is provided then the hash will be passed into the block and the return value
191
+ will be nil.
180
192
 
181
193
  =end
182
194
 
183
- def pop(opts = {})
184
-
185
- # do we want the message header?
186
- hdr = opts.delete(:header)
195
+ def pop(opts = {}, &blk)
187
196
 
188
197
  # do we want to have to provide an acknowledgement?
189
198
  ack = opts.delete(:ack)
@@ -199,26 +208,33 @@ a hash <tt>{:delivery_tag, :redelivered, :exchange, :routing_key, :message_count
199
208
  method = client.next_method
200
209
 
201
210
  if method.is_a?(Qrack::Protocol09::Basic::GetEmpty) then
202
- return :queue_empty
211
+ queue_empty = true
203
212
  elsif !method.is_a?(Qrack::Protocol09::Basic::GetOk)
204
213
  raise Bunny::ProtocolError, "Error getting message from queue #{name}"
205
214
  end
206
-
207
- # get delivery tag to use for acknowledge
208
- self.delivery_tag = method.delivery_tag if ack
209
-
210
- header = client.next_payload
211
-
212
- # If maximum frame size is smaller than message payload body then message
213
- # will have a message header and several message bodies
214
- msg = ''
215
- while msg.length < header.size
216
- msg += client.next_payload
215
+
216
+ if !queue_empty
217
+ # get delivery tag to use for acknowledge
218
+ self.delivery_tag = method.delivery_tag if ack
219
+
220
+ header = client.next_payload
221
+
222
+ # If maximum frame size is smaller than message payload body then message
223
+ # will have a message header and several message bodies
224
+ msg = ''
225
+ while msg.length < header.size
226
+ msg += client.next_payload
227
+ end
228
+
229
+ msg_hash = {:header => header, :payload => msg, :delivery_details => method.arguments}
230
+
231
+ else
232
+ msg_hash = {:header => nil, :payload => :queue_empty, :delivery_details => nil}
217
233
  end
218
234
 
219
- # Return message with additional info if requested
220
- hdr ? {:header => header, :payload => msg, :delivery_details => method.arguments} : msg
221
-
235
+ # Pass message hash to block or return message hash
236
+ blk ? blk.call(msg_hash) : msg_hash
237
+
222
238
  end
223
239
 
224
240
  =begin rdoc
@@ -246,7 +262,9 @@ without any formal "undo" mechanism. If an error occurs raises _Bunny_::_Protoco
246
262
  Qrack::Protocol09::Queue::Purge.new({ :queue => name, :nowait => false, :reserved_1 => 0 }.merge(opts))
247
263
  )
248
264
 
249
- raise Bunny::ProtocolError, "Error purging queue #{name}" unless client.next_method.is_a?(Qrack::Protocol09::Queue::PurgeOk)
265
+ method = client.next_method
266
+
267
+ client.check_response(method, Qrack::Protocol09::Queue::PurgeOk, "Error purging queue #{name}")
250
268
 
251
269
  # return confirmation
252
270
  :purge_ok
@@ -269,100 +287,13 @@ Returns hash {:message_count, :consumer_count}.
269
287
  {:message_count => method.message_count, :consumer_count => method.consumer_count}
270
288
  end
271
289
 
272
- =begin rdoc
273
-
274
- === DESCRIPTION:
275
-
276
- Asks the server to start a "consumer", which is a transient request for messages from a specific
277
- queue. Consumers last as long as the channel they were created on, or until the client cancels them
278
- with an _unsubscribe_. Every time a message reaches the queue it is passed to the _blk_ for
279
- processing. If error occurs, _Bunny_::_ProtocolError_ is raised.
280
-
281
- ==== OPTIONS:
282
- * <tt>:header => true or false (_default_)</tt> - If set to _true_, hash is delivered for each message
283
- <tt>{:header, :delivery_details, :payload}</tt>.
284
- * <tt>:consumer_tag => '_tag_'</tt> - Specifies the identifier for the consumer. The consumer tag is
285
- local to a connection, so two clients can use the same consumer tags. If this field is empty the
286
- queue name is used.
287
- * <tt>:no_ack=> true (_default_) or false</tt> - If set to _true_, the server does not expect an
288
- acknowledgement message from the client. If set to _false_, the server expects an acknowledgement
289
- message from the client and will re-queue the message if it does not receive one within a time specified
290
- by the server.
291
- * <tt>:exclusive => true or false (_default_)</tt> - Request exclusive consumer access, meaning
292
- only this consumer can access the queue.
293
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
294
- * <tt>:timeout => number of seconds - The subscribe loop will continue to wait for
295
- messages until terminated (Ctrl-C or kill command) or this timeout interval is reached.
296
- * <tt>:message_max => max number messages to process</tt> - When the required number of messages
297
- is processed subscribe loop is exited.
298
-
299
- ==== RETURNS:
300
-
301
- If <tt>:header => true</tt> returns hash <tt>{:header, :delivery_details, :payload}</tt> for each message.
302
- <tt>:delivery_details</tt> is a hash <tt>{:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}</tt>.
303
- If <tt>:header => false</tt> only message payload is returned.
304
- If <tt>:timeout => > 0</tt> is reached Qrack::ClientTimeout is raised
305
-
306
- =end
307
-
308
290
  def subscribe(opts = {}, &blk)
309
- # Get maximum amount of messages to process
310
- message_max = opts[:message_max] || nil
311
- return if message_max == 0
312
-
313
- # If a consumer tag is not passed in the server will generate one
314
- consumer_tag = opts[:consumer_tag] || nil
315
-
316
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
317
- # response from the server causing an error.
318
- opts.delete(:nowait)
319
-
320
- # do we want the message header?
321
- hdr = opts.delete(:header)
322
-
323
- # do we want to have to provide an acknowledgement?
324
- ack = opts.delete(:ack)
325
-
326
- client.send_frame(
327
- Qrack::Protocol09::Basic::Consume.new({ :reserved_1 => 0,
328
- :queue => name,
329
- :consumer_tag => consumer_tag,
330
- :no_ack => !ack,
331
- :nowait => false }.merge(opts))
332
- )
333
-
334
- raise Bunny::ProtocolError,
335
- "Error subscribing to queue #{name}" unless
336
- client.next_method.is_a?(Qrack::Protocol09::Basic::ConsumeOk)
337
-
338
- # Initialize message counter
339
- counter = 0
340
-
341
- loop do
342
- method = client.next_method(:timeout => opts[:timeout])
343
-
344
- # get delivery tag to use for acknowledge
345
- self.delivery_tag = method.delivery_tag if ack
346
-
347
- header = client.next_payload
348
-
349
- # If maximum frame size is smaller than message payload body then message
350
- # will have a message header and several message bodies
351
- msg = ''
352
- while msg.length < header.size
353
- msg += client.next_payload
354
- end
355
-
356
- # pass the message and related info, if requested, to the block for processing
357
- blk.call(hdr ? {:header => header, :payload => msg, :delivery_details => method.arguments} : msg)
358
-
359
- # Increment message counter
360
- counter += 1
361
-
362
- # Exit loop if message_max condition met
363
- break if !message_max.nil? and counter == message_max
364
- end
291
+ # Create subscription
292
+ s = Bunny::Subscription09.new(client, self, opts)
293
+ s.start(&blk)
365
294
 
295
+ # Reset when subscription finished
296
+ @subscription = nil
366
297
  end
367
298
 
368
299
  =begin rdoc
@@ -398,9 +329,9 @@ Removes a queue binding from an exchange. If error occurs, a _Bunny_::_ProtocolE
398
329
  )
399
330
  )
400
331
 
401
- raise Bunny::ProtocolError,
402
- "Error unbinding queue #{name}" unless
403
- client.next_method.is_a?(Qrack::Protocol09::Queue::UnbindOk)
332
+ method = client.next_method
333
+
334
+ client.check_response(method, Qrack::Protocol09::Queue::UnbindOk, "Error unbinding queue #{name}")
404
335
 
405
336
  # return message
406
337
  :unbind_ok
@@ -425,19 +356,26 @@ the server will not send any more messages for that consumer.
425
356
  =end
426
357
 
427
358
  def unsubscribe(opts = {})
428
- consumer_tag = opts[:consumer_tag] || name
359
+ # Default consumer_tag from subscription if not passed in
360
+ consumer_tag = subscription ? subscription.consumer_tag : opts[:consumer_tag]
429
361
 
430
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
431
- # response from the server causing an error
432
- opts.delete(:nowait)
362
+ # Must have consumer tag to tell server what to unsubscribe
363
+ raise Bunny::UnsubscribeError,
364
+ "No consumer tag received" if !consumer_tag
433
365
 
434
- client.send_frame( Qrack::Protocol09::Basic::Cancel.new({ :consumer_tag => consumer_tag }.merge(opts)))
366
+ # Cancel consumer
367
+ client.send_frame( Qrack::Protocol09::Basic::Cancel.new(:consumer_tag => consumer_tag,
368
+ :nowait => false))
435
369
 
436
- raise Bunny::ProtocolError,
437
- "Error unsubscribing from queue #{name}" unless
438
- client.next_method.is_a?(Qrack::Protocol09::Basic::CancelOk)
370
+ method = client.next_method
371
+
372
+ client.check_response(method, Qrack::Protocol09::Basic::CancelOk,
373
+ "Error unsubscribing from queue #{name}")
374
+
375
+ # Reset subscription
376
+ @subscription = nil
439
377
 
440
- # return confirmation
378
+ # Return confirmation
441
379
  :unsubscribe_ok
442
380
 
443
381
  end