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

Dispose database connections properly #233

Merged
merged 1 commit into from
Dec 14, 2023
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
49 changes: 14 additions & 35 deletions src/Altinn.Broker.Persistence/DatabaseConnectionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,51 +15,39 @@ namespace Altinn.Broker.Persistence;
public class DatabaseConnectionProvider : IDisposable
{
private readonly string _connectionString;
private NpgsqlConnection? _connection;
private NpgsqlDataSource _dataSource;
private string? _accessToken;

public DatabaseConnectionProvider(IOptions<DatabaseOptions> databaseOptions)
{
_connectionString = databaseOptions.Value.ConnectionString ?? throw new ArgumentNullException("DatabaseOptions__ConnectionString");
var dataSourceBuilder = new NpgsqlDataSourceBuilder(_connectionString);
var dataSource = dataSourceBuilder.Build();
_dataSource = dataSource;
}

public async Task<NpgsqlConnection> GetConnectionAsync()
{
NpgsqlConnectionStringBuilder connectionStringBuilder = new NpgsqlConnectionStringBuilder(_connectionString);
if (string.IsNullOrWhiteSpace(connectionStringBuilder.Password))
if (!string.IsNullOrWhiteSpace(connectionStringBuilder.Password)) // Developer mode
{
connectionStringBuilder.Password = _accessToken;
if (!IsAccessTokenValid())
{
await RefreshToken();
connectionStringBuilder.Password = _accessToken;
_connection = new NpgsqlConnection(connectionStringBuilder.ConnectionString);
}
}

if (_connection is null)
{
_connection = new NpgsqlConnection(connectionStringBuilder.ConnectionString);
_connection.Open();
return await _dataSource.OpenConnectionAsync();
}
else if (_connection.State == System.Data.ConnectionState.Closed)
if (_dataSource is null || !IsAccessTokenValid())
{
_connection.Open();
}
else if (_connection.State == System.Data.ConnectionState.Broken)
{
_connection.Close();
_connection.Open();
await RefreshToken();
connectionStringBuilder.Password = _accessToken;
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionStringBuilder.ConnectionString);
_dataSource = dataSourceBuilder.Build();
}

return _connection;
return await _dataSource.OpenConnectionAsync();
}

private async Task RefreshToken()
{
var sqlServerTokenProvider = new DefaultAzureCredential();
_accessToken = (await sqlServerTokenProvider.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { "https://ossrdbms-aad.database.windows.net/.default" }) { })).Token;
new TokenRequestContext(scopes: ["https://ossrdbms-aad.database.windows.net/.default"]) { })).Token;
}

private bool IsAccessTokenValid()
Expand All @@ -73,17 +61,8 @@ private bool IsAccessTokenValid()
return token.ValidTo > DateTime.Now.Subtract(TimeSpan.FromSeconds(60));
}

private void CloseConnection()
{
if (_connection != null && _connection.State != System.Data.ConnectionState.Closed)
{
_connection.Close();
}
}

