Skip to content

Commit

Permalink
[JetBrains] improve handling of client connection termination (#20288)
Browse files Browse the repository at this point in the history
* [JetBrains] improve handling of client connection termination

* Hold connection provider until workspace stopped

* use lifetime launch

* delay 5 seconds
  • Loading branch information
mustard-mh authored Oct 11, 2024
1 parent 2ffa717 commit 41b6404
Showing 1 changed file with 49 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ import com.jetbrains.rd.util.ConcurrentHashMap
import com.jetbrains.rd.util.URI
import com.jetbrains.rd.util.lifetime.Lifetime
import com.jetbrains.rd.util.lifetime.LifetimeDefinition
import com.jetbrains.rd.util.threading.coroutines.launch
import io.gitpod.gitpodprotocol.api.entities.WorkspaceInstance
import io.gitpod.jetbrains.gateway.common.GitpodConnectionHandleFactory
import io.gitpod.jetbrains.icons.GitpodIcons
import kotlinx.coroutines.*
import kotlinx.coroutines.future.await
import java.awt.Component
import java.net.URL
import java.net.http.HttpClient
import java.net.http.HttpRequest
Expand All @@ -71,6 +73,17 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
private val jacksonMapper = jacksonObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)


private fun showTimedOutDialogDialog(workspaceId: String, detail: String?) {
val title = "Workspace Timed Out"
val message = "Your workspace $workspaceId has timed out${if (detail.isNullOrBlank()) "" else " : $detail"}."
val okButton = Messages.getOkButton()
val options = arrayOf(okButton)
val defaultIndex = 0
val icon = Messages.getInformationIcon()
Messages.showDialog(message, title, options, defaultIndex, icon)
}

override suspend fun connect(
parameters: Map<String, String>,
requestor: ConnectionRequestor
Expand Down Expand Up @@ -188,6 +201,7 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
var thinClientJob: Job? = null

var lastUpdate: WorkspaceInstance? = null
var canceledByGitpod = false
try {
for (update in updates) {
try {
Expand Down Expand Up @@ -255,8 +269,8 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
statusMessage.text = ""
}
}

if (update.status.phase == "stopping" || update.status.phase == "stopped") {
canceledByGitpod = true
thinClientJob?.cancel()
thinClient?.close()
}
Expand Down Expand Up @@ -295,9 +309,41 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
SshHostTunnelConnector(credentials),
URI(joinLinkResp.joinLink)
)
var triggeredClientClosed = false
clientHandle.clientClosed.advise(connectionLifetime) {
application.invokeLater {
connectionLifetime.terminate()
// Been canceled by user
if (!canceledByGitpod) {
connectionLifetime.launch {
// Delay for 5 seconds to see if thinClient could be terminated in time
// Then we don't see error dialog from Gateway
delay(5000)
application.invokeLater {
connectionLifetime.terminate()
}
}
return@advise
}
if (triggeredClientClosed) {
return@advise
}
triggeredClientClosed = true
// Wait until workspace is stopped
suspend fun waitUntilStopped(): Boolean {
while (lastUpdate.status.phase != "stopped") {
delay(1000)
}
return true
}
// Check if it's timed out, if so, show timed out dialog
connectionLifetime.launch {
val isInStoppedPhase = waitUntilStopped()
val isTimedOut = isInStoppedPhase && phaseMessage.text == "Timed Out"
application.invokeLater {
if (isTimedOut) {
showTimedOutDialogDialog(connectParams.resolvedWorkspaceId, lastUpdate.status.conditions.timeout)
}
connectionLifetime.terminate()
}
}
}
clientHandle.onClientPresenceChanged.advise(connectionLifetime) {
Expand Down

0 comments on commit 41b6404

Please sign in to comment.