Skip to content

Commit

Permalink
Merge pull request #1438 from rabbitmq/rabbitmq-dotnet-client-1434
Browse files Browse the repository at this point in the history
Pass exception back up to application code
  • Loading branch information
lukebakken authored Dec 5, 2023
2 parents 3b4b222 + ed7b4e6 commit 4cb93ed
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 21 deletions.
34 changes: 28 additions & 6 deletions projects/RabbitMQ.Client/client/api/ShutdownEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,48 @@ namespace RabbitMQ.Client
/// </remarks>
public class ShutdownEventArgs : EventArgs
{
private readonly Exception _exception;

/// <summary>
/// Construct a <see cref="ShutdownEventArgs"/> with the given parameters and
/// 0 for <see cref="ClassId"/> and <see cref="MethodId"/>.
/// </summary>
public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null)
: this(initiator, replyCode, replyText, 0, 0, cause)
public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null, Exception exception = null)
: this(initiator, replyCode, replyText, 0, 0, cause, exception)
{
}

/// <summary>
/// Construct a <see cref="ShutdownEventArgs"/> with the given parameters.
/// </summary>
public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string replyText,
ushort classId, ushort methodId, object cause = null)
ushort classId, ushort methodId, object cause = null, Exception exception = null)
{
Initiator = initiator;
ReplyCode = replyCode;
ReplyText = replyText;
ClassId = classId;
MethodId = methodId;
Cause = cause;
_exception = exception;
}

/// <summary>
/// Exception causing the shutdown, or null if none.
/// </summary>
public Exception Exception
{
get
{
if (_exception != null)
{
return _exception;
}
else
{
return new Exception(ToString());
}
}
}

/// <summary>
Expand Down Expand Up @@ -98,13 +119,14 @@ public ShutdownEventArgs(ShutdownInitiator initiator, ushort replyCode, string r
/// Override ToString to be useful for debugging.
/// </summary>
public override string ToString()
{
return $"AMQP close-reason, initiated by {Initiator}"
{
return $"AMQP close-reason, initiated by {Initiator}"
+ $", code={ReplyCode}"
+ (ReplyText != null ? $", text='{ReplyText}'" : string.Empty)
+ $", classId={ClassId}"
+ $", methodId={MethodId}"
+ (Cause != null ? $", cause={Cause}" : string.Empty);
+ (Cause != null ? $", cause={Cause}" : string.Empty)
+ (_exception != null ? $", exception={_exception}" : string.Empty);
}
}
}
37 changes: 25 additions & 12 deletions projects/RabbitMQ.Client/client/impl/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,13 +457,14 @@ public void HandleMainLoopException(ShutdownEventArgs reason)
{
if (!SetCloseReason(reason))
{
LogCloseError("Unexpected Main Loop Exception while closing: "
+ reason, new Exception(reason.ToString()));
LogCloseError($"Unexpected Main Loop Exception while closing: {reason}", reason.Exception);
return;
}

_model0.MaybeSetConnectionStartException(reason.Exception);

OnShutdown();
LogCloseError($"Unexpected connection closure: {reason}", new Exception(reason.ToString()));
LogCloseError($"Unexpected connection closure: {reason}", reason.Exception);
}

public bool HardProtocolExceptionHandler(HardProtocolException hpe)
Expand Down Expand Up @@ -540,22 +541,33 @@ public void MainLoop()
catch (EndOfStreamException eose)
{
// Possible heartbeat exception
HandleMainLoopException(new ShutdownEventArgs(
ShutdownInitiator.Library,
0,
"End of stream",
eose));
var ea = new ShutdownEventArgs(ShutdownInitiator.Library,
0, "End of stream",
cause: null, exception: eose);
HandleMainLoopException(ea);
}
catch (HardProtocolException hpe)
{
shutdownCleanly = HardProtocolExceptionHandler(hpe);
}
catch (FileLoadException fileLoadException)
{
/*
* https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/1434
* Ensure that these exceptions eventually make it to application code
*/
var ea = new ShutdownEventArgs(ShutdownInitiator.Library,
Constants.InternalError, fileLoadException.Message,
cause: null, exception: fileLoadException);
HandleMainLoopException(ea);
}
catch (Exception ex)
{
HandleMainLoopException(new ShutdownEventArgs(ShutdownInitiator.Library,
var ea = new ShutdownEventArgs(ShutdownInitiator.Library,
Constants.InternalError,
"Unexpected Exception",
ex));
$"Unexpected Exception: {ex.Message}",
cause: null, exception: ex);
HandleMainLoopException(ea);
}

// If allowed for clean shutdown, run main loop until the
Expand Down Expand Up @@ -1104,7 +1116,8 @@ private void StartAndTune()

if (connectionStart == null)
{
throw new IOException("connection.start was never received, likely due to a network timeout");
const string msg = "connection.start was never received, likely due to a network timeout";
throw new IOException(msg, _model0.ConnectionStartException);
}

ServerProperties = connectionStart.m_serverProperties;
Expand Down
17 changes: 16 additions & 1 deletion projects/RabbitMQ.Client/client/impl/ModelBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ abstract class ModelBase : IFullModel, IRecoverable
{
///<summary>Only used to kick-start a connection open
///sequence. See <see cref="Connection.Open"/> </summary>
public BlockingCell<ConnectionStartDetails> m_connectionStartCell = null;
internal BlockingCell<ConnectionStartDetails> m_connectionStartCell = null;
private Exception m_connectionStartException = null;

internal readonly IBasicProperties _emptyBasicProperties;

private readonly Dictionary<string, IBasicConsumer> _consumers = new Dictionary<string, IBasicConsumer>();
Expand Down Expand Up @@ -174,6 +176,19 @@ public bool IsOpen

public ISession Session { get; private set; }

public Exception ConnectionStartException
{
get { return m_connectionStartException; }
}

public void MaybeSetConnectionStartException(Exception ex)
{
if (m_connectionStartCell != null)
{
m_connectionStartException = ex;
}
}

public Task Close(ushort replyCode, string replyText, bool abort)
{
return Close(new ShutdownEventArgs(ShutdownInitiator.Application,
Expand Down
5 changes: 3 additions & 2 deletions projects/Unit/APIApproval.Approve.verified.txt
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,11 @@ namespace RabbitMQ.Client
}
public class ShutdownEventArgs : System.EventArgs
{
public ShutdownEventArgs(RabbitMQ.Client.ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null) { }
public ShutdownEventArgs(RabbitMQ.Client.ShutdownInitiator initiator, ushort replyCode, string replyText, ushort classId, ushort methodId, object cause = null) { }
public ShutdownEventArgs(RabbitMQ.Client.ShutdownInitiator initiator, ushort replyCode, string replyText, object cause = null, System.Exception exception = null) { }
public ShutdownEventArgs(RabbitMQ.Client.ShutdownInitiator initiator, ushort replyCode, string replyText, ushort classId, ushort methodId, object cause = null, System.Exception exception = null) { }
public object Cause { get; }
public ushort ClassId { get; }
public System.Exception Exception { get; }
public RabbitMQ.Client.ShutdownInitiator Initiator { get; }
public ushort MethodId { get; }
public ushort ReplyCode { get; }
Expand Down

0 comments on commit 4cb93ed

Please sign in to comment.