@@ -24,12 +24,16 @@ import com.intellij.util.net.HttpConfigurable
2424import  com.intellij.util.net.JdkProxyProvider 
2525import  kotlinx.coroutines.CoroutineScope 
2626import  kotlinx.coroutines.Deferred 
27+ import  kotlinx.coroutines.Job 
2728import  kotlinx.coroutines.async 
2829import  kotlinx.coroutines.channels.BufferOverflow 
30+ import  kotlinx.coroutines.delay 
2931import  kotlinx.coroutines.flow.MutableSharedFlow 
3032import  kotlinx.coroutines.flow.asSharedFlow 
3133import  kotlinx.coroutines.flow.map 
3234import  kotlinx.coroutines.future.asCompletableFuture 
35+ import  kotlinx.coroutines.isActive 
36+ import  kotlinx.coroutines.launch 
3337import  kotlinx.coroutines.runBlocking 
3438import  kotlinx.coroutines.sync.Mutex 
3539import  kotlinx.coroutines.sync.withLock 
@@ -50,6 +54,7 @@ import org.eclipse.lsp4j.jsonrpc.MessageConsumer
5054import  org.eclipse.lsp4j.jsonrpc.messages.ResponseMessage 
5155import  org.eclipse.lsp4j.launch.LSPLauncher 
5256import  org.slf4j.event.Level 
57+ import  software.aws.toolkits.core.utils.debug 
5358import  software.aws.toolkits.core.utils.getLogger 
5459import  software.aws.toolkits.core.utils.info 
5560import  software.aws.toolkits.core.utils.warn 
@@ -125,6 +130,7 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
125130        get() =  instance.getCompleted().initializeResult.getCompleted().capabilities
126131    val  encryptionManager
127132        get() =  instance.getCompleted().encryptionManager
133+     private  val  heartbeatJob:  Job 
128134
129135    //  dont allow lsp commands if server is restarting
130136    private  val  mutex =  Mutex (false )
@@ -157,9 +163,36 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
157163
158164    init  {
159165        instance =  start()
166+ 
167+         //  Initialize heartbeat job
168+         heartbeatJob =  cs.launch {
169+             while  (isActive) {
170+                 delay(5 .seconds) //  Check every 2 seconds
171+                 checkConnectionStatus()
172+             }
173+         }
174+     }
175+ 
176+     private  suspend  fun  checkConnectionStatus () {
177+         try  {
178+             val  currentInstance =  mutex.withLock { instance }.await()
179+ 
180+             //  Check if the launcher's Future (startListening) is done
181+             //  If it's done, that means the connection has been terminated
182+             if  (currentInstance.launcherFuture.isDone) {
183+                 LOG .debug { " LSP server connection terminated, restarting server"   }
184+                 restart()
185+             } else  {
186+                 LOG .debug { " LSP server is currently running "   }
187+             }
188+         } catch  (e:  Exception ) {
189+             LOG .debug(e) { " Connection status check failed, restarting LSP server"   }
190+             restart()
191+         }
160192    }
161193
162194    override  fun  dispose () {
195+         heartbeatJob.cancel()
163196    }
164197
165198    suspend  fun  restart () =  mutex.withLock {
@@ -225,7 +258,8 @@ private class AmazonQServerInstance(private val project: Project, private val cs
225258        get() =  launcher.remoteProxy
226259
227260    @Suppress(" ForbiddenVoid"  )
228-     private  val  launcherFuture:  Future <Void >
261+     var  launcherFuture:  Future <Void >
262+         private  set
229263    private  val  launcherHandler:  KillableProcessHandler 
230264    val  initializeResult:  Deferred <InitializeResult >
231265
0 commit comments