Skip to content

Commit 1d5f574

Browse files
authored
Merge pull request #1791 from rabbitmq/rabbitmq-server-13387
Demonstrate handling of `Channel.Close`
2 parents eb64b79 + 00e227a commit 1d5f574

File tree

3 files changed

+170
-1
lines changed

3 files changed

+170
-1
lines changed

projects/RabbitMQ.Client/Impl/Connection.Receive.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ await _session0.HandleFrameAsync(frame, cancellationToken)
181181
// frames for non-zero channels (and any inbound
182182
// commands on channel zero that aren't
183183
// Connection.CloseOk) must be discarded.
184-
if (_closeReason is null)
184+
if (CloseReason is null)
185185
{
186186
// No close reason, not quiescing the
187187
// connection. Handle the frame. (Of course, the

projects/RabbitMQ.Client/Impl/SessionManager.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ public ISession Lookup(int number)
100100
{
101101
lock (_sessionMap)
102102
{
103+
/*
104+
* Note: rabbitmq/rabbitmq-server#13337
105+
* When investigating the above issue, a couple KeyNotFoundExceptions
106+
* were thrown here during test shutdown. No reliable reproducer.
107+
*/
103108
return _sessionMap[number];
104109
}
105110
}

projects/Test/Integration/GH/TestGitHubIssues.cs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
//---------------------------------------------------------------------------
3131

3232
using System;
33+
using System.Collections.Generic;
34+
using System.Text;
3335
using System.Threading;
3436
using System.Threading.Tasks;
3537
using RabbitMQ.Client;
@@ -165,5 +167,167 @@ await Assert.ThrowsAnyAsync<BrokerUnreachableException>(
165167
async () => await _connFactory.CreateConnectionAsync());
166168
Assert.IsAssignableFrom<PossibleAuthenticationFailureException>(ex.InnerException);
167169
}
170+
171+
[Fact]
172+
public async Task SendInvalidPublishMaybeClosesConnection_GH13387()
173+
{
174+
const int messageCount = 200;
175+
176+
_connFactory = new ConnectionFactory();
177+
_conn = await _connFactory.CreateConnectionAsync();
178+
179+
var opts = new CreateChannelOptions(
180+
publisherConfirmationsEnabled: true,
181+
publisherConfirmationTrackingEnabled: true);
182+
_channel = await _conn.CreateChannelAsync(opts);
183+
184+
await _channel.BasicQosAsync(0, 10, false);
185+
186+
string queueName = GenerateQueueName();
187+
QueueDeclareOk q = await _channel.QueueDeclareAsync(queueName);
188+
Assert.Equal(queueName, q.QueueName);
189+
190+
byte[] body = Encoding.ASCII.GetBytes("incoming message");
191+
var publishTasks = new List<ValueTask>();
192+
for (int i = 0; i < messageCount; i++)
193+
{
194+
ValueTask pt = _channel.BasicPublishAsync(
195+
exchange: string.Empty,
196+
routingKey: queueName,
197+
body: body);
198+
publishTasks.Add(pt);
199+
if (i % 20 == 0)
200+
{
201+
foreach (ValueTask t in publishTasks)
202+
{
203+
await t;
204+
}
205+
publishTasks.Clear();
206+
}
207+
}
208+
209+
foreach (ValueTask t in publishTasks)
210+
{
211+
await t;
212+
}
213+
publishTasks.Clear();
214+
215+
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
216+
217+
_conn.CallbackExceptionAsync += (object sender, CallbackExceptionEventArgs args) =>
218+
{
219+
if (IsVerbose)
220+
{
221+
_output.WriteLine("_conn.CallbackExceptionAsync: {0}", args.Exception);
222+
}
223+
tcs.TrySetException(args.Exception);
224+
return Task.CompletedTask;
225+
};
226+
227+
_conn.ConnectionShutdownAsync += (object sender, ShutdownEventArgs args) =>
228+
{
229+
if (args.Exception is not null)
230+
{
231+
if (IsVerbose)
232+
{
233+
_output.WriteLine("_conn.ConnectionShutdownAsync: {0}", args.Exception);
234+
}
235+
tcs.TrySetException(args.Exception);
236+
}
237+
else
238+
{
239+
if (IsVerbose)
240+
{
241+
_output.WriteLine("_conn.ConnectionShutdownAsync");
242+
}
243+
tcs.TrySetResult(false);
244+
}
245+
return Task.CompletedTask;
246+
};
247+
248+
_channel.CallbackExceptionAsync += (object sender, CallbackExceptionEventArgs args) =>
249+
{
250+
if (IsVerbose)
251+
{
252+
_output.WriteLine("_channel.CallbackExceptionAsync: {0}", args.Exception);
253+
}
254+
tcs.TrySetException(args.Exception);
255+
return Task.CompletedTask;
256+
};
257+
258+
_channel.ChannelShutdownAsync += (object sender, ShutdownEventArgs args) =>
259+
{
260+
if (args.Exception is not null)
261+
{
262+
if (IsVerbose)
263+
{
264+
_output.WriteLine("_channel.ChannelShutdownAsync: {0}", args.Exception);
265+
}
266+
tcs.TrySetException(args.Exception);
267+
}
268+
else
269+
{
270+
if (IsVerbose)
271+
{
272+
_output.WriteLine("_channel.ChannelShutdownAsync");
273+
}
274+
tcs.TrySetResult(false);
275+
}
276+
return Task.CompletedTask;
277+
};
278+
279+
var ackExceptions = new List<Exception>();
280+
var publishExceptions = new List<Exception>();
281+
var props = new BasicProperties { Expiration = "-1" };
282+
int receivedCounter = 0;
283+
var consumer = new AsyncEventingBasicConsumer(_channel);
284+
consumer.ReceivedAsync += async (object sender, BasicDeliverEventArgs args) =>
285+
{
286+
var c = (AsyncEventingBasicConsumer)sender;
287+
IChannel ch = c.Channel;
288+
try
289+
{
290+
await ch.BasicAckAsync(args.DeliveryTag, false);
291+
}
292+
catch (Exception ex)
293+
{
294+
ackExceptions.Add(ex);
295+
}
296+
297+
try
298+
{
299+
await ch.BasicPublishAsync(exchange: string.Empty, routingKey: queueName,
300+
mandatory: true, basicProperties: props, body: body);
301+
}
302+
catch (Exception ex)
303+
{
304+
publishExceptions.Add(ex);
305+
}
306+
307+
if (Interlocked.Increment(ref receivedCounter) >= messageCount)
308+
{
309+
tcs.SetResult(true);
310+
}
311+
};
312+
313+
consumer.ShutdownAsync += (object sender, ShutdownEventArgs args) =>
314+
{
315+
if (IsVerbose)
316+
{
317+
_output.WriteLine("consumer.ShutdownAsync");
318+
}
319+
return Task.CompletedTask;
320+
};
321+
322+
await _channel.BasicConsumeAsync(queueName, false, consumer);
323+
324+
await tcs.Task;
325+
326+
if (IsVerbose)
327+
{
328+
_output.WriteLine("saw {0} ackExceptions", ackExceptions.Count);
329+
_output.WriteLine("saw {0} publishExceptions", publishExceptions.Count);
330+
}
331+
}
168332
}
169333
}

0 commit comments

Comments
 (0)