Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add akka.hosting #148

Merged
merged 18 commits into from
Dec 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,4 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
src/Akka.HealthCheck.Hosting.Web.Example/snapshots/snapshot-Akka.HealthCheck-df1340d9ebac45c1a96f100d8d667fd0-7-638068266586153191
30 changes: 27 additions & 3 deletions Akka.HealthCheck.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.14
# Visual Studio Version 17
VisualStudioVersion = 17.3.32825.248
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{79D71264-186B-4F62-8930-35DD9ECCAF3B}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -23,11 +23,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.HealthCheck.Cluster",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.HealthCheck.Cluster.Tests", "src\Akka.HealthCheck.Cluster.Tests\Akka.HealthCheck.Cluster.Tests.csproj", "{BA43AC18-0706-49D1-9B71-BA1EDC54ABC2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akkka.HealthCheck.Example", "src\Akkka.HealthCheck.Example\Akkka.HealthCheck.Example.csproj", "{6213BECB-4145-41BF-BAD0-C5D16412BBD5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.HealthCheck.Example", "src\Akka.HealthCheck.Example\Akka.HealthCheck.Example.csproj", "{6213BECB-4145-41BF-BAD0-C5D16412BBD5}"
ProjectSection(ProjectDependencies) = postProject
{642308A0-B6F7-4478-B286-3B8707A00F82} = {642308A0-B6F7-4478-B286-3B8707A00F82}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.HealthCheck.Hosting.Web.Example", "src\Akka.HealthCheck.Hosting.Web.Example\Akka.HealthCheck.Hosting.Web.Example.csproj", "{437E9BF1-75AE-4D1E-A6AF-37F799FAF8A3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.HealthCheck.Hosting", "src\Akka.HealthCheck.Hosting\Akka.HealthCheck.Hosting.csproj", "{E39E17B7-4412-436B-B233-92150080B28B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.HealthCheck.Hosting.Web", "src\Akka.HealthCheck.Hosting.Web\Akka.HealthCheck.Hosting.Web.csproj", "{9C69B5DB-FCAE-4528-A6CE-2C36DB2B806D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Akka.HealthCheck.Hosting.Web.Custom.Example", "src\Akka.HealthCheck.Hosting.Web.Custom.Example\Akka.HealthCheck.Hosting.Web.Custom.Example.csproj", "{1E2AD614-CF7D-4944-BB71-B9B829088157}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -62,6 +70,22 @@ Global
{6213BECB-4145-41BF-BAD0-C5D16412BBD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6213BECB-4145-41BF-BAD0-C5D16412BBD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6213BECB-4145-41BF-BAD0-C5D16412BBD5}.Release|Any CPU.Build.0 = Release|Any CPU
{437E9BF1-75AE-4D1E-A6AF-37F799FAF8A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{437E9BF1-75AE-4D1E-A6AF-37F799FAF8A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{437E9BF1-75AE-4D1E-A6AF-37F799FAF8A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{437E9BF1-75AE-4D1E-A6AF-37F799FAF8A3}.Release|Any CPU.Build.0 = Release|Any CPU
{E39E17B7-4412-436B-B233-92150080B28B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E39E17B7-4412-436B-B233-92150080B28B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E39E17B7-4412-436B-B233-92150080B28B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E39E17B7-4412-436B-B233-92150080B28B}.Release|Any CPU.Build.0 = Release|Any CPU
{9C69B5DB-FCAE-4528-A6CE-2C36DB2B806D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C69B5DB-FCAE-4528-A6CE-2C36DB2B806D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C69B5DB-FCAE-4528-A6CE-2C36DB2B806D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C69B5DB-FCAE-4528-A6CE-2C36DB2B806D}.Release|Any CPU.Build.0 = Release|Any CPU
{1E2AD614-CF7D-4944-BB71-B9B829088157}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E2AD614-CF7D-4944-BB71-B9B829088157}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E2AD614-CF7D-4944-BB71-B9B829088157}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E2AD614-CF7D-4944-BB71-B9B829088157}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
3 changes: 2 additions & 1 deletion Akka.HealthCheck.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
Copyright (C) 2015 - $CURRENT_YEAR$ Petabridge, LLC <https://petabridge.com>
</copyright>
-----------------------------------------------------------------------</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/PsiConfigurationSettingsKey/CustomLocation/@EntryValue">C:\Users\aaron\AppData\Local\JetBrains\Transient\ReSharperPlatformVs15\v11_10617ea1\SolutionCaches</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/Environment/Hierarchy/PsiConfigurationSettingsKey/CustomLocation/@EntryValue">C:\Users\aaron\AppData\Local\JetBrains\Transient\ReSharperPlatformVs15\v11_10617ea1\SolutionCaches</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Liveness/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
5 changes: 5 additions & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ Target "RunTests" (fun _ ->
let projects =
match (isWindows) with
| true -> !! "./src/**/*.Tests.csproj"
-- "./src/**/*.Example.csproj"
| _ -> !! "./src/**/*.Tests.csproj" // if you need to filter specs for Linux vs. Windows, do it here
-- "./src/**/*.Example.csproj"

let runSingleProject project =
let arguments =
Expand All @@ -144,7 +146,9 @@ Target "RunTestsNet" (fun _ ->
let projects =
match (isWindows) with
| true -> !! "./src/**/*.Tests.csproj"
-- "./src/**/*.Example.csproj"
| _ -> !! "./src/**/*.Tests.csproj" // if you need to filter specs for Linux vs. Windows, do it here
-- "./src/**/*.Example.csproj"

let runSingleProject project =
let arguments =
Expand Down Expand Up @@ -243,6 +247,7 @@ Target "CreateNuget" (fun _ ->
let projects = !! "src/**/*.csproj"
-- "src/**/*Tests.csproj" // Don't publish unit tests
-- "src/**/*Tests*.csproj"
-- "src/**/*.Example.csproj" // Don't publish example projects

let runSingleProject project =
DotNetCli.Pack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<PropertyGroup>
<TargetFrameworks>$(NetStandardLibVersion);$(NetLibVersion)</TargetFrameworks>
<Description>Akka.NET and Akka.Cluster healthchecks for environments like K8s, AWS, Azure, Pivotal Cloud Foundry, and more.</Description>
<LangVersion>9.0</LangVersion>
</PropertyGroup>


Expand Down
2 changes: 1 addition & 1 deletion src/Akka.HealthCheck.Cluster/ClusterLivenessProbe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public sealed class ClusterLivenessProbe : ReceiveActor
public ClusterLivenessProbe() : this(DefaultClusterLivenessStatus)
{
}

public ClusterLivenessProbe(LivenessStatus livenessStatus)
{
_livenessStatus = livenessStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Akka.HealthCheck;
using System;

namespace Akkka.HealthCheck.Example
namespace Akka.HealthCheck.Example
{
class Program
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Akka.HealthCheck.Hosting.Web\Akka.HealthCheck.Hosting.Web.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// -----------------------------------------------------------------------
// <copyright file="CustomHealthCheckReadinessProbe.cs" company="Petabridge, LLC">
// Copyright (C) 2015 - 2022 Petabridge, LLC <https://petabridge.com>
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Configuration;
using Akka.HealthCheck.Liveness;
using Akka.HealthCheck.Readiness;
using Microsoft.Extensions.Diagnostics.HealthChecks;

namespace Akka.HealthCheck.Hosting.Web.Custom.Example;

public class CustomHealthCheckReadinessProbe: IHealthCheck
{
private readonly IActorRef _probe;

public CustomHealthCheckReadinessProbe(ActorSystem system)
{
if (!AkkaHealthCheck.For(system).ReadinessProbes.TryGetValue("custom", out _probe!))
{
throw new ConfigurationException("Could not find readiness actor with key 'custom'.");
}
}

public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken())
{
try
{
var status = await _probe.Ask<ReadinessStatus>(
message: GetCurrentReadiness.Instance,
cancellationToken: cancellationToken);

return status.IsReady
? HealthCheckResult.Healthy("healthy", new Dictionary<string, object> { ["message"] = status.StatusMessage })
: HealthCheckResult.Unhealthy("unhealthy", data: new Dictionary<string, object> { ["message"] = status.StatusMessage });
}
catch (Exception e)
{
return HealthCheckResult.Unhealthy("unhealthy", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// -----------------------------------------------------------------------
// <copyright file="CustomProbe.cs" company="Petabridge, LLC">
// Copyright (C) 2015 - 2022 Petabridge, LLC <https://petabridge.com>
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using Akka.Actor;
using Akka.HealthCheck.Readiness;

namespace Akka.HealthCheck.Hosting.Web.Custom.Example;

public class CustomReadinessProbe: ReceiveActor, IWithTimers
{
private readonly string _timerKey = "periodic-timer";
private readonly string _timerSignal = "do-check";

private ReadinessStatus _readinessStatus;
private readonly HashSet<IActorRef> _subscribers = new ();

public CustomReadinessProbe() : this(new ReadinessStatus(false))
{
}

public CustomReadinessProbe(ReadinessStatus readinessStatus)
{
_readinessStatus = readinessStatus;

Receive<GetCurrentReadiness>(_ => {
Sender.Tell(_readinessStatus);
});

Receive<SubscribeToReadiness>(s =>
{
_subscribers.Add(s.Subscriber);
Context.Watch(s.Subscriber);
s.Subscriber.Tell(_readinessStatus);
});

Receive<UnsubscribeFromReadiness>(u =>
{
_subscribers.Remove(u.Subscriber);
Context.Unwatch(u.Subscriber);
});

Receive<Terminated>(t => {
_subscribers.Remove(t.ActorRef);
});

ReceiveAsync<string>(
s => s == "do-check",
async _ =>
{
// TODO: insert probe check here
_readinessStatus = new ReadinessStatus(true);
});
}

protected override void PreStart()
{
Timers.StartPeriodicTimer(_timerKey, _timerSignal, TimeSpan.FromSeconds(1));
}

public ITimerScheduler Timers { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// -----------------------------------------------------------------------
// <copyright file="CustomProbeProvider.cs" company="Petabridge, LLC">
// Copyright (C) 2015 - 2022 Petabridge, LLC <https://petabridge.com>
// </copyright>
// -----------------------------------------------------------------------

using Akka.Actor;

namespace Akka.HealthCheck.Hosting.Web.Custom.Example;

public sealed class CustomReadinessProbeProvider: ProbeProviderBase
{
public override Props ProbeProps => Props.Create(() => new CustomReadinessProbe());

public CustomReadinessProbeProvider(ActorSystem system) : base(system)
{
}
}
32 changes: 32 additions & 0 deletions src/Akka.HealthCheck.Hosting.Web.Custom.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Akka.HealthCheck.Hosting;
using Akka.HealthCheck.Hosting.Web.Custom.Example;
using Akka.Hosting;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;

var webBuilder = WebApplication.CreateBuilder(args);

webBuilder.Services
.AddHealthChecks()
.AddCheck<CustomHealthCheckReadinessProbe>("akka-custom-readiness", HealthStatus.Unhealthy, new [] { "akka", "ready", "custom" });

webBuilder.Services
.AddAkka("actor-system", (builder, serviceProvider) =>
{
builder
.WithHealthCheck(opt =>
{
opt.AddReadinessProvider<CustomReadinessProbeProvider>("custom");
});
});

var app = webBuilder.Build();

app.MapHealthChecks("/healthz/akka/ready/custom", new HealthCheckOptions
{
Predicate = healthCheck => healthCheck.Tags.IsSupersetOf(new [] { "akka", "ready", "custom" })
});

await app.RunAsync();
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\common.props" />

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Akka.Cluster.Hosting" Version="$(AkkaHostingVersion)" />
<PackageReference Include="Akka.Hosting" Version="$(AkkaHostingVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Akka.HealthCheck.Hosting.Web\Akka.HealthCheck.Hosting.Web.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Remove="snapshots\**" />
<EmbeddedResource Remove="snapshots\**" />
<None Remove="snapshots\**" />
<Content Remove="snapshots\**" />
</ItemGroup>
</Project>
43 changes: 43 additions & 0 deletions src/Akka.HealthCheck.Hosting.Web.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Akka.Cluster.Hosting;
using Akka.Hosting;

namespace Akka.HealthCheck.Hosting.Web.Example;

public static class Program
{
public static async Task Main(string[] args)
{
var webBuilder = WebApplication.CreateBuilder(args);

webBuilder.Services
// Register all of the health check service with IServiceCollection
.WithAkkaHealthCheck(HealthCheckType.All)
.AddAkka("actor-system", (builder, serviceProvider) =>
{
builder
.AddHocon("akka.cluster.min-nr-of-members = 1", HoconAddMode.Prepend)
.WithClustering()
// Automatically detects which health checks were registered inside the health check middleware and starts them
.WithWebHealthCheck(serviceProvider)
.AddStartup((system, _) =>
{
var cluster = Akka.Cluster.Cluster.Get(system);
cluster.Join(cluster.SelfAddress);
});
});

var app = webBuilder.Build();

// Automatically detects which health checks were registered inside the health check middleware and maps their routes
app.MapAkkaHealthCheckRoutes(
prependPath:"/health",
optionConfigure: opt =>
{
// Use a custom response writer to output a json of all reported statuses
opt.ResponseWriter = Helper.JsonResponseWriter;
});

await app.RunAsync();
}

}
Loading