@@ -30,12 +30,14 @@ namespace LehrerApp.McpBridge;
|
||||
internal sealed class RealServerBridge : IAsyncDisposable
|
||||
{
|
||||
private const int ConnectTimeoutMs = 3000;
|
||||
private static readonly TimeSpan ReconnectCooldown = TimeSpan.FromSeconds(3);
|
||||
|
||||
public McpServerPrimitiveCollection<McpServerTool> Tools { get; } = new();
|
||||
|
||||
private readonly SemaphoreSlim _gate = new(1, 1);
|
||||
private McpClient? _client;
|
||||
private NamedPipeClientStream? _pipe;
|
||||
private DateTime? _lastFailedConnectAttemptUtc;
|
||||
|
||||
/// <summary>Reicht einen Tool-Aufruf an die echte Verbindung weiter (aufgerufen aus
|
||||
/// <see cref="ProxyMcpServerTool"/>). Bricht die Verbindung erst hier ab, statt sie proaktiv vor
|
||||
@@ -66,19 +68,29 @@ internal sealed class RealServerBridge : IAsyncDisposable
|
||||
|
||||
/// <summary>Versucht, sofern noch nicht verbunden, jetzt sofort eine Verbindung aufzubauen -
|
||||
/// aufgerufen sowohl beim Start der Bridge als auch aus <see cref="StatusMcpServerTool"/>
|
||||
/// (expliziter Nutzer-/Assistenten-Wunsch, jetzt nachzusehen) und aus dem Hintergrund-Loop.</summary>
|
||||
/// (expliziter Nutzer-/Assistenten-Wunsch, jetzt nachzusehen) und aus dem Hintergrund-Loop.
|
||||
/// Nach einem fehlgeschlagenen Versuch schlägt ein weiterer Aufruf innerhalb von
|
||||
/// <see cref="ReconnectCooldown"/> sofort fehl, statt erneut den vollen Pipe-Connect-Timeout
|
||||
/// abzuwarten - sonst kostet ein versehentlicher Doppelaufruf (z.B. weil ein KI-Client
|
||||
/// "lehrerapp_status" trotz gegenteiligem Hinweis im selben Zug erneut aufruft) unnötig weitere
|
||||
/// mehrere Sekunden.</summary>
|
||||
public async Task<bool> TryReconnectAsync(CancellationToken ct)
|
||||
{
|
||||
if (_client is not null) return true;
|
||||
if (IsInCooldown()) return false;
|
||||
await _gate.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
if (_client is not null) return true; // ein anderer Aufrufer war währenddessen schneller
|
||||
if (IsInCooldown()) return false;
|
||||
return await ConnectCoreAsync(ct);
|
||||
}
|
||||
finally { _gate.Release(); }
|
||||
}
|
||||
|
||||
private bool IsInCooldown() =>
|
||||
_lastFailedConnectAttemptUtc is { } last && DateTime.UtcNow - last < ReconnectCooldown;
|
||||
|
||||
private async Task<bool> ConnectCoreAsync(CancellationToken ct)
|
||||
{
|
||||
var pipe = new NamedPipeClientStream(
|
||||
@@ -102,6 +114,7 @@ internal sealed class RealServerBridge : IAsyncDisposable
|
||||
|
||||
_client = client;
|
||||
_pipe = pipe;
|
||||
_lastFailedConnectAttemptUtc = null;
|
||||
await Console.Error.WriteLineAsync(
|
||||
$"LehrerApp.McpBridge: mit LehrerApp verbunden, {tools.Count} Werkzeug(e) übernommen.");
|
||||
return true;
|
||||
@@ -111,6 +124,7 @@ internal sealed class RealServerBridge : IAsyncDisposable
|
||||
await pipe.DisposeAsync();
|
||||
var (_, _, stderrLine) = ConnectionDiagnostics.Describe(ex);
|
||||
await Console.Error.WriteLineAsync(stderrLine);
|
||||
_lastFailedConnectAttemptUtc = DateTime.UtcNow;
|
||||
EnsureFallbackTool();
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user