public void Dispose()
{
CloseConnection();
_connection?.Dispose();
_dataSource?.Dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public ActorFileStatusRepository(IActorRepository actorRepository, DatabaseConne

public async Task<List<ActorFileStatusEntity>> GetActorEvents(Guid fileId)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using (var command = new NpgsqlCommand(
"SELECT *, a.actor_external_id " +
Expand Down Expand Up @@ -51,7 +51,7 @@ public async Task<List<ActorFileStatusEntity>> GetActorEvents(Guid fileId)

public async Task InsertActorFileStatus(Guid fileId, ActorFileStatus status, string actorExternalReference)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

var actor = await _actorRepository.GetActorAsync(actorExternalReference);
long actorId = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/Altinn.Broker.Persistence/Repositories/ActorRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public ActorRepository(DatabaseConnectionProvider connectionProvider)

public async Task<ActorEntity?> GetActorAsync(string actorExternalId)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using var command = new NpgsqlCommand(
"SELECT * FROM broker.actor WHERE actor_external_id = @actorExternalId",
Expand All @@ -38,7 +38,7 @@ public ActorRepository(DatabaseConnectionProvider connectionProvider)

public async Task<long> AddActorAsync(ActorEntity actor)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

NpgsqlCommand command = new NpgsqlCommand(
"INSERT INTO broker.actor (actor_external_id) " +
Expand Down
14 changes: 7 additions & 7 deletions src/Altinn.Broker.Persistence/Repositories/FileRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public FileRepository(DatabaseConnectionProvider connectionProvider, IActorRepos

public async Task<FileEntity?> GetFile(Guid fileId)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

var file = new FileEntity();
using var command = new NpgsqlCommand(
Expand Down Expand Up @@ -86,7 +86,7 @@ FROM broker.file
* */
private async Task<List<ActorFileStatusEntity>> GetLatestRecipientFileStatuses(Guid fileId)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

var fileStatuses = new List<ActorFileStatusEntity>();
using (var command = new NpgsqlCommand(
Expand Down Expand Up @@ -142,7 +142,7 @@ public async Task<Guid> AddFile(ServiceOwnerEntity serviceOwner, string filename
actorId = actor.ActorId;
}

var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();
NpgsqlCommand command = new NpgsqlCommand(
"INSERT INTO broker.file (file_id_pk, service_owner_id_fk, filename, checksum, external_file_reference, sender_actor_id_fk, created, storage_provider_id_fk, expiration_time) " +
"VALUES (@fileId, @serviceOwnerId, @filename, @checksum, @externalFileReference, @senderActorId, @created, @storageProviderId, @expirationTime)",
Expand All @@ -169,7 +169,7 @@ public async Task<Guid> AddFile(ServiceOwnerEntity serviceOwner, string filename

public async Task<List<Guid>> GetFilesAssociatedWithActor(ActorEntity actor)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using (var command = new NpgsqlCommand(
"SELECT DISTINCT afs.file_id_fk, 'Recipient' " +
Expand Down Expand Up @@ -203,7 +203,7 @@ public async Task<List<Guid>> GetFilesAssociatedWithActor(ActorEntity actor)

public async Task SetStorageReference(Guid fileId, long storageProviderId, string fileLocation)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using (var command = new NpgsqlCommand(
"UPDATE broker.file " +
Expand All @@ -221,7 +221,7 @@ public async Task SetStorageReference(Guid fileId, long storageProviderId, strin

private async Task<Dictionary<string, string>> GetMetadata(Guid fileId)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using (var command = new NpgsqlCommand(
"SELECT * " +
Expand All @@ -243,7 +243,7 @@ private async Task<Dictionary<string, string>> GetMetadata(Guid fileId)

private async Task SetMetadata(Guid fileId, Dictionary<string, string> property)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();
using var transaction = connection.BeginTransaction();
using var command = new NpgsqlCommand(
"INSERT INTO broker.file_property (property_id_pk, file_id_fk, key, value) " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public FileStatusRepository(DatabaseConnectionProvider connectionProvider)

public async Task InsertFileStatus(Guid fileId, FileStatus status)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();
using var command = new NpgsqlCommand("", connection);

command.CommandText =
Expand All @@ -34,7 +34,7 @@ public async Task InsertFileStatus(Guid fileId, FileStatus status)

public async Task<List<FileStatusEntity>> GetFileStatusHistory(Guid fileId)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using (var command = new NpgsqlCommand(
"SELECT * " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public ServiceOwnerRepository(DatabaseConnectionProvider connectionProvider)

public async Task<ServiceOwnerEntity?> GetServiceOwner(string serviceOwnerId)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();
using var command = new NpgsqlCommand(
"SELECT service_owner_id_pk, service_owner_name, file_time_to_live, " +
"storage_provider_id_pk, created, resource_name, storage_provider_type " +
Expand Down Expand Up @@ -52,7 +52,7 @@ public ServiceOwnerRepository(DatabaseConnectionProvider connectionProvider)

public async Task InitializeServiceOwner(string sub, string name, TimeSpan fileTimeToLive)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using (var command = new NpgsqlCommand(
"INSERT INTO broker.service_owner (service_owner_id_pk, service_owner_name, file_time_to_live) " +
Expand All @@ -70,7 +70,7 @@ public async Task InitializeServiceOwner(string sub, string name, TimeSpan fileT

public async Task InitializeStorageProvider(string sub, string resourceName, StorageProviderType storageType)
{
var connection = await _connectionProvider.GetConnectionAsync();
using var connection = await _connectionProvider.GetConnectionAsync();

using (var command = new NpgsqlCommand(
"INSERT INTO broker.storage_provider (created, resource_name, storage_provider_type, service_owner_id_fk, file_time_to_live) " +
Expand Down