Skip to content

Commit 52f494c

Browse files
authored
Merge pull request #1442 from rabbitmq/rabbitmq-dotnet-client-1434-main
Port #1434 to `main`
2 parents a3d46e9 + 77ed226 commit 52f494c

File tree

5 files changed

+66
-8
lines changed

5 files changed

+66
-8
lines changed

projects/RabbitMQ.Client/client/api/ShutdownEventArgs.cs

+26-2
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ namespace RabbitMQ.Client
4141
/// </remarks>
4242
public class ShutdownEventArgs : EventArgs
4343
{
44+
private readonly Exception _exception;
45+
4446
/// <summary>
4547
/// Construct a <see cref="ShutdownEventArgs"/> with the given parameters and
4648
/// 0 for <see cref="ClassId"/> and <see cref="MethodId"/>.
4749
/// </summary>
48-
public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null)
50+
public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText,
51+
object cause = null)
4952
: this(initiator, replyCode, replyText, 0, 0, cause)
5053
{
5154
}
@@ -64,6 +67,26 @@ public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string r
6467
Cause = cause;
6568
}
6669

70+
/// <summary>
71+
/// Construct a <see cref="ShutdownEventArgs"/> with the given parameters.
72+
/// </summary>
73+
public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, Exception exception)
74+
: this(initiator, replyCode, replyText, 0, 0)
75+
{
76+
_exception = exception ?? throw new ArgumentNullException(nameof(exception));
77+
}
78+
79+
/// <summary>
80+
/// Exception causing the shutdown, or null if none.
81+
/// </summary>
82+
public Exception Exception
83+
{
84+
get
85+
{
86+
return _exception;
87+
}
88+
}
89+
6790
/// <summary>
6891
/// Object causing the shutdown, or null if none.
6992
/// </summary>
@@ -104,7 +127,8 @@ public override string ToString()
104127
+ (ReplyText != null ? $", text='{ReplyText}'" : string.Empty)
105128
+ $", classId={ClassId}"
106129
+ $", methodId={MethodId}"
107-
+ (Cause != null ? $", cause={Cause}" : string.Empty);
130+
+ (Cause != null ? $", cause={Cause}" : string.Empty)
131+
+ (_exception != null ? $", exception={_exception}" : string.Empty);
108132
}
109133
}
110134
}

projects/RabbitMQ.Client/client/impl/ChannelBase.cs

+11
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ internal abstract class ChannelBase : IChannel, IRecoverable
5050
///<summary>Only used to kick-start a connection open
5151
///sequence. See <see cref="Connection.OpenAsync"/> </summary>
5252
internal TaskCompletionSource<ConnectionStartDetails> m_connectionStartCell;
53+
private Exception m_connectionStartException = null;
5354

5455
// AMQP only allows one RPC operation to be active at a time.
5556
protected readonly SemaphoreSlim _rpcSemaphore = new SemaphoreSlim(1, 1);
@@ -171,6 +172,16 @@ public IBasicConsumer DefaultConsumer
171172

172173
public ISession Session { get; private set; }
173174

175+
public Exception ConnectionStartException => m_connectionStartException;
176+
177+
public void MaybeSetConnectionStartException(Exception ex)
178+
{
179+
if (m_connectionStartCell != null)
180+
{
181+
m_connectionStartException = ex;
182+
}
183+
}
184+
174185
protected void TakeOver(ChannelBase other)
175186
{
176187
_basicAcksWrapper.Takeover(other._basicAcksWrapper);

projects/RabbitMQ.Client/client/impl/Connection.Commands.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ await _frameHandler.SendProtocolHeaderAsync()
8181

8282
if (connectionStart is null)
8383
{
84-
throw new IOException("connection.start was never received, likely due to a network timeout");
84+
const string msg = "connection.start was never received, likely due to a network timeout";
85+
throw new IOException(msg, _channel0.ConnectionStartException);
8586
}
8687

8788
ServerProperties = connectionStart.m_serverProperties;

projects/RabbitMQ.Client/client/impl/Connection.Receive.cs

+25-5
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,34 @@ await ReceiveLoop()
5353
catch (EndOfStreamException eose)
5454
{
5555
// Possible heartbeat exception
56-
HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, 0, "End of stream", eose));
56+
var ea = new ShutdownEventArgs(ShutdownInitiator.Library,
57+
0, "End of stream",
58+
exception: eose);
59+
HandleMainLoopException(ea);
5760
}
5861
catch (HardProtocolException hpe)
5962
{
6063
await HardProtocolExceptionHandler(hpe)
6164
.ConfigureAwait(false);
6265
}
66+
catch (FileLoadException fileLoadException)
67+
{
68+
/*
69+
* https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/1434
70+
* Ensure that these exceptions eventually make it to application code
71+
*/
72+
var ea = new ShutdownEventArgs(ShutdownInitiator.Library,
73+
Constants.InternalError, fileLoadException.Message,
74+
exception: fileLoadException);
75+
HandleMainLoopException(ea);
76+
}
6377
catch (Exception ex)
6478
{
65-
HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library, Constants.InternalError, "Unexpected Exception", ex));
79+
var ea = new ShutdownEventArgs(ShutdownInitiator.Library,
80+
Constants.InternalError,
81+
$"Unexpected Exception: {ex.Message}",
82+
exception: ex);
83+
HandleMainLoopException(ea);
6684
}
6785

6886
FinishClose();
@@ -146,15 +164,17 @@ private void HandleMainLoopException(ShutdownEventArgs reason)
146164
{
147165
if (!SetCloseReason(reason))
148166
{
149-
// TODO reason.Cause could be an Exception, should we use that?
150-
LogCloseError("Unexpected Main Loop Exception while closing: " + reason, new Exception(reason.ToString()));
167+
LogCloseError($"Unexpected Main Loop Exception while closing: {reason}", reason.Exception);
151168
return;
152169
}
153170

171+
_channel0.MaybeSetConnectionStartException(reason.Exception);
172+
154173
OnShutdown(reason);
155-
LogCloseError($"Unexpected connection closure: {reason}", new Exception(reason.ToString()));
174+
LogCloseError($"Unexpected connection closure: {reason}", reason.Exception);
156175
}
157176

177+
// TODO rename Async, add cancellation token?
158178
private async Task HardProtocolExceptionHandler(HardProtocolException hpe)
159179
{
160180
if (SetCloseReason(hpe.ShutdownReason))

projects/Test/Unit/APIApproval.Approve.verified.txt

+2
Original file line numberDiff line numberDiff line change
@@ -787,10 +787,12 @@ namespace RabbitMQ.Client
787787
}
788788
public class ShutdownEventArgs : System.EventArgs
789789
{
790+
public ShutdownEventArgs(RabbitMQ.Client.ShutdownInitiator initiator, ushort replyCode, string replyText, System.Exception exception) { }
790791
public ShutdownEventArgs(RabbitMQ.Client.ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null) { }
791792
public ShutdownEventArgs(RabbitMQ.Client.ShutdownInitiator initiator, ushort replyCode, string replyText, ushort classId, ushort methodId, object cause = null) { }
792793
public object Cause { get; }
793794
public ushort ClassId { get; }
795+
public System.Exception Exception { get; }
794796
public RabbitMQ.Client.ShutdownInitiator Initiator { get; }
795797
public ushort MethodId { get; }
796798
public ushort ReplyCode { get; }

0 commit comments

Comments
 (0)