refactor(link): bound every teardown and handler wait behind one helper [CI]
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/verify Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful

This commit is contained in:
justme committed 2026-10-19 10:07:36 +08:00
1 parent c05842fd91
commit d95acc6575
10 files changed
+130 -31

No files matched your search

+4 -3
View File
@@ -279,6 +279,7 @@ public sealed class FleetLink
Task cancellation = Task.Delay(Timeout.Infinite, ct);
Task finished = await Task.WhenAny(run, pump, heartbeat, cancellation);
string finishedReason = DescribeFinishedTask(finished, run, pump, heartbeat, session.TransportFailure);
_session = null; // 链路已经结束:上报方不能再往这条会话上写,收尾卡住时也一样
if (ct.IsCancellationRequested)
{
try
@@ -295,15 +296,15 @@ public sealed class FleetLink
}
await sessionCts.CancelAsync();
await Task.WhenAll(Quiet(run), Quiet(pump), Quiet(heartbeat));
await Bounded.WaitAsync(Task.WhenAll(Quiet(run), Quiet(pump), Quiet(heartbeat)), Bounded.Teardown, _time);
return finishedReason;
}
finally
{
_session = null;
await sessionCts.CancelAsync();
await Quiet(run);
await session.DisposeAsync();
await Bounded.WaitAsync(Quiet(run), Bounded.Teardown, _time);
await Bounded.WaitAsync(session.DisposeAsync().AsTask(), Bounded.Teardown, _time);
}
}
+19 -5
View File
@@ -118,6 +118,7 @@ public sealed class WsTransport : IRpcTransport
public sealed class TlsFrameTransport : IRpcTransport
{
private const int HeaderBytes = 5;
private static readonly TimeSpan s_sendTimeout = TimeSpan.FromSeconds(20);
private readonly Stream _stream;
private readonly int _maxFrameBytes;
@@ -139,16 +140,29 @@ public sealed class TlsFrameTransport : IRpcTransport
byte[] header = new byte[HeaderBytes];
BinaryPrimitives.WriteUInt32LittleEndian(header, (uint)frame.Data.Length);
header[4] = (byte)frame.Kind;
await _sendLock.WaitAsync(ct);
// 对端黑洞时写会一直挂着并占着发送锁,心跳、时钟同步和重连都跟着卡住:超时就掐掉这条连接
using var timeout = new CancellationTokenSource(s_sendTimeout);
using CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(ct, timeout.Token);
bool lockTaken = false;
try
{
await _stream.WriteAsync(header, ct);
await _stream.WriteAsync(frame.Data, ct);
await _stream.FlushAsync(ct);
await _sendLock.WaitAsync(linked.Token);
lockTaken = true;
await _stream.WriteAsync(header, linked.Token);
await _stream.WriteAsync(frame.Data, linked.Token);
await _stream.FlushAsync(linked.Token);
}
catch (OperationCanceledException) when (timeout.IsCancellationRequested && !ct.IsCancellationRequested)
{
await _stream.DisposeAsync();
throw new TimeoutException($"peer send timed out after {s_sendTimeout.TotalSeconds:0} seconds");
}
finally
{
_sendLock.Release();
if (lockTaken)
{
_sendLock.Release();
}
}
}