Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions source/Nevermore/Diagnostics/Events/DiagnosticSources.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Data.Common;
using System.Diagnostics;
using Nevermore.Transient;

namespace Nevermore.Diagnostics.Events
{
public static class DiagnosticSources
{
public static class Retry
{
static readonly DiagnosticSource Source = new DiagnosticListener("Nevermore.Retry");

public static void OwnedConnectionClosed(DbCommand command, RetryPolicy retryPolicy, string operationName)
{
if (Source.IsEnabled(nameof(OwnedConnectionClosed)))
{
Source.Write(nameof(OwnedConnectionClosed), new
{
Command = command,
RetryPolicy = retryPolicy,
OperationName = operationName
});
}
}

public static void ConnectionOpened(DbConnection connection, RetryPolicy retryPolicy)
{
if (Source.IsEnabled(nameof(ConnectionOpened)))
{
Source.Write(nameof(ConnectionOpened), new
{
Connection = connection,
RetryPolicy = retryPolicy
});
}
}

public static void ConnectionReopening(DbCommand command, RetryPolicy retryPolicy)
{
if (Source.IsEnabled(nameof(ConnectionReopening)))
{
Source.Write(nameof(ConnectionReopening), new
{
Command = command,
RetryPolicy = retryPolicy
});
}
}

public static void ConnectionReopened(DbCommand command, RetryPolicy retryPolicy)
{
if (Source.IsEnabled(nameof(ConnectionReopened)))
{
Source.Write(nameof(ConnectionReopened), new
{
Command = command,
RetryPolicy = retryPolicy
});
}
}
}
}
}
31 changes: 27 additions & 4 deletions source/Nevermore/Transient/DbCommandExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using Nevermore.Diagnostics.Events;

namespace Nevermore.Transient
{
Expand All @@ -22,7 +23,10 @@ public static int ExecuteNonQueryWithRetry(this DbCommand command, RetryPolicy c
finally
{
if (weOwnTheConnectionLifetime && command.Connection?.State == ConnectionState.Open)
{
command.Connection.Close();
DiagnosticSources.Retry.OwnedConnectionClosed(command, commandRetryPolicy, operationName);
}
}
});
}
Expand All @@ -41,7 +45,10 @@ public static Task<int> ExecuteNonQueryWithRetryAsync(this DbCommand command, Re
finally
{
if (weOwnTheConnectionLifetime && command.Connection?.State == ConnectionState.Open)
{
await command.Connection.CloseAsync();
DiagnosticSources.Retry.OwnedConnectionClosed(command, commandRetryPolicy, operationName);
}
}
});
}
Expand All @@ -59,9 +66,12 @@ public static DbDataReader ExecuteReaderWithRetry(this DbCommand command, RetryP
}
catch (Exception)
{
if (weOwnTheConnectionLifetime && command.Connection != null &&
command.Connection.State == ConnectionState.Open)
if (weOwnTheConnectionLifetime && command.Connection?.State == ConnectionState.Open)
{
command.Connection.Close();
DiagnosticSources.Retry.OwnedConnectionClosed(command, commandRetryPolicy, operationName);
}

throw;
}
});
Expand All @@ -81,9 +91,12 @@ public static async Task<DbDataReader> ExecuteReaderWithRetryAsync(this DbComman
}
catch (Exception)
{
if (weOwnTheConnectionLifetime && command.Connection != null &&
command.Connection.State == ConnectionState.Open)
if (weOwnTheConnectionLifetime && command.Connection?.State == ConnectionState.Open)
{
await command.Connection.CloseAsync();
DiagnosticSources.Retry.OwnedConnectionClosed(command, commandRetryPolicy, operationName);
}

throw;
}
});
Expand All @@ -103,7 +116,10 @@ public static object ExecuteScalarWithRetry(this DbCommand command, RetryPolicy
finally
{
if (weOwnTheConnectionLifetime && command.Connection?.State == ConnectionState.Open)
{
command.Connection.Close();
DiagnosticSources.Retry.OwnedConnectionClosed(command, commandRetryPolicy, operationName);
}
}
});
}
Expand All @@ -122,7 +138,10 @@ public static async Task<object> ExecuteScalarWithRetryAsync(this DbCommand comm
finally
{
if (weOwnTheConnectionLifetime && command.Connection?.State == ConnectionState.Open)
{
await command.Connection.CloseAsync();
DiagnosticSources.Retry.OwnedConnectionClosed(command, commandRetryPolicy, operationName);
}
}
});
}
Expand All @@ -145,7 +164,9 @@ static bool EnsureValidConnection(DbCommand command, RetryPolicy retryPolicy)

if (command.Connection.State == ConnectionState.Open) return false;

DiagnosticSources.Retry.ConnectionReopening(command, retryPolicy);
command.Connection.OpenWithRetry(retryPolicy);
DiagnosticSources.Retry.ConnectionReopened(command, retryPolicy);
return true;
}

