diff --git a/.github/workflows/release-healthcheck-package.yml b/.github/workflows/release-healthcheck-package.yml new file mode 100644 index 0000000..c43df1d --- /dev/null +++ b/.github/workflows/release-healthcheck-package.yml @@ -0,0 +1,27 @@ +name: SOFTURE COMMON HEALTHCHECK - RELEASE NEW VERSION TO NUGET.ORG + +on: + release: + types: [released] + +jobs: + publishing: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: ⚙️ Install dotnet + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 8.0.100 + + - name: 🔗 Restore dependencies + run: dotnet restore ./API + + - name: 📂 Create new nuget package + run: dotnet pack --no-restore -c Release -o ./artifacts /p:PackageVersion=${{ github.ref_name }} /p:Version=${{ github.ref_name }} ./COMMON/SOFTURE.Common.HealthCheck/SOFTURE.Common.HealthCheck.csproj + continue-on-error: false + + - name: 🚀 Push new nuget package + run: dotnet nuget push ./artifacts/SOFTURE.Common.HealthCheck.${{ github.ref_name }}.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/API/API.sln b/API/API.sln index 1a471c5..41db50d 100644 --- a/API/API.sln +++ b/API/API.sln @@ -1,10 +1,16 @@  Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SOFTURE.Common.HealthCheck", "SOFTURE.Common.HealthCheck\SOFTURE.Common.HealthCheck.csproj", "{5D6F7130-2C65-4BB3-A81C-5975E9CEEE9A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5D6F7130-2C65-4BB3-A81C-5975E9CEEE9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D6F7130-2C65-4BB3-A81C-5975E9CEEE9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D6F7130-2C65-4BB3-A81C-5975E9CEEE9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D6F7130-2C65-4BB3-A81C-5975E9CEEE9A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/API/SOFTURE.Common.HealthCheck/Core/CheckBase.cs b/API/SOFTURE.Common.HealthCheck/Core/CheckBase.cs new file mode 100644 index 0000000..5bff517 --- /dev/null +++ b/API/SOFTURE.Common.HealthCheck/Core/CheckBase.cs @@ -0,0 +1,36 @@ +using CSharpFunctionalExtensions; +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace SOFTURE.Common.HealthCheck.Core; + +public abstract class CheckBase() : ICommonHealthCheck +{ + private string Name => GetType().Name.Replace("HealthCheck", string.Empty); + + protected readonly CancellationTokenSource Cts = new(TimeSpan.FromSeconds(2)); + + protected abstract Task Check(); + + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken ct = new()) + { + var data = new Dictionary(); + + try + { + var result = await Check(); + + if (result.IsFailure) + data.Add("Error", result.Error); + + return result.IsSuccess + ? HealthCheckResult.Healthy($"{Name} is available") + : HealthCheckResult.Unhealthy($"{Name} is not available", data: data); + } + catch (Exception ex) + { + data.Add("Exception", ex.InnerException?.Message ?? ex.Message); + + return HealthCheckResult.Unhealthy($"{Name} is not available", data: data); + } + } +} \ No newline at end of file diff --git a/API/SOFTURE.Common.HealthCheck/Core/Consts.cs b/API/SOFTURE.Common.HealthCheck/Core/Consts.cs new file mode 100644 index 0000000..57d0ea9 --- /dev/null +++ b/API/SOFTURE.Common.HealthCheck/Core/Consts.cs @@ -0,0 +1,6 @@ +namespace SOFTURE.Common.HealthCheck.Core; + +internal static class Consts +{ + public const string HealthCheckTag = "softure"; +} \ No newline at end of file diff --git a/API/SOFTURE.Common.HealthCheck/Core/ICommonHealthCheck.cs b/API/SOFTURE.Common.HealthCheck/Core/ICommonHealthCheck.cs new file mode 100644 index 0000000..ce38d57 --- /dev/null +++ b/API/SOFTURE.Common.HealthCheck/Core/ICommonHealthCheck.cs @@ -0,0 +1,7 @@ +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace SOFTURE.Common.HealthCheck.Core; + +public interface ICommonHealthCheck : IHealthCheck +{ +} \ No newline at end of file diff --git a/API/SOFTURE.Common.HealthCheck/DependencyInjection.cs b/API/SOFTURE.Common.HealthCheck/DependencyInjection.cs new file mode 100644 index 0000000..386e032 --- /dev/null +++ b/API/SOFTURE.Common.HealthCheck/DependencyInjection.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using SOFTURE.Common.HealthCheck.Core; +using SOFTURE.Common.HealthCheck.Presentation; + +namespace SOFTURE.Common.HealthCheck +{ + public static class DependencyInjection + { + public static IServiceCollection AddCommonHealthCheck(this IServiceCollection services) + where THealthCheck : CheckBase, ICommonHealthCheck + { + var healthCheckName = typeof(THealthCheck).Name.Replace("HealthCheck", string.Empty); + + services.AddHealthChecks() + .AddCheck(healthCheckName, tags: new[] { Consts.HealthCheckTag }); + + return services; + } + + public static WebApplication MapCommonHealthChecks(this WebApplication app) + { + app.MapHealthChecks("/hc", new HealthCheckOptions + { + ResponseWriter = Writer.WriteResponse, + Predicate = healthCheck => healthCheck.Tags.Contains(Consts.HealthCheckTag) + }); + + return app; + } + } +} \ No newline at end of file diff --git a/API/SOFTURE.Common.HealthCheck/Presentation/Writer.cs b/API/SOFTURE.Common.HealthCheck/Presentation/Writer.cs new file mode 100644 index 0000000..176ccfd --- /dev/null +++ b/API/SOFTURE.Common.HealthCheck/Presentation/Writer.cs @@ -0,0 +1,48 @@ +using System.Text; +using System.Text.Json; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace SOFTURE.Common.HealthCheck.Presentation; + +internal static class Writer +{ + internal static Task WriteResponse(HttpContext context, HealthReport healthReport) + { + context.Response.ContentType = "application/json; charset=utf-8"; + + var options = new JsonWriterOptions { Indented = true }; + + using var memoryStream = new MemoryStream(); + using (var jsonWriter = new Utf8JsonWriter(memoryStream, options)) + { + jsonWriter.WriteStartObject(); + jsonWriter.WriteString("Status", healthReport.Status.ToString()); + jsonWriter.WriteStartObject("Results"); + + foreach (var healthReportEntry in healthReport.Entries) + { + jsonWriter.WriteStartObject(healthReportEntry.Key); + jsonWriter.WriteString("Status", healthReportEntry.Value.Status.ToString()); + jsonWriter.WriteString("Description", healthReportEntry.Value.Description); + + if (healthReportEntry.Value.Data.Count > 0) + { + jsonWriter.WriteStartObject("Information"); + + foreach(var data in healthReportEntry.Value.Data) + jsonWriter.WriteString(data.Key, data.Value.ToString()); + + jsonWriter.WriteEndObject(); + } + + jsonWriter.WriteEndObject(); + } + + jsonWriter.WriteEndObject(); + jsonWriter.WriteEndObject(); + } + + return context.Response.WriteAsync(Encoding.UTF8.GetString(memoryStream.ToArray())); + } +} \ No newline at end of file diff --git a/API/SOFTURE.Common.HealthCheck/SOFTURE.Common.HealthCheck.csproj b/API/SOFTURE.Common.HealthCheck/SOFTURE.Common.HealthCheck.csproj new file mode 100644 index 0000000..e20c02b --- /dev/null +++ b/API/SOFTURE.Common.HealthCheck/SOFTURE.Common.HealthCheck.csproj @@ -0,0 +1,41 @@ + + + + net8.0 + enable + enable + + + + + + + + + SOFTURE.Common.HealthCheck + $(AssemblyName) + enable + latest + $(AssemblyName) + SOFTURE + Copyright (c) 2024 $(Authors) + SOFTURE - HealtCheck + true + true + $(AssemblyName) + LICENSE + https://github.com/SOFTURE/API + README.md + See $(PackageProjectUrl)/blob/master/CHANGELOG.md for release notes. + SOFTURE + true + Git + $(PackageProjectUrl) + + + + + + + +