Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc2de76963 | ||
|
|
13382531ce |
@@ -32,4 +32,8 @@ COPY --from=build --chown=1654:1654 /out/ ./
|
||||
USER 1654:1654
|
||||
EXPOSE 8080/tcp
|
||||
EXPOSE 9050/udp
|
||||
# The chiseled image has no shell or curl; the probe re-enters the server
|
||||
# assembly in --health-probe mode and reports through the exit code.
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD ["dotnet", "FinalFactory.Rendezvous.Server.dll", "--health-probe"]
|
||||
ENTRYPOINT ["dotnet", "FinalFactory.Rendezvous.Server.dll"]
|
||||
|
||||
@@ -24,6 +24,12 @@ services:
|
||||
hard: 4096
|
||||
stop_grace_period: 40s
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "dotnet", "FinalFactory.Rendezvous.Server.dll", "--health-probe"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
environment:
|
||||
ASPNETCORE_ENVIRONMENT: Production
|
||||
ASPNETCORE_HTTP_PORTS: "8080"
|
||||
@@ -34,4 +40,8 @@ services:
|
||||
- ${RENDEZVOUS_SECRET_SOURCE:-./secrets/signing-key}:/run/secrets/rendezvous-signing-key:ro
|
||||
ports:
|
||||
- "127.0.0.1:${RENDEZVOUS_HTTP_HOST_PORT:-8080}:8080/tcp"
|
||||
# 9050 is also a common game-client default UDP port. Evaluating this
|
||||
# service on the same machine as a running game client can silently
|
||||
# collide; remap with RENDEZVOUS_UDP_HOST_PORT and keep the advertised
|
||||
# Rendezvous:Deployment:PublicUdpPort in appsettings matched to it.
|
||||
- "${RENDEZVOUS_UDP_HOST_PORT:-9050}:9050/udp"
|
||||
|
||||
@@ -31,8 +31,11 @@ must be repeated from the public feed.
|
||||
|
||||
## Proven local path
|
||||
|
||||
The SpaceGame host and client each create one caller-owned `NetManager`, set its
|
||||
three gameplay QoS channels before `Start`, and give the same manager and
|
||||
The SpaceGame host and client each create one caller-owned `NetManager`,
|
||||
configure any additional gameplay QoS channels before `Start` (the pilot
|
||||
harness used three; current SpaceGame source uses LiteNetLib's default single
|
||||
channel — both peers must simply agree, because a `ChannelsCount` mismatch
|
||||
fails the connection silently), and give the same manager and
|
||||
`RendezvousNetListener` to the coordinator. Rendezvous authenticates discovery,
|
||||
join authorization, host presence, mediation, and connection outcome reporting.
|
||||
After traversal, SpaceGame performs a separate audience-bound admission exchange
|
||||
|
||||
@@ -57,11 +57,13 @@
|
||||
<Compile Include="Diagnostics/DiagnosticDashboardOptions.cs" />
|
||||
<Compile Include="Http/ContractEndpoints.cs" />
|
||||
<Compile Include="Http/RendezvousExceptionHandler.cs" />
|
||||
<Compile Include="Http/RootEndpoints.cs" />
|
||||
<Compile Include="JoinAttempts/JoinAttemptCursorCodec.cs" />
|
||||
<Compile Include="JoinAttempts/JoinAttemptService.cs" />
|
||||
<Compile Include="Observability/AuditOptions.cs" />
|
||||
<Compile Include="Observability/AuditTrail.cs" />
|
||||
<Compile Include="Observability/HealthEndpoints.cs" />
|
||||
<Compile Include="Observability/HealthProbe.cs" />
|
||||
<Compile Include="Observability/PrometheusMetricsEndpoint.cs" />
|
||||
<Compile Include="Observability/RendezvousReadiness.cs" />
|
||||
<Compile Include="Observability/RendezvousTelemetry.cs" />
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using FinalFactory.Rendezvous.Contracts;
|
||||
using FinalFactory.Rendezvous.Server.Diagnostics;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace FinalFactory.Rendezvous.Server.Http;
|
||||
|
||||
internal static class RootEndpoints
|
||||
{
|
||||
public static IEndpointRouteBuilder MapRootEndpoint(
|
||||
this IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
endpoints.MapGet("/", ServeRoot).ExcludeFromDescription();
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private static IResult ServeRoot(
|
||||
[FromServices] IOptions<DiagnosticDashboardOptions> diagnostics) =>
|
||||
diagnostics.Value.Enabled
|
||||
? Results.Redirect("/diagnostics")
|
||||
: Results.Json(new
|
||||
{
|
||||
contractVersion = ContractLimits.ContractVersion,
|
||||
service = "rendezvous",
|
||||
health = "/health/live",
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace FinalFactory.Rendezvous.Server.Observability;
|
||||
|
||||
/// <summary>
|
||||
/// Container healthcheck entry mode (<c>--health-probe</c>). The chiseled
|
||||
/// runtime image ships no shell or curl, so the probe re-enters the server
|
||||
/// assembly, queries the local liveness endpoint, and reports via exit code.
|
||||
/// </summary>
|
||||
internal static class HealthProbe
|
||||
{
|
||||
public const string Argument = "--health-probe";
|
||||
|
||||
public static async Task<int> RunAsync()
|
||||
{
|
||||
string configuredPorts =
|
||||
Environment.GetEnvironmentVariable("ASPNETCORE_HTTP_PORTS") ?? "8080";
|
||||
string port = configuredPorts
|
||||
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.FirstOrDefault() ?? "8080";
|
||||
using HttpClient client = new() { Timeout = TimeSpan.FromSeconds(4) };
|
||||
try
|
||||
{
|
||||
using HttpResponseMessage response = await client.GetAsync(
|
||||
new Uri($"http://127.0.0.1:{port}/health/live"));
|
||||
return response.IsSuccessStatusCode ? 0 : 1;
|
||||
}
|
||||
catch (Exception exception)
|
||||
when (exception is HttpRequestException
|
||||
or TaskCanceledException
|
||||
or UriFormatException)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,11 @@ using FinalFactory.Rendezvous.Server.Transport;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.OpenApi;
|
||||
|
||||
if (args.Contains(HealthProbe.Argument, StringComparer.Ordinal))
|
||||
{
|
||||
return await HealthProbe.RunAsync();
|
||||
}
|
||||
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||
builder.Logging.AddFilter(
|
||||
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware",
|
||||
@@ -378,6 +383,7 @@ app.UseMiddleware<TelemetryMiddleware>();
|
||||
app.UseExceptionHandler();
|
||||
app.UseMiddleware<HttpAbuseProtectionMiddleware>();
|
||||
app.MapOpenApi();
|
||||
app.MapRootEndpoint();
|
||||
app.MapRendezvousContractEndpoints();
|
||||
app.MapOperatorEndpoints();
|
||||
app.MapRendezvousHealthEndpoints();
|
||||
@@ -385,6 +391,7 @@ app.MapDiagnosticDashboardEndpoints();
|
||||
app.MapPrometheusMetricsEndpoint(metricsOptions, metricsCredential);
|
||||
|
||||
await app.RunAsync();
|
||||
return 0;
|
||||
|
||||
/// <summary>
|
||||
/// Entry point marker used by integration-test hosts.
|
||||
|
||||
Reference in New Issue
Block a user