Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable writing events to external database #3739

Merged
merged 4 commits into from
Mar 7, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ private readonly HashSet<int> _transientErrors
private int _commandTimeout;
private static ReplicaHandler _replicaHandler;
private static object _initLocker = new object();
private static EventLogHandler _eventLogHandler;

/// <summary>
/// Constructor that initializes this implementation of the ISqlRetryService interface. This class
Expand Down Expand Up @@ -109,12 +110,14 @@ public SqlRetryService(
_customIsExceptionRetriable = sqlRetryServiceDelegateOptions.CustomIsExceptionRetriable;

InitReplicaHandler();
InitEventLogHandler();
}

private SqlRetryService(ISqlConnectionBuilder sqlConnectionBuilder)
{
_sqlConnectionBuilder = sqlConnectionBuilder;
InitReplicaHandler();
InitEventLogHandler();
}

/// <summary>
Expand Down Expand Up @@ -371,12 +374,23 @@ public async Task TryLogEvent(string process, string status, string text, DateTi
cmd.Parameters.AddWithValue("@Start", startDate.Value);
}

using var conn = await _sqlConnectionBuilder.GetSqlConnectionAsync(initialCatalog: null, cancellationToken: cancellationToken).ConfigureAwait(false);
conn.RetryLogicProvider = null;
await conn.OpenAsync(cancellationToken);
cmd.Connection = conn;

await cmd.ExecuteNonQueryAsync(cancellationToken);
var connStr = _eventLogHandler.GetEventLogConnectionString(_sqlConnectionBuilder);
if (connStr == null)
{
using var conn = await _sqlConnectionBuilder.GetSqlConnectionAsync(initialCatalog: null, cancellationToken: cancellationToken).ConfigureAwait(false);
conn.RetryLogicProvider = null;
await conn.OpenAsync(cancellationToken);
cmd.Connection = conn;
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
else
{
using var conn = new SqlConnection(connStr);
conn.RetryLogicProvider = null;
await conn.OpenAsync(cancellationToken);
cmd.Connection = conn;
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
}
catch
{
Expand All @@ -395,10 +409,21 @@ private static void InitReplicaHandler()
}
}

private static void InitEventLogHandler()
{
if (_eventLogHandler == null) // this is needed, strictly speaking, only if SqlRetryService is not singleton, but it works either way.
{
lock (_initLocker)
{
_eventLogHandler ??= new EventLogHandler();
}
}
}

private class ReplicaHandler
{
private DateTime? _lastUpdated;
private object _databaseAccessLocker = new object();
private readonly object _databaseAccessLocker = new object();
private double _replicaTrafficRatio = 0;
private long _usageCounter = 0;

Expand Down Expand Up @@ -481,5 +506,51 @@ private static double GetReplicaTrafficRatioFromDatabase(ISqlConnectionBuilder s
}
}
}

private class EventLogHandler
{
private bool _initialized = false;
private readonly object _databaseAccessLocker = new object();
private string _eventLogConnectionString = null;

public EventLogHandler()
{
}

internal string GetEventLogConnectionString(ISqlConnectionBuilder sqlConnectionBuilder)
{
if (!_initialized)
{
lock (_databaseAccessLocker)
{
if (!_initialized)
{
_eventLogConnectionString = GetEventLogConnectionStringFromDatabase(sqlConnectionBuilder);
}
}
}

return _eventLogConnectionString;
}

private string GetEventLogConnectionStringFromDatabase(ISqlConnectionBuilder sqlConnectionBuilder)
{
try
{
using var conn = sqlConnectionBuilder.GetSqlConnection();
conn.RetryLogicProvider = null;
conn.Open();
using var cmd = new SqlCommand("IF object_id('dbo.Parameters') IS NOT NULL SELECT Char FROM dbo.Parameters WHERE Id = 'EventLogConnectionString'", conn);
var value = cmd.ExecuteScalar();
var result = value == null ? null : (string)value;
_initialized = true;
return result;
}
catch (SqlException)
{
return null;
}
}
}
}
}
Loading