Expand All @@ -157,7 +178,9 @@ static async Task<bool> EnsureValidConnectionAsync(DbCommand command, RetryPolic

if (command.Connection.State == ConnectionState.Open) return false;

DiagnosticSources.Retry.ConnectionReopening(command, retryPolicy);
await command.Connection.OpenWithRetryAsync(retryPolicy, cancellationToken);
DiagnosticSources.Retry.ConnectionReopened(command, retryPolicy);
return true;
}
}
Expand Down
15 changes: 11 additions & 4 deletions source/Nevermore/Transient/DbConnectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using Nevermore.Diagnostics.Events;

namespace Nevermore.Transient
{
Expand All @@ -16,7 +15,11 @@ public static void OpenWithRetry(this DbConnection connection)

public static void OpenWithRetry(this DbConnection connection, RetryPolicy retryPolicy)
{
(retryPolicy ?? RetryPolicy.NoRetry).LoggingRetries("Open Database Connection").ExecuteAction(connection.Open);
(retryPolicy ?? RetryPolicy.NoRetry).LoggingRetries("Open Database Connection").ExecuteAction(() =>
{
connection.Open();
DiagnosticSources.Retry.ConnectionOpened(connection, retryPolicy);
});
}

public static Task OpenWithRetryAsync(this DbConnection connection)
Expand All @@ -36,7 +39,11 @@ public static Task OpenWithRetryAsync(this DbConnection connection, RetryPolicy

public static Task OpenWithRetryAsync(this DbConnection connection, RetryPolicy retryPolicy, CancellationToken cancellationToken)
{
return (retryPolicy ?? RetryPolicy.NoRetry).LoggingRetries("Open Database Connection").ExecuteActionAsync(() => connection.OpenAsync(cancellationToken));
return (retryPolicy ?? RetryPolicy.NoRetry).LoggingRetries("Open Database Connection").ExecuteActionAsync(async () =>
{
await connection.OpenAsync(cancellationToken);
DiagnosticSources.Retry.ConnectionOpened(connection, retryPolicy);
});
}
}
}
10 changes: 5 additions & 5 deletions source/Nevermore/Transient/RetryPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ namespace Nevermore.Transient
/// Initializes a new instance of the <see cref="T:Nevermore.Transient.RetryPolicy`1" /> class with the specified number of retry attempts and parameters defining the progressive delay between retries.
/// </summary>
/// <param name="retryStrategy">The strategy to use for this retry policy.</param>
public RetryPolicy(RetryStrategy retryStrategy) : base((default(T) == null) ? Activator.CreateInstance<T>() : default(T), retryStrategy)
public RetryPolicy(RetryStrategy retryStrategy) : base(new T(), retryStrategy)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="T:Nevermore.Transient.RetryPolicy`1" /> class with the specified number of retry attempts and the default fixed time interval between retries.
/// </summary>
/// <param name="retryCount">The number of retry attempts.</param>
public RetryPolicy(int retryCount) : base((default(T) == null) ? Activator.CreateInstance<T>() : default(T), retryCount)
public RetryPolicy(int retryCount) : base(new T(), retryCount)
{
}

Expand All @@ -32,7 +32,7 @@ namespace Nevermore.Transient
/// </summary>
/// <param name="retryCount">The number of retry attempts.</param>
/// <param name="retryInterval">The interval between retries.</param>
public RetryPolicy(int retryCount, TimeSpan retryInterval) : base((default(T) == null) ? Activator.CreateInstance<T>() : default(T), retryCount, retryInterval)
public RetryPolicy(int retryCount, TimeSpan retryInterval) : base(new T(), retryCount, retryInterval)
{
}

Expand All @@ -43,7 +43,7 @@ namespace Nevermore.Transient
/// <param name="minBackoff">The minimum backoff time.</param>
/// <param name="maxBackoff">The maximum backoff time.</param>
/// <param name="deltaBackoff">The time value that will be used to calculate a random delta in the exponential delay between retries.</param>
public RetryPolicy(int retryCount, TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff) : base((default(T) == null) ? Activator.CreateInstance<T>() : default(T), retryCount, minBackoff, maxBackoff, deltaBackoff)
public RetryPolicy(int retryCount, TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff) : base(new T(), retryCount, minBackoff, maxBackoff, deltaBackoff)
{
}

Expand All @@ -53,7 +53,7 @@ namespace Nevermore.Transient
/// <param name="retryCount">The number of retry attempts.</param>
/// <param name="initialInterval">The initial interval that will apply for the first retry.</param>
/// <param name="increment">The incremental time value that will be used to calculate the progressive delay between retries.</param>
public RetryPolicy(int retryCount, TimeSpan initialInterval, TimeSpan increment) : base((default(T) == null) ? Activator.CreateInstance<T>() : default(T), retryCount, initialInterval, increment)
public RetryPolicy(int retryCount, TimeSpan initialInterval, TimeSpan increment) : base(new T(), retryCount, initialInterval, increment)
{
}
}
Expand Down