30
30
//---------------------------------------------------------------------------
31
31
32
32
using System ;
33
- using System . Buffers . Binary ;
34
33
using System . Collections . Generic ;
35
34
using System . Diagnostics ;
36
35
using System . Text ;
37
36
using System . Threading ;
38
37
using System . Threading . Tasks ;
39
38
using RabbitMQ . Client ;
39
+ using RabbitMQ . Client . Exceptions ;
40
40
41
41
const ushort MAX_OUTSTANDING_CONFIRMS = 256 ;
42
42
@@ -124,11 +124,43 @@ async Task PublishMessagesInBatchAsync()
124
124
var sw = new Stopwatch ( ) ;
125
125
sw . Start ( ) ;
126
126
127
+ channel . BasicReturnAsync += ( sender , ea ) =>
128
+ {
129
+ string sequenceNumber = string . Empty ;
130
+
131
+ IReadOnlyBasicProperties props = ea . BasicProperties ;
132
+ if ( props . Headers is not null )
133
+ {
134
+ object ? maybeSeqNum = props . Headers [ Constants . PublishSequenceNumberHeader ] ;
135
+ if ( maybeSeqNum is not null )
136
+ {
137
+ switch ( maybeSeqNum )
138
+ {
139
+ case byte [ ] seqNumBytes :
140
+ sequenceNumber = Encoding . ASCII . GetString ( seqNumBytes ) ;
141
+ break ;
142
+ case string seqNumStr :
143
+ sequenceNumber = ( string ) seqNumStr ;
144
+ break ;
145
+ }
146
+ }
147
+ }
148
+
149
+ Console . WriteLine ( $ "{ DateTime . Now } [WARNING] message sequence number { sequenceNumber } has been basic.return-ed") ;
150
+
151
+ return Task . CompletedTask ;
152
+ } ;
153
+
127
154
var publishTasks = new List < ValueTask > ( ) ;
128
155
for ( int i = 0 ; i < MESSAGE_COUNT ; i ++ )
129
156
{
157
+ string rk = queueName ;
158
+ if ( i % 1000 == 0 )
159
+ {
160
+ rk = Guid . NewGuid ( ) . ToString ( ) ;
161
+ }
130
162
byte [ ] body = Encoding . UTF8 . GetBytes ( i . ToString ( ) ) ;
131
- publishTasks . Add ( channel . BasicPublishAsync ( exchange : string . Empty , routingKey : queueName , body : body , mandatory : true , basicProperties : props ) ) ;
163
+ publishTasks . Add ( channel . BasicPublishAsync ( exchange : string . Empty , routingKey : rk , body : body , mandatory : true , basicProperties : props ) ) ;
132
164
outstandingMessageCount ++ ;
133
165
134
166
if ( outstandingMessageCount == batchSize )
@@ -139,9 +171,13 @@ async Task PublishMessagesInBatchAsync()
139
171
{
140
172
await pt ;
141
173
}
174
+ catch ( PublishException pex )
175
+ {
176
+ Console . Error . WriteLine ( $ "{ DateTime . Now } [ERROR] saw nack or return, pex.IsReturn: '{ pex . IsReturn } ', seq no: '{ pex . PublishSequenceNumber } '") ;
177
+ }
142
178
catch ( Exception ex )
143
179
{
144
- Console . Error . WriteLine ( $ "{ DateTime . Now } [ERROR] saw nack or return , ex: '{ ex } '") ;
180
+ Console . Error . WriteLine ( $ "{ DateTime . Now } [ERROR] saw exception , ex: '{ ex } '") ;
145
181
}
146
182
}
147
183
publishTasks . Clear ( ) ;
@@ -157,9 +193,13 @@ async Task PublishMessagesInBatchAsync()
157
193
{
158
194
await pt ;
159
195
}
196
+ catch ( PublishException pex )
197
+ {
198
+ Console . Error . WriteLine ( $ "{ DateTime . Now } [ERROR] saw nack or return, pex.IsReturn: '{ pex . IsReturn } ', seq no: '{ pex . PublishSequenceNumber } '") ;
199
+ }
160
200
catch ( Exception ex )
161
201
{
162
- Console . Error . WriteLine ( $ "{ DateTime . Now } [ERROR] saw nack or return , ex: '{ ex } '") ;
202
+ Console . Error . WriteLine ( $ "{ DateTime . Now } [ERROR] saw exception , ex: '{ ex } '") ;
163
203
}
164
204
}
165
205
publishTasks . Clear ( ) ;
@@ -238,20 +278,29 @@ async Task CleanOutstandingConfirms(ulong deliveryTag, bool multiple)
238
278
239
279
channel . BasicReturnAsync += ( sender , ea ) =>
240
280
{
241
- ulong sequenceNumber = 0 ;
281
+ string sequenceNumber = string . Empty ;
242
282
243
283
IReadOnlyBasicProperties props = ea . BasicProperties ;
244
284
if ( props . Headers is not null )
245
285
{
246
286
object ? maybeSeqNum = props . Headers [ Constants . PublishSequenceNumberHeader ] ;
247
287
if ( maybeSeqNum is not null )
248
288
{
249
- sequenceNumber = BinaryPrimitives . ReadUInt64BigEndian ( ( byte [ ] ) maybeSeqNum ) ;
289
+ switch ( maybeSeqNum )
290
+ {
291
+ case byte [ ] seqNumBytes :
292
+ sequenceNumber = Encoding . ASCII . GetString ( seqNumBytes ) ;
293
+ break ;
294
+ case string seqNumStr :
295
+ sequenceNumber = ( string ) seqNumStr ;
296
+ break ;
297
+ }
250
298
}
251
299
}
252
300
253
- Console . WriteLine ( $ "{ DateTime . Now } [WARNING] message sequence number { sequenceNumber } has been basic.return-ed") ;
254
- return CleanOutstandingConfirms ( sequenceNumber , false ) ;
301
+ Console . WriteLine ( $ "{ DateTime . Now } [INFO] message sequence number '{ sequenceNumber } ' has been basic.return-ed") ;
302
+ ulong seq = ulong . Parse ( sequenceNumber ) ;
303
+ return CleanOutstandingConfirms ( seq , false ) ;
255
304
} ;
256
305
257
306
channel . BasicAcksAsync += ( sender , ea ) => CleanOutstandingConfirms ( ea . DeliveryTag , ea . Multiple ) ;
@@ -290,13 +339,21 @@ async Task CleanOutstandingConfirms(ulong deliveryTag, bool multiple)
290
339
// This will cause a basic.return, for fun
291
340
rk = Guid . NewGuid ( ) . ToString ( ) ;
292
341
}
342
+
343
+ var msgProps = new BasicProperties
344
+ {
345
+ Persistent = true ,
346
+ Headers = new Dictionary < string , object ? > ( )
347
+ } ;
348
+
349
+ msgProps . Headers . Add ( Constants . PublishSequenceNumberHeader , nextPublishSeqNo . ToString ( ) ) ;
350
+
293
351
( ulong , ValueTask ) data =
294
- ( nextPublishSeqNo , channel . BasicPublishAsync ( exchange : string . Empty , routingKey : rk , body : body , mandatory : true , basicProperties : props ) ) ;
352
+ ( nextPublishSeqNo , channel . BasicPublishAsync ( exchange : string . Empty , routingKey : rk , body : body , mandatory : true , basicProperties : msgProps ) ) ;
295
353
publishTasks . Add ( data ) ;
296
354
}
297
355
298
356
using var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 10 ) ) ;
299
- // await Task.WhenAll(publishTasks).WaitAsync(cts.Token);
300
357
foreach ( ( ulong SeqNo , ValueTask PublishTask ) datum in publishTasks )
301
358
{
302
359
try
0 commit comments