diff --git a/SS14.Labeller/HealthChecks/GitHubApiHealthCheck.cs b/SS14.Labeller/HealthChecks/GitHubApiHealthCheck.cs new file mode 100644 index 0000000..37be13b --- /dev/null +++ b/SS14.Labeller/HealthChecks/GitHubApiHealthCheck.cs @@ -0,0 +1,56 @@ +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using SS14.Labeller.GitHubApi; + +namespace SS14.Labeller.HealthChecks; + +public class GitHubApiKeyHealthCheck(IHttpClientFactory httpClientFactory, IMemoryCache cache) : IHealthCheck +{ + public async Task CheckHealthAsync( + HealthCheckContext context, + CancellationToken cancellationToken = default + ) + { + var result = await cache.GetOrCreateAsync( + "GHKeyHealthCheck", + async entry => + { + entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5); + return await CheckHealthAsyncInternal(cancellationToken); + } + ); + + return result; + } + + private async Task CheckHealthAsyncInternal(CancellationToken cancellationToken) + { + try + { + var client = httpClientFactory.CreateClient(nameof(IGitHubApiClient)); + + // Make a simple, low-impact request to verify the key + var response = await client.GetAsync("https://api.github.com/user", cancellationToken); + + if (response.IsSuccessStatusCode) + { + return HealthCheckResult.Healthy("GitHub API key is valid."); + } + + if (response.StatusCode is System.Net.HttpStatusCode.Unauthorized or System.Net.HttpStatusCode.Forbidden) + { + return HealthCheckResult.Unhealthy("GitHub API key is invalid or lacks necessary permissions."); + } + + return HealthCheckResult.Degraded($"GitHub API returned an unexpected status code: {response.StatusCode}"); + } + catch (HttpRequestException ex) + { + return HealthCheckResult.Unhealthy("Failed to connect to GitHub API", exception: ex); + } + catch (Exception ex) + { + return HealthCheckResult.Unhealthy("An unexpected error occurred during GitHub API key health check", exception: ex); + } + } +} \ No newline at end of file diff --git a/SS14.Labeller/Program.cs b/SS14.Labeller/Program.cs index 6eaa19a..d3f77ba 100644 --- a/SS14.Labeller/Program.cs +++ b/SS14.Labeller/Program.cs @@ -1,11 +1,5 @@ using Dapper; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; -using SS14.Labeller.Configuration; using SS14.Labeller.Endpoints; -using SS14.Labeller.Handlers; -using SS14.Labeller.Middlewares; -using SS14.Labeller.Models; [module:DapperAot] @@ -31,6 +25,9 @@ public static void Main(string[] args) app.UseHttpLogging(); app.MapGet("/", () => Results.Ok("Nik is a cat!")); + + app.MapHealthChecks("/health"); + app.MapGithubWebhook(); app.Run(); diff --git a/SS14.Labeller/Registry.cs b/SS14.Labeller/Registry.cs index 7757d5d..df9324b 100644 --- a/SS14.Labeller/Registry.cs +++ b/SS14.Labeller/Registry.cs @@ -7,6 +7,7 @@ using SS14.Labeller.Labelling; using SS14.Labeller.Repository; using System.Net.Http.Headers; +using SS14.Labeller.HealthChecks; using Polly; using Polly.Extensions.Http; @@ -80,6 +81,14 @@ public static void RegisterDependencies(this IServiceCollection service, IConfig sp => sp.GetServices() .ToDictionary(x => x.CanHandleType) ); + + service.AddHealthChecks() + .AddCheck( + "GitHub API Key", + tags: ["github", "api-key"] + ); + + service.AddMemoryCache(); } private static IAsyncPolicy GetDiscourseRetryPolicy(IServiceProvider sp)