mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-08 07:36:01 +02:00
feat: Release v0.2.2 with shutdown improvements and connection handling fixes
This commit is contained in:
@@ -4,6 +4,7 @@ Release history for EchoHub.
|
|||||||
|
|
||||||
## Releases
|
## Releases
|
||||||
|
|
||||||
|
- [v0.2.2](v0.2.2.md) - Shutdown Fix
|
||||||
- [v0.2.1](v0.2.1.md) - Shutdown & CI Fixes
|
- [v0.2.1](v0.2.1.md) - Shutdown & CI Fixes
|
||||||
- [v0.2.0](v0.2.0.md) - IRC Gateway
|
- [v0.2.0](v0.2.0.md) - IRC Gateway
|
||||||
- [v0.1.1](v0.1.1.md) - Directory Connection Self-Healing
|
- [v0.1.1](v0.1.1.md) - Directory Connection Self-Healing
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
- name: Overview
|
- name: Overview
|
||||||
href: index.md
|
href: index.md
|
||||||
|
- name: v0.2.2
|
||||||
|
href: v0.2.2.md
|
||||||
- name: v0.2.1
|
- name: v0.2.1
|
||||||
href: v0.2.1.md
|
href: v0.2.1.md
|
||||||
- name: v0.2.0
|
- name: v0.2.0
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# v0.2.2 - Shutdown Fix
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Actually fixed server hanging on Ctrl+C — replaced `await using` with explicit dispose bounded to 3 seconds, so a stuck `HubConnection` can no longer block shutdown
|
||||||
|
- Reduced host shutdown timeout from 30s (default) to 5s
|
||||||
|
- Caught `OperationCanceledException` in the directory service reconnect loop so cancellation exits immediately instead of propagating through dispose
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>0.2.1</Version>
|
<Version>0.2.2</Version>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ while (true)
|
|||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// ── Host options ────────────────────────────────────────────────────
|
||||||
|
builder.Services.Configure<HostOptions>(options =>
|
||||||
|
options.ShutdownTimeout = TimeSpan.FromSeconds(5));
|
||||||
|
|
||||||
// ── Serilog ──────────────────────────────────────────────────────────
|
// ── Serilog ──────────────────────────────────────────────────────────
|
||||||
builder.Host.UseSerilog((context, config) =>
|
builder.Host.UseSerilog((context, config) =>
|
||||||
config.ReadFrom.Configuration(context.Configuration));
|
config.ReadFrom.Configuration(context.Configuration));
|
||||||
|
|||||||
@@ -43,9 +43,11 @@ public sealed class ServerDirectoryService(
|
|||||||
// Outer loop: rebuilds the connection if automatic reconnect permanently fails
|
// Outer loop: rebuilds the connection if automatic reconnect permanently fails
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
await using var connection = BuildConnection();
|
var connection = BuildConnection();
|
||||||
_connection = connection;
|
_connection = connection;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
var connectionPermanentlyClosed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
var connectionPermanentlyClosed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
connection.Reconnected += async _ =>
|
connection.Reconnected += async _ =>
|
||||||
@@ -80,10 +82,19 @@ public sealed class ServerDirectoryService(
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Connection was permanently closed — wait briefly then rebuild
|
// Connection was permanently closed — wait briefly then rebuild
|
||||||
_connection = null;
|
|
||||||
logger.LogInformation("Rebuilding directory connection...");
|
logger.LogInformation("Rebuilding directory connection...");
|
||||||
await Task.Delay(ReconnectBaseDelay, stoppingToken);
|
await Task.Delay(ReconnectBaseDelay, stoppingToken);
|
||||||
}
|
}
|
||||||
|
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_connection = null;
|
||||||
|
await DisposeConnectionAsync(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HubConnection BuildConnection()
|
private HubConnection BuildConnection()
|
||||||
@@ -175,9 +186,21 @@ public sealed class ServerDirectoryService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task DisposeConnectionAsync(HubConnection connection)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.DisposeAsync()
|
||||||
|
.AsTask().WaitAsync(TimeSpan.FromSeconds(3));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Don't let a slow dispose block shutdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// Cancel ExecuteAsync first — it disposes the connection via await using
|
|
||||||
await base.StopAsync(cancellationToken);
|
await base.StopAsync(cancellationToken);
|
||||||
_connection = null;
|
_connection = null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user