Skip to content

Commit

Permalink
Added dependency injection for postgres
Browse files Browse the repository at this point in the history
  • Loading branch information
Henning Normann committed Oct 24, 2023
1 parent 883c377 commit dc5318e
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.12" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
using Altinn.Notifications.Core.Models.Recipients;
using Altinn.Notifications.Core.Repository.Interfaces;
using Altinn.Notifications.Persistence.Extensions;

using Microsoft.ApplicationInsights;
using Npgsql;

using NpgsqlTypes;

namespace Altinn.Notifications.Persistence.Repository;
Expand All @@ -17,6 +16,8 @@ namespace Altinn.Notifications.Persistence.Repository;
public class EmailNotificationRepository : IEmailNotificationRepository
{
private readonly NpgsqlDataSource _dataSource;
private readonly TelemetryClient _telemetryClient;

private const string _insertEmailNotificationSql = "call notifications.insertemailnotification($1, $2, $3, $4, $5, $6, $7)"; // (__orderid, _alternateid, _recipientid, _toaddress, _result, _resulttime, _expirytime)
private const string _getEmailNotificationsSql = "select * from notifications.getemails_statusnew_updatestatus()";
private const string _updateEmailStatus = "call notifications.updateemailstatus($1, $2, $3)"; // (_alternateid, _result, _operationid)
Expand All @@ -26,15 +27,18 @@ public class EmailNotificationRepository : IEmailNotificationRepository
/// Initializes a new instance of the <see cref="EmailNotificationRepository"/> class.
/// </summary>
/// <param name="dataSource">The npgsql data source.</param>
public EmailNotificationRepository(NpgsqlDataSource dataSource)
/// <param name="telemetryClient">Telemetry client</param>
public EmailNotificationRepository(NpgsqlDataSource dataSource, TelemetryClient telemetryClient = null)

Check warning on line 31 in src/Altinn.Notifications.Persistence/Repository/EmailNotificationRepository.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Cannot convert null literal to non-nullable reference type.

Check warning on line 31 in src/Altinn.Notifications.Persistence/Repository/EmailNotificationRepository.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Cannot convert null literal to non-nullable reference type.

Check warning on line 31 in src/Altinn.Notifications.Persistence/Repository/EmailNotificationRepository.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Cannot convert null literal to non-nullable reference type.

Check warning on line 31 in src/Altinn.Notifications.Persistence/Repository/EmailNotificationRepository.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Cannot convert null literal to non-nullable reference type.
{
_dataSource = dataSource;
_telemetryClient = telemetryClient;
}

/// <inheritdoc/>
public async Task AddNotification(EmailNotification notification, DateTime expiry)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_insertEmailNotificationSql);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);

pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, notification.OrderId);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, notification.Id);
Expand All @@ -45,13 +49,15 @@ public async Task AddNotification(EmailNotification notification, DateTime expir
pgcom.Parameters.AddWithValue(NpgsqlDbType.TimestampTz, expiry);

await pgcom.ExecuteNonQueryAsync();
tracker.Track();
}

/// <inheritdoc/>
public async Task<List<Email>> GetNewNotifications()
{
List<Email> searchResult = new();
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_getEmailNotificationsSql);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);

await using (NpgsqlDataReader reader = await pgcom.ExecuteReaderAsync())
{
Expand All @@ -71,17 +77,20 @@ public async Task<List<Email>> GetNewNotifications()
}
}

tracker.Track();
return searchResult;
}

/// <inheritdoc/>
public async Task UpdateSendStatus(Guid notificationId, EmailNotificationResultType status, string? operationId = null)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_updateEmailStatus);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, notificationId);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, status.ToString());
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, operationId ?? (object)DBNull.Value);
await pgcom.ExecuteNonQueryAsync();
tracker.Track();
}

/// <inheritdoc/>
Expand All @@ -90,6 +99,7 @@ public async Task<List<EmailRecipient>> GetRecipients(Guid notificationId)
List<EmailRecipient> searchResult = new();

await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_getEmailRecipients);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, notificationId);
await using (NpgsqlDataReader reader = await pgcom.ExecuteReaderAsync())
{
Expand All @@ -103,6 +113,7 @@ public async Task<List<EmailRecipient>> GetRecipients(Guid notificationId)
}
}

tracker.Track();
return searchResult;
}
}
25 changes: 22 additions & 3 deletions src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Altinn.Notifications.Core.Models.Orders;
using Altinn.Notifications.Core.Repository.Interfaces;
using Altinn.Notifications.Persistence.Extensions;
using Microsoft.ApplicationInsights;
using Npgsql;
using NpgsqlTypes;

Expand All @@ -16,6 +17,7 @@ namespace Altinn.Notifications.Persistence.Repository;
public class OrderRepository : IOrderRepository
{
private readonly NpgsqlDataSource _dataSource;
private readonly TelemetryClient _telemetryClient;

private const string _getOrderByIdSql = "select notificationorder from notifications.orders where alternateid=$1 and creatorname=$2";
private const string _getOrdersBySendersReferenceSql = "select notificationorder from notifications.orders where sendersreference=$1 and creatorname=$2";
Expand All @@ -29,15 +31,18 @@ public class OrderRepository : IOrderRepository
/// Initializes a new instance of the <see cref="OrderRepository"/> class.
/// </summary>
/// <param name="dataSource">The npgsql data source.</param>
public OrderRepository(NpgsqlDataSource dataSource)
/// <param name="telemetryClient">Telemetry client</param>
public OrderRepository(NpgsqlDataSource dataSource, TelemetryClient telemetryClient = null)

Check warning on line 35 in src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Cannot convert null literal to non-nullable reference type.

Check warning on line 35 in src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Cannot convert null literal to non-nullable reference type.

Check warning on line 35 in src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Cannot convert null literal to non-nullable reference type.

Check warning on line 35 in src/Altinn.Notifications.Persistence/Repository/OrderRepository.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Cannot convert null literal to non-nullable reference type.
{
_dataSource = dataSource;
_telemetryClient = telemetryClient;
}

/// <inheritdoc/>
public async Task<NotificationOrder?> GetOrderById(Guid id, string creator)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_getOrderByIdSql);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, id);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, creator);

Expand All @@ -51,6 +56,7 @@ public OrderRepository(NpgsqlDataSource dataSource)
}
}

tracker.Track();
return order;
}

Expand All @@ -60,6 +66,7 @@ public async Task<List<NotificationOrder>> GetOrdersBySendersReference(string se
List<NotificationOrder> searchResult = new();

await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_getOrdersBySendersReferenceSql);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, sendersReference);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, creator);

Expand All @@ -72,6 +79,7 @@ public async Task<List<NotificationOrder>> GetOrdersBySendersReference(string se
}
}

tracker.Track();
return searchResult;
}

Expand Down Expand Up @@ -105,9 +113,11 @@ public async Task<NotificationOrder> Create(NotificationOrder order)
public async Task SetProcessingStatus(Guid orderId, OrderProcessingStatus status)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_setProcessCompleted);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, status.ToString());
pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, orderId);
await pgcom.ExecuteNonQueryAsync();
tracker.Track();
}

/// <inheritdoc/>
Expand All @@ -116,7 +126,7 @@ public async Task<List<NotificationOrder>> GetPastDueOrdersAndSetProcessingState
List<NotificationOrder> searchResult = new();

await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_getOrdersPastSendTimeUpdateStatus);

using TelemetryTracker tracker = new(_telemetryClient, pgcom);
await using (NpgsqlDataReader reader = await pgcom.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
Expand All @@ -126,13 +136,15 @@ public async Task<List<NotificationOrder>> GetPastDueOrdersAndSetProcessingState
}
}

tracker.Track();
return searchResult;
}

/// <inheritdoc/>
public async Task<NotificationOrderWithStatus?> GetOrderWithStatusById(Guid id, string creator)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_getOrderIncludeStatus);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, id);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, creator);

Expand Down Expand Up @@ -163,6 +175,7 @@ public async Task<List<NotificationOrder>> GetPastDueOrdersAndSetProcessingState
}
}

tracker.Track();
return order;
}

Expand All @@ -189,6 +202,7 @@ public async Task<List<NotificationOrder>> GetPastDueOrdersAndSetProcessingState
private async Task<long> InsertOrder(NotificationOrder order)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_insertOrderSql);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);

pgcom.Parameters.AddWithValue(NpgsqlDbType.Uuid, order.Id);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, order.Creator.ShortName);
Expand All @@ -199,12 +213,16 @@ private async Task<long> InsertOrder(NotificationOrder order)

await using NpgsqlDataReader reader = await pgcom.ExecuteReaderAsync();
await reader.ReadAsync();
return (long)reader.GetValue(0);

long orderId = (long)reader.GetValue(0);
tracker.Track();
return orderId;
}

private async Task InsertEmailText(long dbOrderId, string fromAddress, string subject, string body, string contentType)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_insertEmailTextSql);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);

pgcom.Parameters.AddWithValue(NpgsqlDbType.Bigint, dbOrderId);
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, fromAddress);
Expand All @@ -213,5 +231,6 @@ private async Task InsertEmailText(long dbOrderId, string fromAddress, string su
pgcom.Parameters.AddWithValue(NpgsqlDbType.Text, contentType);

await pgcom.ExecuteNonQueryAsync();
tracker.Track();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Diagnostics;
using Microsoft.ApplicationInsights;
using Npgsql;

namespace Altinn.Notifications.Persistence.Repository
{
/// <summary>
/// Helper to track application insights dependencies for PostgreSQL invocations
/// </summary>
public class TelemetryTracker : IDisposable

Check warning on line 10 in src/Altinn.Notifications.Persistence/Repository/TelemetryTracker.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Fix this implementation of 'IDisposable' to conform to the dispose pattern. (https://rules.sonarsource.com/csharp/RSPEC-3881)

Check warning on line 10 in src/Altinn.Notifications.Persistence/Repository/TelemetryTracker.cs

View workflow job for this annotation

GitHub Actions / Build, test & analyze

Fix this implementation of 'IDisposable' to conform to the dispose pattern. (https://rules.sonarsource.com/csharp/RSPEC-3881)
{
private readonly DateTime _startTime = DateTime.Now;
private readonly Stopwatch _timer = Stopwatch.StartNew();
private readonly TelemetryClient _telemetryClient;
private readonly NpgsqlCommand _cmd;
private bool _tracked = false;

/// <summary>
/// Initializes a new instance of the <see cref="TelemetryTracker"/> class.
/// </summary>
/// <param name="telemetryClient">Telemetry client from DI</param>
/// <param name="cmd">The npgsql cmd</param>
public TelemetryTracker(TelemetryClient telemetryClient, NpgsqlCommand cmd)
{
_telemetryClient = telemetryClient;
_cmd = cmd;
}

/// <inheritdoc/>
public void Dispose()
{
if (!_tracked)
{
Track(false);
_tracked = true;
}

GC.SuppressFinalize(this);
}

/// <summary>
/// Track the PostgreSQL invocation
/// <paramref name="success">Outcome of invocation</paramref>
/// </summary>
public void Track(bool success = true)
{
_timer.Stop();
if (_telemetryClient != null)
{
_telemetryClient.TrackDependency("Postgres", _cmd.CommandText, _cmd.CommandText, _startTime, _timer.Elapsed, success);
}

_tracked = true;
}
}
}
1 change: 1 addition & 0 deletions src/Altinn.Notifications/Altinn.Notifications.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<ProjectGuid>{A791EC3D-DC08-416D-9522-C4BE4540084F}</ProjectGuid>
<UserSecretsId>abbc1054-3be2-45c5-b3e0-36044cb70e42</UserSecretsId>
</PropertyGroup>

<ItemGroup>
Expand Down

0 comments on commit dc5318e

Please sign in to comment.