From f12656bd993b9ab34b855c5e621dc0de67055f45 Mon Sep 17 00:00:00 2001 From: Carl-Robert Linnupuu Date: Wed, 3 Dec 2025 22:01:56 +0000 Subject: [PATCH] fix: code completion grpc connections upon client deadline timeouts --- .../edit/CodeCompletionStreamObserver.kt | 37 +++++++++---------- .../codecompletions/edit/GrpcClientService.kt | 10 ++--- .../edit/NextEditStreamObserver.kt | 23 ++---------- 3 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/CodeCompletionStreamObserver.kt b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/CodeCompletionStreamObserver.kt index df6301df..a3e8443c 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/CodeCompletionStreamObserver.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/CodeCompletionStreamObserver.kt @@ -1,13 +1,13 @@ package ee.carlrobert.codegpt.codecompletions.edit import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElement -import com.intellij.openapi.editor.Editor -import ee.carlrobert.codegpt.CodeGPTKeys import com.intellij.notification.NotificationType import com.intellij.openapi.diagnostic.thisLogger +import com.intellij.openapi.editor.Editor +import ee.carlrobert.codegpt.CodeGPTKeys import ee.carlrobert.codegpt.codecompletions.CodeCompletionEventListener -import ee.carlrobert.llm.client.openai.completion.ErrorDetails import ee.carlrobert.codegpt.ui.OverlayUtil +import ee.carlrobert.llm.client.openai.completion.ErrorDetails import ee.carlrobert.service.PartialCodeCompletionResponse import io.grpc.Status import io.grpc.StatusRuntimeException @@ -43,26 +43,25 @@ class CodeCompletionStreamObserver( } override fun onError(t: Throwable?) { - if (t is StatusRuntimeException && t.status.code == Status.Code.CANCELLED) { - eventListener.onCancelled(messageBuilder) - channel.close() - return - } - logger.error("Error occurred while fetching code completion", t) if (t is StatusRuntimeException) { val code = t.status.code - if (code != Status.Code.UNAVAILABLE && code != Status.Code.DEADLINE_EXCEEDED) { - OverlayUtil.showNotification( - t.message ?: "Something went wrong", - NotificationType.ERROR - ) + if (code == Status.Code.CANCELLED || code == Status.Code.DEADLINE_EXCEEDED) { + eventListener.onComplete(messageBuilder) + return + } + + if (code == Status.Code.UNAVAILABLE) { + eventListener.onError(ErrorDetails("Connection unavailable"), t) + channel.close(t) + return } - } else { - OverlayUtil.showNotification( - t?.message ?: "Something went wrong", - NotificationType.ERROR - ) } + + logger.error("Unexpected error occurred while fetching code completion", t) + OverlayUtil.showNotification( + t?.message ?: "Something went wrong", + NotificationType.ERROR + ) eventListener.onError(ErrorDetails(t?.message ?: "Code completion error"), t ?: Throwable()) channel.close(t) } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/GrpcClientService.kt b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/GrpcClientService.kt index 56782878..66dffc9e 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/GrpcClientService.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/GrpcClientService.kt @@ -63,7 +63,7 @@ class GrpcClientService(private val project: Project) : Disposable { val prev = ctx.attach() try { codeCompletionStub - ?.withDeadlineAfter(10, TimeUnit.SECONDS) + ?.withDeadlineAfter(2, TimeUnit.SECONDS) ?.getCodeCompletion(grpcRequest, codeCompletionObserver) } finally { ctx.detach(prev) @@ -94,7 +94,7 @@ class GrpcClientService(private val project: Project) : Disposable { val prev = ctx.attach() try { nextEditStub - ?.withDeadlineAfter(10, TimeUnit.SECONDS) + ?.withDeadlineAfter(2, TimeUnit.SECONDS) ?.nextEdit(request, nextEditStreamObserver) } finally { ctx.detach(prev) @@ -225,11 +225,11 @@ class GrpcClientService(private val project: Project) : Disposable { .trustManager(CertificateManager.getInstance().trustManager) .build() ) - .withOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) + .withOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5_000) .keepAliveTime(2, TimeUnit.MINUTES) .keepAliveTimeout(20, TimeUnit.SECONDS) - .keepAliveWithoutCalls(false) - .idleTimeout(5, TimeUnit.MINUTES) + .keepAliveWithoutCalls(true) + .idleTimeout(30, TimeUnit.MINUTES) .maxInboundMessageSize(32 * 1024 * 1024) .build() diff --git a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/NextEditStreamObserver.kt b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/NextEditStreamObserver.kt index c57ffd8a..4fbd1037 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/NextEditStreamObserver.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/edit/NextEditStreamObserver.kt @@ -11,12 +11,11 @@ import ee.carlrobert.service.NextEditResponse import io.grpc.Status import io.grpc.StatusRuntimeException import io.grpc.stub.StreamObserver -import kotlin.coroutines.cancellation.CancellationException class NextEditStreamObserver( private val editor: Editor, private val addToQueue: Boolean = false, - private val onDispose: () -> Unit + private val onRefreshConnection: () -> Unit ) : StreamObserver { companion object { @@ -40,25 +39,11 @@ class NextEditStreamObserver( } override fun onError(ex: Throwable) { - if (ex is CancellationException || - (ex is StatusRuntimeException && ex.status.code == Status.Code.CANCELLED) - ) { - onCompleted() - return + if (ex is StatusRuntimeException && ex.status.code == Status.Code.UNAVAILABLE) { + onRefreshConnection() } - try { - if (ex is StatusRuntimeException) { - if (ex.status.code == Status.Code.DEADLINE_EXCEEDED) { - return - } - } else { - logger.error("Something went wrong", ex) - } - } finally { - onCompleted() - onDispose() - } + onCompleted() } override fun onCompleted() {