-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
EES-5147 - implemented proper Health Check function. Added configurat…
…ion into Bicep for configuring Health Checks and creating metrics. Reduced retry attempts on deploying Data Processor code and removed manual sleep, as sleeps are included in retry mechanism.
- Loading branch information
1 parent
1e9f1ab
commit 86bfc21
Showing
7 changed files
with
196 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
...loreEducationStatistics.Public.Data.Processor.Tests/Functions/HealthCheckFunctionTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
using System.Net; | ||
using GovUk.Education.ExploreEducationStatistics.Common.Tests.Extensions; | ||
using GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Functions; | ||
using GovUk.Education.ExploreEducationStatistics.Public.Data.Services.Interfaces; | ||
using Microsoft.AspNetCore.Http; | ||
|
||
namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Tests.Functions; | ||
|
||
public abstract class HealthCheckFunctionTests(ProcessorFunctionsIntegrationTestFixture fixture) | ||
: ProcessorFunctionsIntegrationTest(fixture) | ||
{ | ||
public class HealthCheckTests(ProcessorFunctionsIntegrationTestFixture fixture) | ||
: HealthCheckFunctionTests(fixture) | ||
{ | ||
[Fact] | ||
public async Task Success() | ||
{ | ||
// Ensure that the test folder for simulating the File Share Mount is present prior to | ||
// running the Health Check. | ||
var dataSetVersionPathResolver = GetRequiredService<IDataSetVersionPathResolver>(); | ||
Directory.CreateDirectory(dataSetVersionPathResolver.BasePath()); | ||
|
||
var function = GetRequiredService<HealthCheckFunctions>(); | ||
|
||
var httpContext = new DefaultHttpContext(); | ||
var result = await function.HealthCheck(httpContext.Request); | ||
|
||
var expectedHealthCheckResult = new HealthCheckFunctions.HealthCheckResponse( | ||
PsqlConnection: new HealthCheckFunctions.HealthCheckSummary(Healthy: true), | ||
FileShareMount: new HealthCheckFunctions.HealthCheckSummary(Healthy: true)); | ||
|
||
result.AssertOkObjectResult(expectedHealthCheckResult); | ||
Assert.Equal((int) HttpStatusCode.OK, httpContext.Response.StatusCode); | ||
} | ||
|
||
[Fact] | ||
public async Task Failure_NoFileShareMount() | ||
{ | ||
var function = GetRequiredService<HealthCheckFunctions>(); | ||
|
||
// Call the Health Check without firstly adding a test File Share folder. | ||
var httpContext = new DefaultHttpContext(); | ||
var result = await function.HealthCheck(httpContext.Request); | ||
|
||
var expectedHealthCheckResult = new HealthCheckFunctions.HealthCheckResponse( | ||
PsqlConnection: new HealthCheckFunctions.HealthCheckSummary(Healthy: true), | ||
FileShareMount: new HealthCheckFunctions.HealthCheckSummary( | ||
Healthy: false, | ||
"File Share Mount folder does not exist")); | ||
|
||
result.AssertObjectResult(HttpStatusCode.InternalServerError, expectedHealthCheckResult); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 45 additions & 26 deletions
71
...cation.ExploreEducationStatistics.Public.Data.Processor/Functions/HealthCheckFunctions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,82 @@ | ||
using GovUk.Education.ExploreEducationStatistics.Public.Data.Model.Database; | ||
using GovUk.Education.ExploreEducationStatistics.Public.Data.Services.Options; | ||
using GovUk.Education.ExploreEducationStatistics.Public.Data.Services.Interfaces; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.Azure.Functions.Worker; | ||
using Microsoft.Azure.Functions.Worker.Http; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace GovUk.Education.ExploreEducationStatistics.Public.Data.Processor.Functions; | ||
|
||
// ReSharper disable once ClassNeverInstantiated.Global | ||
public class HealthCheckFunctions( | ||
ILogger<HealthCheckFunctions> logger, | ||
PublicDataDbContext publicDataDbContext, | ||
IOptions<ParquetFilesOptions> parquetFileOptions) | ||
IDataSetVersionPathResolver dataSetVersionPathResolver) | ||
{ | ||
[Function(nameof(CountDataSets))] | ||
public async Task<string> CountDataSets( | ||
[Function(nameof(HealthCheck))] | ||
[Produces("application/json")] | ||
public async Task<IActionResult> HealthCheck( | ||
#pragma warning disable IDE0060 | ||
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequestData request) | ||
[HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest request) | ||
#pragma warning restore IDE0060 | ||
{ | ||
var psqlConnectionHealthCheck = await CheckPsqlConnectionHealthy(); | ||
var fileShareMountHealthCheck = CheckFileShareMountHealth(); | ||
var healthCheckResponse = new HealthCheckResponse( | ||
PsqlConnection: psqlConnectionHealthCheck, | ||
FileShareMount: fileShareMountHealthCheck); | ||
|
||
if (healthCheckResponse.Healthy) | ||
{ | ||
return new OkObjectResult(healthCheckResponse); | ||
} | ||
|
||
return new ObjectResult(healthCheckResponse){ | ||
StatusCode = StatusCodes.Status500InternalServerError | ||
}; | ||
} | ||
|
||
private async Task<HealthCheckSummary> CheckPsqlConnectionHealthy() | ||
{ | ||
logger.LogInformation("Attempting to test PSQL health"); | ||
|
||
try | ||
{ | ||
var message = $"Found {await publicDataDbContext.DataSets.CountAsync()} datasets."; | ||
logger.LogInformation(message); | ||
return message; | ||
await publicDataDbContext.DataSets.AnyAsync(); | ||
return new HealthCheckSummary(true); | ||
} | ||
catch (Exception e) | ||
{ | ||
logger.LogError(e, "Error encountered when querying Data Sets"); | ||
throw; | ||
logger.LogError(e, "Error encountered when testing PSQL connection health"); | ||
return new HealthCheckSummary(false, e.Message); | ||
} | ||
} | ||
|
||
[Function(nameof(CheckForFileShareMount))] | ||
public Task CheckForFileShareMount( | ||
#pragma warning disable IDE0060 | ||
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequestData request) | ||
#pragma warning restore IDE0060 | ||
private HealthCheckSummary CheckFileShareMountHealth() | ||
{ | ||
logger.LogInformation("Attempting to read from file share"); | ||
|
||
try | ||
{ | ||
if (Directory.Exists(parquetFileOptions.Value.BasePath)) | ||
{ | ||
logger.LogInformation("Successfully found the file share mount"); | ||
} | ||
else | ||
if (Directory.Exists(dataSetVersionPathResolver.BasePath())) | ||
{ | ||
logger.LogError("Unable to find the file share mount"); | ||
return new HealthCheckSummary(true); | ||
} | ||
|
||
return new HealthCheckSummary(false, "File Share Mount folder does not exist"); | ||
} | ||
catch (Exception e) | ||
{ | ||
logger.LogError(e, "Error encountered when attempting to find the file share mount"); | ||
throw; | ||
return new HealthCheckSummary(false, e.Message); | ||
} | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
public record HealthCheckResponse(HealthCheckSummary PsqlConnection, HealthCheckSummary FileShareMount) | ||
{ | ||
public bool Healthy => PsqlConnection.Healthy && FileShareMount.Healthy; | ||
}; | ||
|
||
public record HealthCheckSummary(bool Healthy, string? UnhealthyReason = null); | ||
} |