Skip to content

Commit d8426e4

Browse files
committed
address comments
1 parent e191ac8 commit d8426e4

File tree

1 file changed

+44
-4
lines changed
  • plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp

1 file changed

+44
-4
lines changed

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ import java.net.URI
8585
import java.nio.charset.StandardCharsets
8686
import java.nio.file.Files
8787
import java.util.concurrent.Future
88+
import kotlin.time.Duration.Companion.milliseconds
8889
import kotlin.time.Duration.Companion.seconds
8990

9091
// https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/server/LSPProcessListener.java
@@ -131,6 +132,8 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
131132
val encryptionManager
132133
get() = instance.getCompleted().encryptionManager
133134
private val heartbeatJob: Job
135+
private val restartTimestamps = ArrayDeque<Long>()
136+
private val restartMutex = Mutex() // Separate mutex for restart tracking
134137

135138
// dont allow lsp commands if server is restarting
136139
private val mutex = Mutex(false)
@@ -179,14 +182,18 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
179182

180183
// Check if the launcher's Future (startListening) is done
181184
// 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" }
185+
if (currentInstance.launcherFuture.isDone || true) {
186+
LOG.debug { "LSP server connection terminated, checking restart limits" }
187+
waitForRestartSlot()
188+
LOG.debug { "Restarting LSP server" }
184189
restart()
185190
} else {
186-
LOG.debug { "LSP server is currently running " }
191+
LOG.debug { "LSP server is currently running" }
187192
}
188193
} catch (e: Exception) {
189-
LOG.debug(e) { "Connection status check failed, restarting LSP server" }
194+
LOG.debug(e) { "Connection status check failed, checking restart limits" }
195+
waitForRestartSlot()
196+
LOG.debug { "Restarting LSP server" }
190197
restart()
191198
}
192199
}
@@ -219,6 +226,37 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
219226
instance = start()
220227
}
221228

229+
private suspend fun waitForRestartSlot(): Unit = restartMutex.withLock {
230+
val currentTime = System.currentTimeMillis()
231+
232+
while (restartTimestamps.isNotEmpty() &&
233+
currentTime - restartTimestamps.first() > RESTART_WINDOW_MS
234+
) {
235+
restartTimestamps.removeFirst()
236+
}
237+
238+
if (restartTimestamps.size < MAX_RESTARTS) {
239+
restartTimestamps.addLast(currentTime)
240+
return
241+
}
242+
243+
val oldestTimestamp = restartTimestamps.first()
244+
val waitTimeMs = (oldestTimestamp + RESTART_WINDOW_MS) - currentTime
245+
246+
LOG.info { "Rate limit reached for LSP server restarts. Waiting ${waitTimeMs}ms for next available slot." }
247+
248+
restartMutex.unlock()
249+
try {
250+
delay(waitTimeMs.milliseconds)
251+
} finally {
252+
restartMutex.lock()
253+
}
254+
255+
// After waiting, recursively call this function to check again
256+
// (in case conditions changed while we were waiting)
257+
waitForRestartSlot()
258+
}
259+
222260
suspend fun<T> execute(runnable: suspend AmazonQLspService.(AmazonQLanguageServer) -> T): T {
223261
val lsp = withTimeout(10.seconds) {
224262
val holder = mutex.withLock { instance }.await()
@@ -236,6 +274,8 @@ class AmazonQLspService(private val project: Project, private val cs: CoroutineS
236274

237275
companion object {
238276
private val LOG = getLogger<AmazonQLspService>()
277+
private const val MAX_RESTARTS = 5
278+
private const val RESTART_WINDOW_MS = 3 * 60 * 1000
239279
fun getInstance(project: Project) = project.service<AmazonQLspService>()
240280

241281
fun <T> executeIfRunning(project: Project, runnable: AmazonQLspService.(AmazonQLanguageServer) -> T): T? =

0 commit comments

Comments
 (0)