Skip to content
Merged
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
14 changes: 12 additions & 2 deletions src/SqlBindingUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ internal static async Task OpenAsyncWithSqlErrorHandling(this SqlConnection conn
}

/// <summary>
/// Checks whether an exception is a fatal SqlException. It is deteremined to be fatal
/// Checks whether an exception is a fatal SqlException. It is determined to be fatal
/// if the Class value of the Exception is 20 or higher, see
/// https://learn.microsoft.com/dotnet/api/microsoft.data.sqlclient.sqlexception#remarks
/// for details
Expand All @@ -250,6 +250,16 @@ internal static bool IsFatalSqlException(this Exception e)
return (e as SqlException)?.Class >= 20 || (e.InnerException as SqlException)?.Class >= 20;
}

/// <summary>
/// Checks whether the connection state is currently Broken or Closed
/// </summary>
/// <param name="conn">The connection to check</param>
/// <returns>True if the connection is broken or closed, false otherwise</returns>
internal static bool IsBrokenOrClosed(this SqlConnection conn)
{
return conn.State == ConnectionState.Broken || conn.State == ConnectionState.Closed;
}

/// <summary>
/// Attempts to ensure that this connection is open, if it currently is in a broken state
/// then it will close the connection and re-open it.
Expand All @@ -266,7 +276,7 @@ internal static async Task<bool> TryEnsureConnected(this SqlConnection conn,
string connectionName,
CancellationToken token)
{
if (forceReconnect || conn.State.HasFlag(ConnectionState.Broken | ConnectionState.Closed))
if (forceReconnect || conn.IsBrokenOrClosed())
{
logger.LogWarning($"{connectionName} is broken, attempting to reconnect...");
logger.LogDebugWithThreadId($"BEGIN RetryOpen{connectionName}");
Expand Down
12 changes: 8 additions & 4 deletions src/TriggerBinding/SqlTableChangeMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,10 @@ private async Task RunChangeConsumptionLoopAsync()
await this.ReleaseLeasesAsync(connection, token);
}
}
catch (Exception e) when (e.IsFatalSqlException())
catch (Exception e) when (e.IsFatalSqlException() || connection.IsBrokenOrClosed())
{
// Retry connection if there was a fatal SQL exception or something else caused the connection to be closed
// since that indicates some other issue occurred (such as dropped network) and may be able to be recovered
this._logger.LogError($"Fatal SQL Client exception processing changes. Will attempt to reestablish connection in {this._pollingIntervalInMs}ms. Exception = {e.Message}");
forceReconnect = true;
}
Expand Down Expand Up @@ -435,9 +437,9 @@ private async Task GetTableChangesAsync(SqlConnection connection, CancellationTo
this._rowsToProcess = new List<IReadOnlyDictionary<string, object>>();
this._logger.LogError($"Failed to check for changes in table '{this._userTable.FullName}' due to exception: {e.GetType()}. Exception message: {e.Message}");
TelemetryInstance.TrackException(TelemetryErrorName.GetChanges, e, this._telemetryProps);
if (e.IsFatalSqlException())
if (e.IsFatalSqlException() || connection.IsBrokenOrClosed())
{
// If we get a fatal SQL Client exception here let it bubble up so we can try to re-establish the connection
// If we get a fatal SQL Client exception or the connection is broken let it bubble up so we can try to re-establish the connection
throw;
}
}
Expand Down Expand Up @@ -546,8 +548,10 @@ private async void RunLeaseRenewalLoopAsync()
{
await this.RenewLeasesAsync(connection, token);
}
catch (Exception e) when (e.IsFatalSqlException())
catch (Exception e) when (e.IsFatalSqlException() || connection.IsBrokenOrClosed())
{
// Retry connection if there was a fatal SQL exception or something else caused the connection to be closed
// since that indicates some other issue occurred (such as dropped network) and may be able to be recovered
forceReconnect = true;
}

Expand Down