@@ -57,6 +57,8 @@ public void ConnectToHost()
5757 _devServer = JsonRpc . Attach < IIdeChannelServer > ( _pipeServer ) ;
5858 _devServer . MessageFromDevServer += ProcessDevServerMessage ;
5959
60+ // Signal connection established once
61+ Connected ? . Invoke ( this , EventArgs . Empty ) ;
6062 ScheduleKeepAlive ( ct ) ;
6163 }
6264 catch ( Exception e )
@@ -83,8 +85,6 @@ public async Task SendToDevServerAsync(IdeMessage message, CancellationToken ct)
8385
8486 private void ScheduleKeepAlive ( CancellationToken ct )
8587 {
86- Connected ? . Invoke ( this , EventArgs . Empty ) ;
87-
8888 // Replace recursive re-scheduling with a single periodic timer
8989 var oldTimer = Interlocked . Exchange ( ref _keepAliveTimer , null ) ;
9090 oldTimer ? . Dispose ( ) ;
@@ -93,7 +93,22 @@ private void ScheduleKeepAlive(CancellationToken ct)
9393 {
9494 if ( ct is { IsCancellationRequested : false } && _devServer is not null )
9595 {
96- _ = _devServer . SendToDevServerAsync ( IdeMessageSerializer . Serialize ( new KeepAliveIdeMessage ( "IDE" ) ) , ct ) ;
96+ try
97+ {
98+ _ = _devServer
99+ . SendToDevServerAsync ( IdeMessageSerializer . Serialize ( new KeepAliveIdeMessage ( "IDE" ) ) , ct )
100+ . ContinueWith ( t =>
101+ {
102+ if ( t . IsFaulted && t . Exception is { } ex )
103+ {
104+ _logger . Verbose ( $ "Keep-alive send failed: { ex . Flatten ( ) . Message } ") ;
105+ }
106+ } , CancellationToken . None , TaskContinuationOptions . OnlyOnFaulted , TaskScheduler . Default ) ;
107+ }
108+ catch ( Exception ex )
109+ {
110+ _logger . Verbose ( $ "Keep-alive send exception: { ex . Message } ") ;
111+ }
97112 }
98113 else
99114 {
@@ -147,6 +162,12 @@ internal void Dispose()
147162 {
148163 _IDEChannelCancellation ? . Cancel ( ) ;
149164 _keepAliveTimer ? . Dispose ( ) ;
165+
166+ if ( _devServer is not null )
167+ {
168+ _devServer . MessageFromDevServer -= ProcessDevServerMessage ;
169+ }
170+
150171 _pipeServer ? . Dispose ( ) ;
151172 }
152173}
0 commit comments