bunny 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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