mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-29 01:15:43 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2544d57c79 | ||
|
|
c1f466348d |
+30
-10
@@ -28,8 +28,10 @@ namespace eagle {
|
||||
|
||||
public class PersistentClientConnection : IDisposable {
|
||||
private const double TimeoutSeconds = 300.0;
|
||||
// Idle timeout = 2x HTTP/2 keepalive interval (15s * 2 = 30s)
|
||||
private const double MaxIdleSeconds = 30.0;
|
||||
// Idle timeout - must be longer than potential idle periods in the game
|
||||
// (AI thinking, between turns, etc.). Set equal to deadline since HTTP/2
|
||||
// keepalive handles transport-level connection health.
|
||||
private const double MaxIdleSeconds = 300.0;
|
||||
|
||||
private DateTime _lastResponseReceived = DateTime.UtcNow;
|
||||
private int _lastIdleWarningLevel = 0; // 0=none, 1=10s warning, 2=20s warning
|
||||
@@ -170,8 +172,16 @@ namespace eagle {
|
||||
|
||||
var request = new UpdateStreamRequest { StreamGameRequest = streamGameRequest };
|
||||
|
||||
DoWithStreamingCall(async (sc) => {
|
||||
_remoteEagleClientLogger.LogLine(
|
||||
$"[SUBSCRIBE] Sending StreamGameRequest for game {subscriber.GameId}, " +
|
||||
$"unfilteredCount={subscriber.LastUnfilteredResultCount}");
|
||||
|
||||
// Note: This is fire-and-forget because we're often called from inside a lock.
|
||||
// DoWithStreamingCall will log if the write fails.
|
||||
_ = DoWithStreamingCall(async (sc) => {
|
||||
await sc.RequestStream.WriteAsync(request);
|
||||
_remoteEagleClientLogger.LogLine(
|
||||
$"[SUBSCRIBE] StreamGameRequest sent successfully for game {subscriber.GameId}");
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -528,13 +538,23 @@ namespace eagle {
|
||||
private delegate Task<bool> WithStreamingCallDelegate(
|
||||
AsyncDuplexStreamingCall<UpdateStreamRequest, UpdateStreamResponse> call);
|
||||
private async Task<bool> DoWithStreamingCall(WithStreamingCallDelegate action) {
|
||||
var sc = _streamingCall;
|
||||
if (sc == null) {
|
||||
_remoteEagleClientLogger.LogLine(
|
||||
"[WRITE_FAILED] _streamingCall is null, write skipped");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return await action(_streamingCall);
|
||||
return await action(sc);
|
||||
} catch (RpcException e) {
|
||||
if (e.StatusCode == StatusCode.Cancelled) {
|
||||
// This is expected when the connection is closed.
|
||||
_remoteEagleClientLogger.LogLine(
|
||||
$"[WRITE_FAILED] RpcException Cancelled: {e.Message}");
|
||||
return false;
|
||||
} else {
|
||||
_remoteEagleClientLogger.LogLine(
|
||||
$"[WRITE_FAILED] RpcException {e.StatusCode}: {e.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -797,17 +817,17 @@ namespace eagle {
|
||||
|
||||
var idleTime = (DateTime.UtcNow - _lastResponseReceived).TotalSeconds;
|
||||
|
||||
// Early warnings at 10s and 20s to help diagnose slow connections
|
||||
if (idleTime > 20.0 && _lastIdleWarningLevel < 2) {
|
||||
// Early warnings at 2min and 4min to help diagnose slow connections
|
||||
if (idleTime > 240.0 && _lastIdleWarningLevel < 2) {
|
||||
_lastIdleWarningLevel = 2;
|
||||
_remoteEagleClientLogger.LogLine(
|
||||
$"[IDLE_WARNING] No messages received in {idleTime:F1}s (timeout at {MaxIdleSeconds}s)");
|
||||
LogConnectionEvent("idle_warning_20s", $"idle_time={idleTime:F1}s");
|
||||
} else if (idleTime > 10.0 && _lastIdleWarningLevel < 1) {
|
||||
LogConnectionEvent("idle_warning_4min", $"idle_time={idleTime:F1}s");
|
||||
} else if (idleTime > 120.0 && _lastIdleWarningLevel < 1) {
|
||||
_lastIdleWarningLevel = 1;
|
||||
_remoteEagleClientLogger.LogLine(
|
||||
$"[IDLE_WARNING] No messages received in {idleTime:F1}s (timeout at {MaxIdleSeconds}s)");
|
||||
LogConnectionEvent("idle_warning_10s", $"idle_time={idleTime:F1}s");
|
||||
LogConnectionEvent("idle_warning_2min", $"idle_time={idleTime:F1}s");
|
||||
}
|
||||
|
||||
if (idleTime > MaxIdleSeconds) {
|
||||
|
||||
Reference in New Issue
Block a user