Skip to content

Commit 4a86694

Browse files
committed
Fix multiple clients launching with running backend
1 parent 01dedfd commit 4a86694

File tree

3 files changed

+37
-15
lines changed

3 files changed

+37
-15
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
## Unreleased
66

7+
### Fixed
8+
9+
- Multiple clients being launched when a backend was already running.
10+
711
## 2.11.5 - 2024-05-06
812

913
### Added

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pluginGroup=com.coder.gateway
44
pluginName=coder-gateway
55
# SemVer format -> https://semver.org
6-
pluginVersion=2.11.5
6+
pluginVersion=2.11.6
77
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
88
# for insight into build numbers and IntelliJ Platform versions.
99
pluginSinceBuild=233.6745

src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt

+32-14
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class CoderRemoteConnectionHandle {
145145
setupCommand: String,
146146
ignoreSetupFailure: Boolean,
147147
timeout: Duration = Duration.ofMinutes(10),
148-
): Unit {
148+
) {
149149
workspace.lastOpened = localTimeFormatter.format(LocalDateTime.now())
150150

151151
// This establishes an SSH connection to a remote worker binary.
@@ -168,6 +168,7 @@ class CoderRemoteConnectionHandle {
168168
this.setup(workspace, indicator, setupCommand, ignoreSetupFailure)
169169

170170
// Wait for the IDE to come up.
171+
indicator.text = "Waiting for ${workspace.ideName} backend..."
171172
var status: UnattendedHostStatus? = null
172173
val remoteProjectPath = accessor.makeRemotePath(ShellArgument.PlainText(workspace.projectPath))
173174
val logsDir = accessor.getLogsDir(workspace.ideProductCode.productCode, remoteProjectPath)
@@ -374,7 +375,8 @@ class CoderRemoteConnectionHandle {
374375
}
375376

376377
/**
377-
* Ensure the backend is started. Link is null if not ready to join.
378+
* Ensure the backend is started. Status and/or links may be null if the
379+
* backend has not started.
378380
*/
379381
private suspend fun ensureIDEBackend(
380382
workspace: WorkspaceProjectIDE,
@@ -385,23 +387,39 @@ class CoderRemoteConnectionHandle {
385387
lifetime: LifetimeDefinition,
386388
currentStatus: UnattendedHostStatus?,
387389
): UnattendedHostStatus? {
390+
val details = "${workspace.hostname}:${ideDir.toRawString()}, project=${remoteProjectPath.toRawString()}"
388391
return try {
389-
// Start the backend if not running.
390-
val currentPid = currentStatus?.appPid
391-
if (currentPid == null || !accessor.isPidAlive(currentPid.toInt())) {
392-
logger.info("Starting ${workspace.ideName} backend from ${workspace.hostname}:${ideDir.toRawString()}, project=${remoteProjectPath.toRawString()}, logs=${logsDir.toRawString()}")
393-
// This appears to be idempotent.
394-
accessor.startHostIdeInBackgroundAndDetach(lifetime, ideDir, remoteProjectPath, logsDir)
395-
} else if (!currentStatus.joinLink.isNullOrBlank()) {
396-
// We already have a valid join link.
392+
if (currentStatus?.appPid !== null &&
393+
!currentStatus.joinLink.isNullOrBlank() &&
394+
accessor.isPidAlive(currentStatus.appPid.toInt())
395+
) {
396+
// If the PID is alive, assume the join link we have is still
397+
// valid. The join link seems to change even if it is the same
398+
// backend running, so if we always fetched the link the client
399+
// would relaunch over and over.
397400
return currentStatus
398401
}
399-
// Get new PID and join link.
402+
403+
// See if there is already a backend running. Weirdly, there is
404+
// always a PID, even if there is no backend running, and
405+
// backendUnresponsive is always false, but the links are null so
406+
// hopefully that is an accurate indicator that the IDE is up.
400407
val status = accessor.getHostIdeStatus(ideDir, remoteProjectPath)
401-
logger.info("Got ${workspace.ideName} status from ${workspace.hostname}:${ideDir.toRawString()}, pid=${status.appPid} project=${remoteProjectPath.toRawString()} joinLink=${status.joinLink}")
402-
status
408+
if (!status.joinLink.isNullOrBlank()) {
409+
logger.info("Found existing ${workspace.ideName} backend on $details")
410+
return status
411+
}
412+
413+
// Otherwise, spawn a new backend. This does not seem to spawn a
414+
// second backend if one is already running, yet it does somehow
415+
// cause a second client to launch. So only run this if we are
416+
// really sure we have to launch a new backend.
417+
logger.info("Starting ${workspace.ideName} backend on $details")
418+
accessor.startHostIdeInBackgroundAndDetach(lifetime, ideDir, remoteProjectPath, logsDir)
419+
// Get the newly spawned PID and join link.
420+
return accessor.getHostIdeStatus(ideDir, remoteProjectPath)
403421
} catch (ex: Exception) {
404-
logger.info("Failed to get ${workspace.ideName} status from ${workspace.hostname}:${ideDir.toRawString()}, project=${remoteProjectPath.toRawString()}", ex)
422+
logger.info("Failed to get ${workspace.ideName} status from $details", ex)
405423
currentStatus
406424
}
407425
}

0 commit comments

Comments
 (0)