@@ -80,6 +80,7 @@ public class Subscription: IEnumerable, IEnumerator, IDisposable {
80
80
protected bool m_noAck ;
81
81
82
82
protected readonly object m_consumerLock = new object ( ) ;
83
+ protected readonly object m_eventLock = new object ( ) ;
83
84
protected volatile QueueingBasicConsumer m_consumer ;
84
85
protected string m_consumerTag ;
85
86
@@ -156,7 +157,11 @@ public void Close()
156
157
}
157
158
158
159
if ( shouldCancelConsumer ) {
159
- m_model . BasicCancel ( m_consumerTag ) ;
160
+ if ( m_model . IsOpen )
161
+ {
162
+ m_model . BasicCancel ( m_consumerTag ) ;
163
+ }
164
+
160
165
m_consumerTag = null ;
161
166
}
162
167
} catch ( OperationInterruptedException ) {
@@ -169,34 +174,73 @@ public void Close()
169
174
///null.</summary>
170
175
public void Ack ( )
171
176
{
172
- if ( m_latestEvent != null ) {
173
- Ack ( m_latestEvent ) ;
174
- }
177
+ Ack ( m_latestEvent ) ;
175
178
}
176
179
177
180
///<summary>If we are not in "noAck" mode, calls
178
- ///IModel.BasicAck with the delivery-tag from the passed in
179
- ///event; otherwise, sends nothing to the server. In both
180
- ///cases, if the passed-in event is the same as LatestEvent
181
- ///(by pointer comparison), sets LatestEvent to
182
- ///null.</summary>
181
+ ///IModel.BasicAck with the delivery-tag from <paramref name="evt"/>;
182
+ ///otherwise, sends nothing to the server. if <paramref name="evt"/> is the same as LatestEvent
183
+ ///by pointer comparison, sets LatestEvent to null.
184
+ ///</summary>
183
185
///<remarks>
184
- /// Make sure that this method is only called with events that
185
- /// originated from this Subscription - other usage will have
186
- /// unpredictable results.
186
+ ///Passing an event that did not originate with this Subscription's
187
+ /// channel, will lead to unpredictable behaviour
187
188
///</remarks>
188
189
public void Ack ( BasicDeliverEventArgs evt )
189
190
{
190
191
if ( evt == null ) {
191
192
return ;
192
193
}
193
194
194
- if ( ! m_noAck ) {
195
+ if ( ! m_noAck && m_model . IsOpen ) {
195
196
m_model . BasicAck ( evt . DeliveryTag , false ) ;
196
197
}
197
198
198
199
if ( evt == m_latestEvent ) {
199
- m_latestEvent = null ;
200
+ MutateLatestEvent ( null ) ;
201
+ }
202
+ }
203
+
204
+ ///<summary>If LatestEvent is non-null, passes it to
205
+ ///Nack(BasicDeliverEventArgs, false, requeue). Causes LatestEvent to become
206
+ ///null.</summary>
207
+ public void Nack ( bool requeue )
208
+ {
209
+ Nack ( m_latestEvent , false , requeue ) ;
210
+ }
211
+
212
+
213
+ ///<summary>If LatestEvent is non-null, passes it to
214
+ ///Nack(BasicDeliverEventArgs, multiple, requeue). Causes LatestEvent to become
215
+ ///null.</summary>
216
+ public void Nack ( bool multiple , bool requeue )
217
+ {
218
+ Nack ( m_latestEvent , multiple , requeue ) ;
219
+ }
220
+
221
+ ///<summary>If we are not in "noAck" mode, calls
222
+ ///IModel.BasicNack with the delivery-tag from <paramref name="evt"/>;
223
+ ///otherwise, sends nothing to the server. if <paramref name="evt"/> is the same as LatestEvent
224
+ ///by pointer comparison, sets LatestEvent to null.
225
+ ///</summary>
226
+ ///<remarks>
227
+ ///Passing an event that did not originate with this Subscription's
228
+ /// channel, will lead to unpredictable behaviour
229
+ ///</remarks>
230
+ public void Nack ( BasicDeliverEventArgs evt ,
231
+ bool multiple ,
232
+ bool requeue )
233
+ {
234
+ if ( evt == null ) {
235
+ return ;
236
+ }
237
+
238
+ if ( ! m_noAck && m_model . IsOpen ) {
239
+ m_model . BasicNack ( evt . DeliveryTag , multiple , requeue ) ;
240
+ }
241
+
242
+ if ( evt == m_latestEvent ) {
243
+ MutateLatestEvent ( null ) ;
200
244
}
201
245
}
202
246
@@ -220,19 +264,19 @@ public void Ack(BasicDeliverEventArgs evt)
220
264
///</remarks>
221
265
public BasicDeliverEventArgs Next ( )
222
266
{
267
+ // Alias the pointer as otherwise it may change out
268
+ // from under us by the operation of Close() from
269
+ // another thread.
270
+ QueueingBasicConsumer consumer = m_consumer ;
223
271
try {
224
- // Alias the pointer as otherwise it may change out
225
- // from under us by the operation of Close() from
226
- // another thread.
227
- QueueingBasicConsumer consumer = m_consumer ;
228
272
if ( consumer == null || m_model . IsClosed ) {
229
- // Closed!
230
- m_latestEvent = null ;
273
+ MutateLatestEvent ( null ) ;
231
274
} else {
232
- m_latestEvent = ( BasicDeliverEventArgs ) consumer . Queue . Dequeue ( ) ;
275
+ BasicDeliverEventArgs bdea = ( BasicDeliverEventArgs ) consumer . Queue . Dequeue ( ) ;
276
+ MutateLatestEvent ( bdea ) ;
233
277
}
234
278
} catch ( EndOfStreamException ) {
235
- m_latestEvent = null ;
279
+ MutateLatestEvent ( null ) ;
236
280
}
237
281
return m_latestEvent ;
238
282
}
@@ -289,8 +333,7 @@ public bool Next(int millisecondsTimeout, out BasicDeliverEventArgs result)
289
333
// another thread.
290
334
QueueingBasicConsumer consumer = m_consumer ;
291
335
if ( consumer == null || m_model . IsClosed ) {
292
- // Closed!
293
- m_latestEvent = null ;
336
+ MutateLatestEvent ( null ) ;
294
337
result = null ;
295
338
return false ;
296
339
} else {
@@ -299,10 +342,10 @@ public bool Next(int millisecondsTimeout, out BasicDeliverEventArgs result)
299
342
result = null ;
300
343
return false ;
301
344
}
302
- m_latestEvent = qValue ;
345
+ MutateLatestEvent ( qValue ) ;
303
346
}
304
347
} catch ( EndOfStreamException ) {
305
- m_latestEvent = null ;
348
+ MutateLatestEvent ( null ) ;
306
349
}
307
350
result = m_latestEvent ;
308
351
return true ;
@@ -369,5 +412,13 @@ void IDisposable.Dispose()
369
412
{
370
413
Close ( ) ;
371
414
}
415
+
416
+ protected void MutateLatestEvent ( BasicDeliverEventArgs value )
417
+ {
418
+ lock ( m_eventLock )
419
+ {
420
+ m_latestEvent = value ;
421
+ }
422
+ }
372
423
}
373
424
}
0 commit comments