Skip to content

Conversation

@haefele
Copy link
Owner

@haefele haefele commented Jan 12, 2026

No description provided.

The custom timeout configuration (ClientTimeoutInterval: 2 minutes, KeepAliveInterval: 30 seconds) was causing disconnections during active use due to a timing mismatch with the client's default ServerTimeout of 30 seconds.

When the server sends keep-alive pings every 30 seconds but the client expects messages within 30 seconds, any network latency or processing delay causes the client to timeout before the server's ping arrives.

Reverting to SignalR defaults provides the recommended 2:1 ratio:
- Server KeepAliveInterval: 15 seconds (default)
- Server ClientTimeoutInterval: 30 seconds (default)
- Client KeepAliveInterval: 15 seconds (default)
- Client ServerTimeout: 30 seconds (default)

This ensures sufficient buffer time for network jitter and prevents spurious disconnections.
Add proper initialization guards and null checks to prevent InvalidOperationException
when connections are being torn down:

- Add EnsureInitialized() to UpdateProperties to ensure presenter exists before validation
- Add EnsureInitialized() to Internal_AddViewer to prevent adding viewers to uninitialized grains
- Add null guard in Internal_RemoveClient viewer path to handle race condition where
  presenter has already disconnected and nullified _presenter
- Add EnsureInitialized() to Internal_DisplayNameChanged to prevent calls on uninitialized grains

The race condition occurred when:
1. Presenter disconnects first, nullifying _presenter
2. Viewer disconnects immediately after
3. Viewer removal attempts to call NotifyConnectionChangedAsync() which requires presenter

Now viewer removal gracefully skips notification if presenter is already gone,
since the connection is effectively dead and all clients have already been notified
via ConnectionStopped.

Fixes: System.InvalidOperationException: ConnectionGrain not initialized: ConnectionId=..., presenter=null
@haefele haefele enabled auto-merge (rebase) January 12, 2026 17:46
@haefele haefele merged commit 95037c5 into main Jan 12, 2026
2 of 4 checks passed
@haefele haefele deleted the fix/signalr-timeout-defaults branch January 12, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants