Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
1st version of healthcheck & webstatus
Browse files Browse the repository at this point in the history
  • Loading branch information
eiximenis committed Mar 23, 2017
1 parent 9893c29 commit 561ba3b
Show file tree
Hide file tree
Showing 104 changed files with 24,876 additions and 6 deletions.
13 changes: 12 additions & 1 deletion docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,15 @@ services:
- SA_PASSWORD=Pass@word
- ACCEPT_EULA=Y
ports:
- "5433:1433"
- "5433:1433"

webstatus:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:5107
- CatalogUrl=http://catalog.api:5101/hc
- OrderingUrl=http://ordering.api:5102/hc
- BasketUrl=http://basket.api:5103/hc
- IdentityUrl=http://10.0.75.1:5105/hc
ports:
- "5107:5107"
12 changes: 11 additions & 1 deletion docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,14 @@ services:
- SA_PASSWORD=Pass@word
- ACCEPT_EULA=Y
ports:
- "5433:1433"
- "5433:1433"

webstatus:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- CatalogUrl=http://catalog.api:5101/hc
- OrderingUrl=http://ordering.api:5102/hc
- BasketUrl=http://basket.api:5103/hc
- IdentityUrl=http://10.0.75.1:5105/hc
ports:
- "5107:5107"
15 changes: 15 additions & 0 deletions docker-compose.vs.debug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,18 @@ services:
entrypoint: tail -f /dev/null
labels:
- "com.microsoft.visualstudio.targetoperatingsystem=linux"

webstatus:
image: eshop/webstatus:dev
build:
args:
source: ${DOCKER_BUILD_SOURCE}
environment:
- DOTNET_USE_POLLING_FILE_WATCHER=1
volumes:
- ./src/Web/WebStatus:/app
- ~/.nuget/packages:/root/.nuget/packages:ro
- ~/clrdbg:/clrdbg:ro
entrypoint: tail -f /dev/null
labels:
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
10 changes: 10 additions & 0 deletions docker-compose.vs.release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,13 @@ services:
entrypoint: tail -f /dev/null
labels:
- "com.microsoft.visualstudio.targetoperatingsystem=linux"

webstatus:
build:
args:
source: ${DOCKER_BUILD_SOURCE}
volumes:
- ~/clrdbg:/clrdbg:ro
entrypoint: tail -f /dev/null
labels:
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
6 changes: 6 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,9 @@ services:
image: rabbitmq
ports:
- "5672:5672"

webstatus:
image: eshop/webstatus
build:
context: ./src/Web/WebStatus
dockerfile: Dockerfile
213 changes: 210 additions & 3 deletions eShopOnContainers-ServicesAndWebApps.sln

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.HealthChecks;
using Newtonsoft.Json;

