Skip to content

Commit

Permalink
Have lexbox API container check fw-headless health (#1192)
Browse files Browse the repository at this point in the history
Since fw-headless container isn't exposed to outside, but we might want
to know if it's healthy, we'll add code into the lexbox-api health check
to call the fw-headless health check and report lexbox-api's status as
unhealthy if fw-headless is not healthy. (Except on local dev, where
lexbox-api's status would just be Degraded so that editing fw-headless
code doesn't bring down the whole API server).
  • Loading branch information
rmunn authored Nov 7, 2024
1 parent 253403b commit b41478b
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 1 deletion.
8 changes: 8 additions & 0 deletions backend/FwHeadless/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@

var app = builder.Build();

// Add lexbox-version header to all requests
app.Logger.LogInformation("FwHeadless version: {version}", AppVersionService.Version);
app.Use(async (context, next) =>
{
context.Response.Headers["lexbox-version"] = AppVersionService.Version;
await next();
});

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
Expand Down
9 changes: 9 additions & 0 deletions backend/FwHeadless/Services/AppVersionService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Reflection;

namespace FwHeadless;

public static class AppVersionService
{
public static readonly string Version = typeof(AppVersionService).Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "dev";
}
7 changes: 7 additions & 0 deletions backend/LexBoxApi/Config/HealthChecksConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace LexBoxApi.Config;

public class HealthChecksConfig
{
public bool RequireFwHeadlessContainerVersionMatch { get; init; } = true;
public bool RequireHealthyFwHeadlessContainer { get; init; } = true;
}
9 changes: 8 additions & 1 deletion backend/LexBoxApi/LexBoxKernel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public static void AddLexBoxApi(this IServiceCollection services,
.BindConfiguration("Tus")
.ValidateDataAnnotations()
.ValidateOnStart();
services.AddOptions<HealthChecksConfig>()
.BindConfiguration("HealthChecks")
.ValidateDataAnnotations()
.ValidateOnStart();
services.AddHttpClient();
services.AddHttpContextAccessor();
services.AddMemoryCache();
Expand All @@ -57,6 +61,7 @@ public static void AddLexBoxApi(this IServiceCollection services,
services.AddScoped<IHgService, HgService>();
services.AddHostedService<HgService>();
services.AddTransient<HgWebHealthCheck>();
services.AddTransient<FwHeadlessHealthCheck>();
services.AddScoped<IIsLanguageForgeProjectDataLoader, IsLanguageForgeProjectDataLoader>();
services.AddResiliencePipeline<string, IReadOnlyDictionary<string, bool>>(IsLanguageForgeProjectDataLoader.ResiliencePolicyName, (builder, context) =>
{
Expand All @@ -69,7 +74,9 @@ public static void AddLexBoxApi(this IServiceCollection services,
if (environment.IsDevelopment())
services.AddHostedService<SwaggerValidationService>();
services.AddScheduledTasks(configuration);
services.AddHealthChecks().AddCheck<HgWebHealthCheck>("hgweb", HealthStatus.Unhealthy, ["hg"], TimeSpan.FromSeconds(5));
services.AddHealthChecks()
.AddCheck<HgWebHealthCheck>("hgweb", HealthStatus.Unhealthy, ["hg"], TimeSpan.FromSeconds(5))
.AddCheck<FwHeadlessHealthCheck>("fw-headless", HealthStatus.Unhealthy, ["fw-headless"], TimeSpan.FromSeconds(5));
services.AddSyncProxy();
AuthKernel.AddLexBoxAuth(services, configuration, environment);
services.AddLexGraphQL(environment);
Expand Down
37 changes: 37 additions & 0 deletions backend/LexBoxApi/Services/FwHeadlessHealthCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using LexBoxApi.Config;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;

namespace LexBoxApi.Services;

public class FwHeadlessHealthCheck(IHttpClientFactory clientFactory, IOptions<HealthChecksConfig> healthCheckOptions) : IHealthCheck
{
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context,
CancellationToken cancellationToken = new())
{
var http = clientFactory.CreateClient();
var fwHeadlessResponse = await http.GetAsync("http://fw-headless/api/healthz");
if (!fwHeadlessResponse.IsSuccessStatusCode)
{
if (healthCheckOptions.Value.RequireHealthyFwHeadlessContainer)
{
return HealthCheckResult.Unhealthy("fw-headless not repsonding to health check");
}
else
{
return HealthCheckResult.Degraded("fw-headless not repsonding to health check");
}
}
var fwHeadlessVersion = fwHeadlessResponse.Headers.GetValues("lexbox-version").FirstOrDefault();
if (healthCheckOptions.Value.RequireFwHeadlessContainerVersionMatch && string.IsNullOrEmpty(fwHeadlessVersion))
{
return HealthCheckResult.Degraded("fw-headless version check failed to return a value");
}
if (healthCheckOptions.Value.RequireFwHeadlessContainerVersionMatch && fwHeadlessVersion != AppVersionService.Version)
{
return HealthCheckResult.Degraded(
$"api version: '{AppVersionService.Version}' fw-headless version: '{fwHeadlessVersion}' mismatch");
}
return HealthCheckResult.Healthy();
}
}
4 changes: 4 additions & 0 deletions backend/LexBoxApi/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
"LfMergeTrustToken": "lf-merge-dev-trust-token",
"AutoUpdateLexEntryCountOnSendReceive": true
},
"HealthChecks": {
"RequireFwHeadlessContainerVersionMatch": false,
"RequireHealthyFwHeadlessContainer": false
},
"Authentication": {
"Jwt": {
"Secret": "d5cf1adc-16e6-4064-8041-4cfa00174210"
Expand Down
2 changes: 2 additions & 0 deletions deployment/develop/lexbox-deployment.patch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ spec:
value: "https://develop.lexbox.org"
- name: HgConfig__RequireContainerVersionMatch
value: "false"
- name: HealthChecksConfig__RequireFwHeadlessContainerVersionMatch
value: "false"
4 changes: 4 additions & 0 deletions deployment/local-dev/lexbox-deployment.patch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ spec:
valueFrom:
- name: CloudFlare__AllowDomain
value: "mailinator.com"
- name: HealthChecksConfig__RequireFwHeadlessContainerVersionMatch
value: "false"
- name: HealthChecksConfig__RequireHealthyFwHeadlessContainer
value: "false"
- name: Email__SmtpUser
value: 'maildev'
valueFrom:
Expand Down

0 comments on commit b41478b

Please sign in to comment.