Commit 0476eb83 authored by Marc Gravell's avatar Marc Gravell Committed by GitHub

Merge pull request #576 from deepakverma/retry-operation

supporting status for being able to retry, if command was never sent over the wire.
parents 83efa0d5 1e78a2a4
......@@ -64,6 +64,7 @@ public void AuthenticationFailureError()
};
var ex = Assert.Throws<RedisConnectionException>(() => muxer.GetDatabase().Ping());
var rde = (RedisConnectionException)ex.InnerException;
Assert.That(ex.CommandStatus, Is.EqualTo(CommandStatus.WaitingToBeSent));
Assert.That(rde.FailureType, Is.EqualTo(ConnectionFailureType.AuthenticationFailure));
Assert.That(rde.InnerException.Message, Is.EqualTo("Error: NOAUTH Authentication required. Verify if the Redis password provided is correct."));
//wait for a second for connectionfailed event to fire
......
namespace StackExchange.Redis
{
/// <summary>
/// track status of a command while communicating with Redis
/// </summary>
public enum CommandStatus
{
/// <summary>
/// command status unknown
/// </summary>
Unknown,
/// <summary>
/// ConnectionMultiplexer has not yet started writing this command to redis
/// </summary>
WaitingToBeSent,
/// <summary>
/// command has been sent to Redis
/// </summary>
Sent,
}
}
......@@ -12,7 +12,8 @@ internal static class ExceptionFactory
DataServerEndpoint = "server-endpoint",
DataConnectionState = "connection-state",
DataLastFailure = "last-failure",
DataLastInnerException = "last-innerexception";
DataLastInnerException = "last-innerexception",
DataSentStatusKey = "request-sent-status";
internal static Exception AdminModeNotEnabled(bool includeDetail, RedisCommand command, Message message, ServerEndPoint server)
......@@ -118,7 +119,7 @@ internal static Exception NoConnectionAvailable(bool includeDetail, RedisCommand
}
#endif
var ex = new RedisConnectionException(ConnectionFailureType.UnableToResolvePhysicalConnection, exceptionmessage.ToString(), innerException);
var ex = new RedisConnectionException(ConnectionFailureType.UnableToResolvePhysicalConnection, exceptionmessage.ToString(), innerException, message?.Status ?? CommandStatus.Unknown);
if (includeDetail)
{
......@@ -173,7 +174,7 @@ internal static Exception NoCursor(RedisCommand command)
internal static Exception Timeout(bool includeDetail, string errorMessage, Message message, ServerEndPoint server)
{
var ex = new TimeoutException(errorMessage);
var ex = new RedisTimeoutException(errorMessage, message?.Status ?? CommandStatus.Unknown);
if (includeDetail) AddDetail(ex, message, server, null);
return ex;
}
......@@ -182,7 +183,11 @@ private static void AddDetail(Exception exception, Message message, ServerEndPoi
{
if (exception != null)
{
if (message != null) exception.Data.Add(DataCommandKey, message.CommandAndKey);
if (message != null)
{
exception.Data.Add(DataCommandKey, message.CommandAndKey);
exception.Data.Add(DataSentStatusKey, message.Status);
}
else if (label != null) exception.Data.Add(DataCommandKey, label);
if (server != null) exception.Data.Add(DataServerKey, Format.ToString(server.EndPoint));
......
......@@ -27,6 +27,40 @@ public sealed class RedisCommandException : Exception
}
/// <summary>
/// Indicates the time allotted for a command or operation has expired.
/// </summary>
#if FEATURE_SERIALIZATION
[Serializable]
#endif
public sealed class RedisTimeoutException : TimeoutException
{
#if FEATURE_SERIALIZATION
private RedisTimeoutException(SerializationInfo info, StreamingContext ctx) : base(info, ctx)
{
Commandstatus = (CommandStatus) info.GetValue("commandStatus", typeof(CommandStatus));
}
/// <summary>
/// Serialization implementation; not intended for general usage
/// </summary>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("commandStatus", Commandstatus);
}
#endif
internal RedisTimeoutException(string message, CommandStatus commandStatus) : base(message)
{
Commandstatus = commandStatus;
}
/// <summary>
/// status of the command while communicating with Redis
/// </summary>
public CommandStatus Commandstatus { get; }
}
/// <summary>
/// Indicates a connection fault when communicating with redis
......@@ -40,6 +74,7 @@ public sealed class RedisConnectionException : RedisException
private RedisConnectionException(SerializationInfo info, StreamingContext ctx) : base(info, ctx)
{
FailureType = (ConnectionFailureType)info.GetInt32("failureType");
CommandStatus = (CommandStatus)info.GetValue("commandStatus", typeof(CommandStatus));
}
/// <summary>
/// Serialization implementation; not intended for general usage
......@@ -48,22 +83,33 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont
{
base.GetObjectData(info, context);
info.AddValue("failureType", (int)FailureType);
info.AddValue("commandStatus", CommandStatus);
}
#endif
internal RedisConnectionException(ConnectionFailureType failureType, string message) : base(message)
internal RedisConnectionException(ConnectionFailureType failureType, string message) : this(failureType, message, null, CommandStatus.Unknown)
{
FailureType = failureType;
}
internal RedisConnectionException(ConnectionFailureType failureType, string message, Exception innerException) : base(message, innerException)
internal RedisConnectionException(ConnectionFailureType failureType, string message, Exception innerException) : this(failureType, message, innerException, CommandStatus.Unknown)
{
}
internal RedisConnectionException(ConnectionFailureType failureType, string message, Exception innerException, CommandStatus commandStatus) : base(message, innerException)
{
FailureType = failureType;
CommandStatus = commandStatus;
}
/// <summary>
/// The type of connection failure
/// </summary>
public ConnectionFailureType FailureType { get; }
/// <summary>
/// status of the command while communicating with Redis
/// </summary>
public CommandStatus CommandStatus { get; }
}
/// <summary>
......@@ -193,6 +239,7 @@ protected Message(int db, CommandFlags flags, RedisCommand command)
createdDateTime = DateTime.UtcNow;
createdTimestamp = System.Diagnostics.Stopwatch.GetTimestamp();
Status = CommandStatus.WaitingToBeSent;
}
internal void SetMasterOnly()
......@@ -231,8 +278,11 @@ internal void PrepareToResend(ServerEndPoint resendTo, bool isMoved)
createdTimestamp = System.Diagnostics.Stopwatch.GetTimestamp();
performance = ProfileStorage.NewAttachedToSameContext(oldPerformance, resendTo, isMoved);
performance.SetMessage(this);
Status = CommandStatus.WaitingToBeSent;
}
internal CommandStatus Status { get; private set; }
public RedisCommand Command => command;
public virtual string CommandAndKey => Command.ToString();
......@@ -678,6 +728,7 @@ internal void SetEnqueued()
internal void SetRequestSent()
{
Status = CommandStatus.Sent;
performance?.SetRequestSent();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment