Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace ServiceLayer.Mesh.FileTypes.NbssAppointmentEvents.Validation;

// TODO - create a whole bunch of implementations of this to perform the validation against NBSS Appointment events records
public interface IRecordValidator
{
IEnumerable<ValidationError> Validate(FileDataRecord fileDataRecord);
Expand Down
8 changes: 4 additions & 4 deletions src/ServiceLayer.Mesh/Functions/FileRetryFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ private async Task RetryStaleExtractions(DateTime staleDateTimeUtc)
&& f.LastUpdatedUtc <= staleDateTimeUtc)
.ToListAsync();

logger.LogInformation($"FileRetryFunction: {staleFiles.Count} stale files found for extraction retry");
logger.LogInformation("FileRetryFunction: {StaleFilesCount} stale files found for extraction retry", staleFiles.Count);

foreach (var file in staleFiles)
{
await fileExtractQueueClient.EnqueueFileExtractAsync(file);
file.LastUpdatedUtc = DateTime.UtcNow;
await serviceLayerDbContext.SaveChangesAsync();
logger.LogInformation($"FileRetryFunction: File {file.FileId} enqueued to Extract queue");
logger.LogInformation("FileRetryFunction: File {FileFileId} enqueued to Extract queue", file.FileId);
}
}

Expand All @@ -53,14 +53,14 @@ private async Task RetryStaleTransformations(DateTime staleDateTimeUtc)
&& f.LastUpdatedUtc <= staleDateTimeUtc)
.ToListAsync();

logger.LogInformation($"FileRetryFunction: {staleFiles.Count} stale files found for transforming retry");
logger.LogInformation("FileRetryFunction: {StaleFilesCount} stale files found for transforming retry", staleFiles.Count);

foreach (var file in staleFiles)
{
await fileTransformQueueClient.EnqueueFileTransformAsync(file);
file.LastUpdatedUtc = DateTime.UtcNow;
await serviceLayerDbContext.SaveChangesAsync();
logger.LogInformation($"FileRetryFunction: File {file.FileId} enqueued to Transform queue");
logger.LogInformation("FileRetryFunction: File {FileFileId} enqueued to Transform queue", file.FileId);
}
}
}
4 changes: 1 addition & 3 deletions src/ServiceLayer.Mesh/Messaging/FileExtractQueueClient.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
using Azure.Storage.Queues;
using Microsoft.Extensions.Logging;
using ServiceLayer.Data.Models;
using ServiceLayer.Mesh.Configuration;

namespace ServiceLayer.Mesh.Messaging;

public class FileExtractQueueClient(
ILogger<FileExtractQueueClient> logger,
IFileExtractQueueClientConfiguration configuration,
QueueServiceClient queueServiceClient)
: QueueClientBase(logger, queueServiceClient), IFileExtractQueueClient
: QueueClientBase(queueServiceClient), IFileExtractQueueClient
{
public async Task EnqueueFileExtractAsync(MeshFile file)
{
Expand Down
4 changes: 1 addition & 3 deletions src/ServiceLayer.Mesh/Messaging/FileTransformQueueClient.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
using Azure.Storage.Queues;
using Microsoft.Extensions.Logging;
using ServiceLayer.Data.Models;
using ServiceLayer.Mesh.Configuration;

namespace ServiceLayer.Mesh.Messaging;

public class FileTransformQueueClient(
ILogger<FileTransformQueueClient> logger,
IFileTransformQueueClientConfiguration configuration,
QueueServiceClient queueServiceClient)
: QueueClientBase(logger, queueServiceClient), IFileTransformQueueClient
: QueueClientBase(queueServiceClient), IFileTransformQueueClient
{
public async Task EnqueueFileTransformAsync(MeshFile file)
{
Expand Down
28 changes: 5 additions & 23 deletions src/ServiceLayer.Mesh/Messaging/QueueClientBase.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using System.Text.Json;
using Azure.Storage.Queues;
using Microsoft.Extensions.Logging;

namespace ServiceLayer.Mesh.Messaging;

public abstract class QueueClientBase(ILogger logger, QueueServiceClient queueServiceClient)
public abstract class QueueClientBase(QueueServiceClient queueServiceClient)
{
private QueueClient? _queueClient;
private QueueClient? _poisonQueueClient;
Expand Down Expand Up @@ -37,30 +36,13 @@ private QueueClient CreatePoisonClient()

protected async Task SendJsonMessageAsync<T>(T message)
{
try
{
var json = JsonSerializer.Serialize(message, QueueJsonOptions);
await Client.SendMessageAsync(json);
}
catch (Exception e)
{
// TODO - consider including file ID or correlation ID in error logs
logger.LogError(e, "Error sending message to queue {QueueName}", QueueName);
throw;
}
var json = JsonSerializer.Serialize(message, QueueJsonOptions);
await Client.SendMessageAsync(json);
}

protected async Task SendToPoisonQueueAsync<T>(T message)
{
try
{
var json = JsonSerializer.Serialize(message, QueueJsonOptions);
await PoisonClient.SendMessageAsync(json);
}
catch (Exception e)
{
logger.LogError(e, "Error sending message to poison queue {PoisonQueueName}", $"{QueueName}-poison");
throw;
}
var json = JsonSerializer.Serialize(message, QueueJsonOptions);
await PoisonClient.SendMessageAsync(json);
}
}
6 changes: 0 additions & 6 deletions src/ServiceLayer.Mesh/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@
services.AddNbssAppointmentEventServices();
});


// Application Insights isn't enabled by default. See https://aka.ms/AAt8mw4.
// builder.Services
// .AddApplicationInsightsTelemetryWorkerService()
// .ConfigureFunctionsApplicationInsights();

var app = host.Build();
await app.RunAsync();
return;
Expand Down
3 changes: 1 addition & 2 deletions src/ServiceLayer.Mesh/Storage/IMeshFilesBlobStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ namespace ServiceLayer.Mesh.Storage;

public interface IMeshFilesBlobStore
{
// TODO - return a Stream or a byte array?
public Task<Stream> DownloadAsync(MeshFile file);

// Mesh client gives us a byte array, hence this not taking a stream.
// Mesh client gives us a byte array, hence this is not taking a stream.
public Task<string> UploadAsync(MeshFile file, byte[] data);
}
2 changes: 1 addition & 1 deletion src/ServiceLayer.Mesh/Storage/MeshFilesBlobStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace ServiceLayer.Mesh.Storage;

public class MeshFilesBlobStore : IMeshFilesBlobStore
{
private BlobContainerClient _blobContainerClient;
private readonly BlobContainerClient _blobContainerClient;

public MeshFilesBlobStore(BlobContainerClient blobContainerClient)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace ServiceLayer.Mesh.Tests.FileTypes.NbssAppointmentEvents.Validation;

public class RegexValidatorTests
public partial class RegexValidatorTests
{
private const string FieldName = "TestField";
private const string MissingCode = "ERR001";
private const string InvalidFormatCode = "ERR002";
private readonly Regex _pattern = new(@"^[A-Z]{2}\d{2}$", RegexOptions.Compiled);
private readonly Regex _pattern = TestRegex();

[Fact]
public void Validate_NullValue_ShouldReturnMissingError()
Expand Down Expand Up @@ -68,4 +68,7 @@ public void Validate_ValueMatchingPattern_ShouldReturnNoErrors(string validValue

Assert.Empty(errors);
}

[GeneratedRegex(@"^[A-Z]{2}\d{2}$", RegexOptions.Compiled)]
private static partial Regex TestRegex();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Moq;
using Microsoft.Azure.Functions.Worker;
using Moq;
using NHS.MESH.Client.Contracts.Services;
using NHS.MESH.Client.Models;
using ServiceLayer.Data.Models;
Expand Down Expand Up @@ -44,7 +45,7 @@ public async Task Run_AddsNewMessageToDbAndQueue()
});

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
var meshFile = AssertFileUpdated(testMessageId, MeshFileStatus.Discovered);
Expand All @@ -67,7 +68,7 @@ public async Task Run_DoesNotAddDuplicateMessageOrQueueIt()
});

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
var count = DbContext.MeshFiles.Count(f => f.FileId == existingFile.FileId);
Expand All @@ -87,7 +88,7 @@ public async Task Run_NoMessagesInInbox_DoesNothing()
});

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
Assert.Empty(DbContext.MeshFiles);
Expand All @@ -107,7 +108,7 @@ public async Task Run_MultipleMessagesInInbox_AllAreProcessed()
});

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
foreach (var id in messageIds)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.Azure.Functions.Worker;
using Moq;
using ServiceLayer.Data.Models;
using ServiceLayer.Mesh.Functions;
Expand Down Expand Up @@ -38,7 +39,7 @@ public async Task Run_EnqueuesDiscoveredOrExtractingFilesOlderThan12Hours(MeshFi
var file = SaveMeshFile(testStatus, 13);

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
_fileExtractQueueClientMock.Verify(q => q.EnqueueFileExtractAsync(It.Is<MeshFile>(f => f.FileId == file.FileId)), Times.Once);
Expand All @@ -56,7 +57,7 @@ public async Task Run_EnqueuesExtractedOrTransformingFilesOlderThan12Hours(MeshF
var file = SaveMeshFile(testStatus, 13);

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
_fileTransformQueueClientMock.Verify(q => q.EnqueueFileTransformAsync(It.Is<MeshFile>(f => f.FileId == file.FileId)), Times.Once);
Expand All @@ -76,7 +77,7 @@ public async Task Run_SkipsFreshFiles(MeshFileStatus testStatus)
var file = SaveMeshFile(testStatus);

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
_fileExtractQueueClientMock.Verify(q => q.EnqueueFileExtractAsync(It.IsAny<MeshFile>()), Times.Never);
Expand All @@ -95,7 +96,7 @@ public async Task Run_IgnoresFilesInOtherStatuses(MeshFileStatus ignoredStatus)
SaveMeshFile(ignoredStatus, 20);

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
_fileTransformQueueClientMock.Verify(q => q.EnqueueFileTransformAsync(It.IsAny<MeshFile>()), Times.Never);
Expand All @@ -106,7 +107,7 @@ public async Task Run_IgnoresFilesInOtherStatuses(MeshFileStatus ignoredStatus)
public async Task Run_IfNoFilesFoundDoNothing()
{
// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
_fileExtractQueueClientMock.Verify(q => q.EnqueueFileExtractAsync(It.IsAny<MeshFile>()), Times.Never);
Expand All @@ -122,7 +123,7 @@ public async Task Run_ProcessesMultipleEligibleFiles()
var file3 = SaveMeshFile(MeshFileStatus.Transforming, 13);

// Act
await _function.Run(null);
await _function.Run(new TimerInfo());

// Assert
_fileExtractQueueClientMock.Verify(q => q.EnqueueFileExtractAsync(It.Is<MeshFile>(f => f.FileId == file1.FileId)), Times.Once);
Expand Down
Loading