namespace Microsoft.AspNetCore.HealthChecks
{
public class HealthCheckMiddleware
{
private RequestDelegate _next;
private string _path;
private int? _port;
private IHealthCheckService _service;

public HealthCheckMiddleware(RequestDelegate next, IHealthCheckService service, int port)
{
_port = port;
_service = service;
_next = next;
}

public HealthCheckMiddleware(RequestDelegate next, IHealthCheckService service, string path)
{
_path = path;
_service = service;
_next = next;
}

public async Task Invoke(HttpContext context)
{
if (IsHealthCheckRequest(context))
{
var result = await _service.CheckHealthAsync();
var status = result.CheckStatus;

if (status != CheckStatus.Healthy)
context.Response.StatusCode = 503;

context.Response.Headers.Add("content-type", "application/json");
await context.Response.WriteAsync(JsonConvert.SerializeObject(new { status = status.ToString() }));
return;
}
else
{
await _next.Invoke(context);
}
}

private bool IsHealthCheckRequest(HttpContext context)
{
if (_port.HasValue)
{
var connInfo = context.Features.Get<IHttpConnectionFeature>();
if (connInfo.LocalPort == _port)
return true;
}

if (context.Request.Path == _path)
return true;

return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;

namespace Microsoft.AspNetCore.HealthChecks
{
public class HealthCheckStartupFilter : IStartupFilter
{
private string _path;
private int? _port;

public HealthCheckStartupFilter(int port)
{
_port = port;
}

public HealthCheckStartupFilter(string path)
{
_path = path;
}

public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return app =>
{
if (_port.HasValue)
app.UseMiddleware<HealthCheckMiddleware>(_port);
else
app.UseMiddleware<HealthCheckMiddleware>(_path);
next(app);
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNetCore.HealthChecks;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Hosting
{
public static class HealthCheckWebHostBuilderExtension
{
public static IWebHostBuilder UseHealthChecks(this IWebHostBuilder builder, int port)
{
Guard.ArgumentValid(port > 0 && port < 65536, nameof(port), "Port must be a value between 1 and 65535");

builder.ConfigureServices(services =>
{
var existingUrl = builder.GetSetting(WebHostDefaults.ServerUrlsKey);
builder.UseSetting(WebHostDefaults.ServerUrlsKey, $"{existingUrl};http://localhost:{port}");
services.AddSingleton<IStartupFilter>(new HealthCheckStartupFilter(port));
});
return builder;
}

public static IWebHostBuilder UseHealthChecks(this IWebHostBuilder builder, string path)
{
Guard.ArgumentNotNull(nameof(path), path);
// REVIEW: Is there a better URL path validator somewhere?
Guard.ArgumentValid(!path.Contains("?"), nameof(path), "Path cannot contain query string values");
Guard.ArgumentValid(path.StartsWith("/"), nameof(path), "Path should start with /");

builder.ConfigureServices(services => services.AddSingleton<IStartupFilter>(new HealthCheckStartupFilter(path)));
return builder;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.Extensions.HealthChecks;

namespace Microsoft.AspNetCore.Hosting
{
public static class HealthCheckWebHostExtensions
{
private const int DEFAULT_TIMEOUT_SECONDS = 300;

public static void RunWhenHealthy(this IWebHost webHost)
{
webHost.RunWhenHealthy(TimeSpan.FromSeconds(DEFAULT_TIMEOUT_SECONDS));
}

public static void RunWhenHealthy(this IWebHost webHost, TimeSpan timeout)
{
var healthChecks = webHost.Services.GetService(typeof(IHealthCheckService)) as IHealthCheckService;

var loops = 0;
do
{
var checkResult = healthChecks.CheckHealthAsync().Result;
if (checkResult.CheckStatus == CheckStatus.Healthy)
{
webHost.Run();
break;
}

System.Threading.Thread.Sleep(1000);
loops++;

} while (loops < timeout.TotalSeconds);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\common\Guard.cs" Link="Internal\Guard.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="1.0.2" />
<ProjectReference Include="..\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Data;
using System.Data.SqlClient;

namespace Microsoft.Extensions.HealthChecks
{
public static class HealthCheckBuilderDataExtensions
{
public static HealthCheckBuilder AddSqlCheck(this HealthCheckBuilder builder, string name, string connectionString)
{
builder.AddCheck($"SqlCheck({name})", async () =>
{
try
{
//TODO: There is probably a much better way to do this.
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = "SELECT 1";
var result = (int)await command.ExecuteScalarAsync().ConfigureAwait(false);
if (result == 1)
{
return HealthCheckResult.Healthy($"SqlCheck({name}): Healthy");
}
return HealthCheckResult.Unhealthy($"SqlCheck({name}): Unhealthy");
}
}
}
catch(Exception ex)
{
return HealthCheckResult.Unhealthy($"SqlCheck({name}): Exception during check: {ex.GetType().FullName}");
}
});

return builder;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\common\Guard.cs" Link="Internal\Guard.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Data.SqlClient" Version="4.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.Extensions.HealthChecks
{
public enum CheckStatus
{
Unknown,
Unhealthy,
Healthy,
Warning
}
}
Loading

0 comments on commit 561ba3b

Please sign in to comment.