diff --git a/FiMAdminApi.Data/Enums/DataSources.cs b/FiMAdminApi.Data/Enums/DataSources.cs index 9c77ca5..70bf8ce 100644 --- a/FiMAdminApi.Data/Enums/DataSources.cs +++ b/FiMAdminApi.Data/Enums/DataSources.cs @@ -5,5 +5,5 @@ public enum DataSources FrcEvents, BlueAlliance, FtcEvents, - OrangeAlliance + //OrangeAlliance } \ No newline at end of file diff --git a/FiMAdminApi/Clients/BlueAllianceDataClient.cs b/FiMAdminApi/Clients/BlueAllianceDataClient.cs index 2583786..eb47975 100644 --- a/FiMAdminApi/Clients/BlueAllianceDataClient.cs +++ b/FiMAdminApi/Clients/BlueAllianceDataClient.cs @@ -77,6 +77,15 @@ public Task> GetQualRankingsForEvent(Data.Models.Event evt) throw new NotImplementedException(); } + public async Task CheckHealth() + { + var resp = await PerformRequest(BuildGetRequest($"status")); + + if (resp.IsSuccessStatusCode) return null; + + return await resp.Content.ReadAsStringAsync(); + } + private static string GetDistrictKey(Season season, string districtName) { return char.IsDigit(districtName[0]) ? districtName : $"{season.StartTime.Year}{districtName}"; diff --git a/FiMAdminApi/Clients/ClientHealthCheck.cs b/FiMAdminApi/Clients/ClientHealthCheck.cs new file mode 100644 index 0000000..972d26b --- /dev/null +++ b/FiMAdminApi/Clients/ClientHealthCheck.cs @@ -0,0 +1,17 @@ +using FiMAdminApi.Data.Enums; +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace FiMAdminApi.Clients; + +public class ClientHealthCheck(IServiceProvider services, DataSources source) : IHealthCheck +{ + public async Task CheckHealthAsync(HealthCheckContext context, + CancellationToken cancellationToken = new()) + { + var dataClient = services.GetKeyedService(source); + if (dataClient is null) return HealthCheckResult.Degraded("Unable to create instance of client"); + + var result = await dataClient.CheckHealth(); + return result == null ? HealthCheckResult.Healthy() : HealthCheckResult.Degraded(result); + } +} \ No newline at end of file diff --git a/FiMAdminApi/Clients/ClientsStartupExtensions.cs b/FiMAdminApi/Clients/ClientsStartupExtensions.cs index 2071105..f90e8ff 100644 --- a/FiMAdminApi/Clients/ClientsStartupExtensions.cs +++ b/FiMAdminApi/Clients/ClientsStartupExtensions.cs @@ -1,4 +1,5 @@ using FiMAdminApi.Data.Enums; +using Microsoft.Extensions.Diagnostics.HealthChecks; namespace FiMAdminApi.Clients; @@ -17,4 +18,15 @@ public static void AddClients(this IServiceCollection services) services.AddKeyedScoped(DataSources.FtcEvents); services.AddScoped(); } + + public static IHealthChecksBuilder AddClientHealthChecks(this IHealthChecksBuilder builder) + { + foreach (var source in Enum.GetValues()) + { + builder.AddTypeActivatedCheck(source.ToString(), HealthStatus.Degraded, + new[] { "DataClient" }, source); + } + + return builder; + } } \ No newline at end of file diff --git a/FiMAdminApi/Clients/FrcEventsDataClient.cs b/FiMAdminApi/Clients/FrcEventsDataClient.cs index cb0c40c..cef745d 100644 --- a/FiMAdminApi/Clients/FrcEventsDataClient.cs +++ b/FiMAdminApi/Clients/FrcEventsDataClient.cs @@ -148,6 +148,15 @@ public async Task> GetQualRankingsForEvent(Data.Models.Event e }).ToList(); } + public async Task CheckHealth() + { + var resp = await PerformRequest(BuildGetRequest($"")); + + if (resp.IsSuccessStatusCode) return null; + + return await resp.Content.ReadAsStringAsync(); + } + private async Task> GetAndParseEvents(Season season, string? eventCode = null, string? districtCode = null) { var queryParams = new Dictionary(); diff --git a/FiMAdminApi/Clients/FtcEventsDataClient.cs b/FiMAdminApi/Clients/FtcEventsDataClient.cs index fa423d8..d3cc575 100644 --- a/FiMAdminApi/Clients/FtcEventsDataClient.cs +++ b/FiMAdminApi/Clients/FtcEventsDataClient.cs @@ -79,6 +79,15 @@ public Task> GetQualRankingsForEvent(Data.Models.Event evt) { throw new NotImplementedException(); } + + public async Task CheckHealth() + { + var resp = await PerformRequest(BuildGetRequest($"")); + + if (resp.IsSuccessStatusCode) return null; + + return await resp.Content.ReadAsStringAsync(); + } private static string GetSeason(Season season) { diff --git a/FiMAdminApi/Clients/IDataClient.cs b/FiMAdminApi/Clients/IDataClient.cs index f1f939b..7524bf6 100644 --- a/FiMAdminApi/Clients/IDataClient.cs +++ b/FiMAdminApi/Clients/IDataClient.cs @@ -15,4 +15,5 @@ public interface IDataClient public Task> GetQualScheduleForEvent(Data.Models.Event evt); public Task> GetQualResultsForEvent(Data.Models.Event evt); public Task> GetQualRankingsForEvent(Data.Models.Event evt); + public Task CheckHealth(); } \ No newline at end of file diff --git a/FiMAdminApi/Program.cs b/FiMAdminApi/Program.cs index 077e184..5a14101 100644 --- a/FiMAdminApi/Program.cs +++ b/FiMAdminApi/Program.cs @@ -37,8 +37,10 @@ builder.Services.AddDataProtection().PersistKeysToFileSystem(dirInfo); } -builder.Services.AddHealthChecks().AddNpgSql(builder.Configuration.GetConnectionString("fimDbConnection") ?? - throw new Exception("DB Connection string was null"), name: "Database"); +builder.Services.AddHealthChecks() + .AddNpgSql(builder.Configuration.GetConnectionString("fimDbConnection") ?? + throw new Exception("DB Connection string was null"), name: "Database") + .AddClientHealthChecks(); var key = builder.Configuration["Supabase:ServiceKey"]; var supabaseUrl = builder.Configuration["Supabase:BaseUrl"]; @@ -105,7 +107,9 @@ app.UseOutputCache(); app.UseApiConfiguration(); -app.UseHttpsRedirection(); +if (!bool.TryParse(app.Configuration["RUNNING_IN_CONTAINER"], out var inContainer) || + !inContainer) + app.UseHttpsRedirection(); app.UseCors(); app.UseApiDocumentation();