Skip to content

Commit

Permalink
Remove Serval status and add status summary to Health Check (#2951)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmachapman authored Jan 17, 2025
1 parent 762d684 commit 62ec49b
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 54 deletions.
27 changes: 1 addition & 26 deletions src/SIL.XForge.Scripture/Controllers/HealthController.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Serval.Client;
using SIL.XForge.Configuration;
using SIL.XForge.DataAccess;
using SIL.XForge.Realtime;
Expand All @@ -26,13 +24,11 @@ namespace SIL.XForge.Scripture.Controllers;
public class HealthController(
IOptions<AuthOptions> authOptions,
IExceptionHandler exceptionHandler,
IRealtimeService realtimeService,
ITranslationEnginesClient translationEnginesClient
IRealtimeService realtimeService
) : ControllerBase
{
public const int Status531MongoDown = 531;
public const int Status532RealtimeServerDown = 532;
public const int Status533ServalDown = 533;

/// <summary>
/// Executes the health check.
Expand All @@ -43,7 +39,6 @@ ITranslationEnginesClient translationEnginesClient
/// <response code="403">You do not have permission to view the health check.</response>
/// <response code="531">Mongo is down.</response>
/// <response code="532">The Realtime Server is down.</response>
/// <response code="533">Serval is down.</response>
[HttpPost]
public async Task<ActionResult<HealthCheckResponse>> HealthCheckAsync(
[FromHeader(Name = "X-Api-Key")] string apiKey
Expand Down Expand Up @@ -103,22 +98,6 @@ public async Task<ActionResult<HealthCheckResponse>> HealthCheckAsync(
response.RealtimeServer.Status = "The project was not retrieved from Mongo";
}

// Third, check Serval
try
{
stopWatch = Stopwatch.StartNew();
var translationEngines = await translationEnginesClient.GetAllAsync();
stopWatch.Stop();
response.Serval.Up = translationEngines.Any();
response.Serval.Time = stopWatch.ElapsedMilliseconds;
response.Serval.Status = response.Serval.Up ? "Success" : "No translation engines were retrieved";
}
catch (Exception e)
{
response.Serval.Status = e.Message;
exceptionHandler.ReportException(e);
}

// Calculate the status code and return the results
int statusCode;
if (!response.Mongo.Up)
Expand All @@ -129,10 +108,6 @@ public async Task<ActionResult<HealthCheckResponse>> HealthCheckAsync(
{
statusCode = Status532RealtimeServerDown;
}
else if (!response.Serval.Up)
{
statusCode = Status533ServalDown;
}
else
{
return Ok(response);
Expand Down
14 changes: 12 additions & 2 deletions src/SIL.XForge.Scripture/Models/HealthCheckResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ namespace SIL.XForge.Scripture.Models;
/// </summary>
public class HealthCheckResponse
{
/// <summary>
/// The <see cref="StatusSummary"/> when all systems are healthy.
/// </summary>
public const string Healthy = "All systems are healthy.";

/// <summary>
/// The <see cref="StatusSummary"/> when one or more systems are down.
/// </summary>
public const string Down = "Some systems are down.";

/// <summary>
/// Gets or sets the health check status for Mongo.
/// </summary>
Expand All @@ -16,7 +26,7 @@ public class HealthCheckResponse
public HealthCheckComponent RealtimeServer { get; } = new HealthCheckComponent();

/// <summary>
/// Gets or sets the health check status for Serval.
/// Gets the status summary.
/// </summary>
public HealthCheckComponent Serval { get; } = new HealthCheckComponent();
public string StatusSummary => Mongo.Up && RealtimeServer.Up ? Healthy : Down;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using NUnit.Framework;
using Serval.Client;
using SIL.XForge.Configuration;
using SIL.XForge.Realtime;
using SIL.XForge.Scripture.Models;
Expand Down Expand Up @@ -35,6 +34,7 @@ public async Task HealthCheck_FailureWithMongo()
Assert.AreEqual(HealthController.Status531MongoDown, objectResult.StatusCode);
var value = (HealthCheckResponse)objectResult.Value!;
Assert.IsFalse(value.Mongo.Up);
Assert.AreEqual(HealthCheckResponse.Down, value.StatusSummary);
}

[Test]
Expand All @@ -52,23 +52,7 @@ public async Task HealthCheck_FailureWithRealtimeServer()
Assert.AreEqual(HealthController.Status532RealtimeServerDown, objectResult.StatusCode);
var value = (HealthCheckResponse)objectResult.Value!;
Assert.IsFalse(value.RealtimeServer.Up);
}

[Test]
public async Task HealthCheck_FailureWithServal()
{
var env = new TestEnvironment();
env.TranslationEnginesClient.GetAllAsync().Throws(new ArgumentException());

// SUT
var actual = await env.Controller.HealthCheckAsync(ApiKey);

env.ExceptionHandler.Received(1).ReportException(Arg.Any<ArgumentException>());
Assert.IsInstanceOf<ObjectResult>(actual.Result);
var objectResult = (ObjectResult)actual.Result!;
Assert.AreEqual(HealthController.Status533ServalDown, objectResult.StatusCode);
var value = (HealthCheckResponse)objectResult.Value!;
Assert.IsFalse(value.Serval.Up);
Assert.AreEqual(HealthCheckResponse.Down, value.StatusSummary);
}

[Test]
Expand All @@ -92,6 +76,9 @@ public async Task HealthCheck_Success()
var actual = await env.Controller.HealthCheckAsync(ApiKey);

Assert.IsInstanceOf<OkObjectResult>(actual.Result);
var objectResult = (OkObjectResult)actual.Result!;
var value = (HealthCheckResponse)objectResult.Value!;
Assert.AreEqual(HealthCheckResponse.Healthy, value.StatusSummary);
}

private class TestEnvironment
Expand All @@ -104,8 +91,7 @@ public TestEnvironment()
var authOptions = Options.Create(new AuthOptions { HealthCheckApiKey = ApiKey });
ExceptionHandler = Substitute.For<IExceptionHandler>();
RealtimeService = Substitute.For<IRealtimeService>();
TranslationEnginesClient = Substitute.For<ITranslationEnginesClient>();
Controller = new HealthController(authOptions, ExceptionHandler, RealtimeService, TranslationEnginesClient);
Controller = new HealthController(authOptions, ExceptionHandler, RealtimeService);

// Set up a default project to return from Mongo
RealtimeService
Expand All @@ -118,16 +104,10 @@ public TestEnvironment()
document.IsLoaded.Returns(true);
connection.Get<SFProject>(Project01).Returns(document);
RealtimeService.ConnectAsync().Returns(Task.FromResult(connection));

// Set up a default translation engine to return from Serval
TranslationEnginesClient
.GetAllAsync()
.Returns(Task.FromResult<IList<TranslationEngine>>([new TranslationEngine()]));
}

public HealthController Controller { get; }
public IExceptionHandler ExceptionHandler { get; }
public IRealtimeService RealtimeService { get; }
public ITranslationEnginesClient TranslationEnginesClient { get; }
}
}

0 comments on commit 62ec49b

Please sign in to comment.