diff --git a/Rinkudesu.Services.Links/Rinkudesu.Services.Links.HealthChecks/DatabaseHealthCheck.cs b/Rinkudesu.Services.Links/Rinkudesu.Services.Links.HealthChecks/DatabaseHealthCheck.cs new file mode 100644 index 0000000..96e8c42 --- /dev/null +++ b/Rinkudesu.Services.Links/Rinkudesu.Services.Links.HealthChecks/DatabaseHealthCheck.cs @@ -0,0 +1,35 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Rinkudesu.Services.Links.Data; + +namespace Rinkudesu.Services.Links.HealthChecks +{ + [ExcludeFromCodeCoverage] + public class DatabaseHealthCheck : IHealthCheck + { + private readonly LinkDbContext _context; + + public DatabaseHealthCheck(LinkDbContext context) + { + this._context = context; + } + + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) + { + if (!await _context.Database.CanConnectAsync(cancellationToken)) + { + return HealthCheckResult.Unhealthy("Unable to connect to the database"); + } + var migrations = await _context.Database.GetPendingMigrationsAsync(cancellationToken); + if (migrations?.Any() ?? false) + { + return HealthCheckResult.Degraded("Database migrations are pending, functionality may be limited"); + } + return HealthCheckResult.Healthy(); + } + } +} \ No newline at end of file diff --git a/Rinkudesu.Services.Links/Rinkudesu.Services.Links.HealthChecks/Rinkudesu.Services.Links.HealthChecks.csproj b/Rinkudesu.Services.Links/Rinkudesu.Services.Links.HealthChecks/Rinkudesu.Services.Links.HealthChecks.csproj new file mode 100644 index 0000000..7de0e99 --- /dev/null +++ b/Rinkudesu.Services.Links/Rinkudesu.Services.Links.HealthChecks/Rinkudesu.Services.Links.HealthChecks.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp3.1 + enable + + + + + + + + + + + + diff --git a/Rinkudesu.Services.Links/Rinkudesu.Services.Links.sln b/Rinkudesu.Services.Links/Rinkudesu.Services.Links.sln index b614ba8..fad321c 100644 --- a/Rinkudesu.Services.Links/Rinkudesu.Services.Links.sln +++ b/Rinkudesu.Services.Links/Rinkudesu.Services.Links.sln @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rinkudesu.Services.Links.Mo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rinkudesu.Services.Links.Data", "Rinkudesu.Services.Links.Data\Rinkudesu.Services.Links.Data.csproj", "{26A791B3-4BAA-4F25-8AE7-AAF90BEC4594}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rinkudesu.Services.Links.HealthChecks", "Rinkudesu.Services.Links.HealthChecks\Rinkudesu.Services.Links.HealthChecks.csproj", "{E43C4BCB-2BB1-4602-A5BC-AB7216F679E2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -42,5 +44,9 @@ Global {26A791B3-4BAA-4F25-8AE7-AAF90BEC4594}.Debug|Any CPU.Build.0 = Debug|Any CPU {26A791B3-4BAA-4F25-8AE7-AAF90BEC4594}.Release|Any CPU.ActiveCfg = Release|Any CPU {26A791B3-4BAA-4F25-8AE7-AAF90BEC4594}.Release|Any CPU.Build.0 = Release|Any CPU + {E43C4BCB-2BB1-4602-A5BC-AB7216F679E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E43C4BCB-2BB1-4602-A5BC-AB7216F679E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E43C4BCB-2BB1-4602-A5BC-AB7216F679E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E43C4BCB-2BB1-4602-A5BC-AB7216F679E2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Dockerfile b/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Dockerfile index e796f44..dbcf0c5 100644 --- a/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Dockerfile +++ b/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Dockerfile @@ -12,4 +12,5 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS final EXPOSE 80 WORKDIR /app COPY --from=publish /app/publish . +HEALTHCHECK --interval=20s --start-period=5s --retries=3 CMD curl --fail http://localhost/health || exit 1 ENTRYPOINT ["dotnet", "Rinkudesu.Services.Links.dll"] diff --git a/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Rinkudesu.Services.Links.csproj b/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Rinkudesu.Services.Links.csproj index b1e7d8d..0a11d5c 100644 --- a/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Rinkudesu.Services.Links.csproj +++ b/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Rinkudesu.Services.Links.csproj @@ -5,8 +5,8 @@ Linux enable true - 0.0.0 - 0.0.0 + 0.2.0 + 0.2.0 Rinkudesu Rinkudesu @@ -43,6 +43,7 @@ + diff --git a/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Startup.cs b/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Startup.cs index 812ba21..56cdae0 100644 --- a/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Startup.cs +++ b/Rinkudesu.Services.Links/Rinkudesu.Services.Links/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.OpenApi.Models; using Rinkudesu.Services.Links.Data; using Rinkudesu.Services.Links.DataTransferObjects; +using Rinkudesu.Services.Links.HealthChecks; using Rinkudesu.Services.Links.Repositories; using Rinkudesu.Services.Links.Utilities; using Serilog; @@ -68,6 +69,8 @@ public void ConfigureServices(IServiceCollection services) var xmlPath = AppContext.BaseDirectory; c.IncludeXmlComments(Path.Combine(xmlPath, xmlName)); }); + + services.AddHealthChecks().AddCheck("Database health check"); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -91,7 +94,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseAuthorization(); - app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + app.UseEndpoints(endpoints => { + endpoints.MapControllers(); + endpoints.MapHealthChecks("/health"); + }); if (InputArguments.Current.ApplyMigrations) {