Skip to content

Commit 8c2271c

Browse files
committed
impl: network metrics poll job
When ssh is connected a poll job is created that searches for the SSH command pid, and then determines the network metrics json file. The pid can change multiple times in a Toolbox session, especially when the OS goes to sleep and comes back - the ssh is respawned. This is the reason we don't cache the pid, instead always search for it. The poll job activates every 5 settings and it is cancelled when the user stops the ssh connection.
1 parent c5c1850 commit 8c2271c

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt

+37
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.coder.toolbox
22

33
import com.coder.toolbox.browser.BrowserUtil
44
import com.coder.toolbox.cli.CoderCLIManager
5+
import com.coder.toolbox.cli.SshCommandProcessHandle
56
import com.coder.toolbox.models.WorkspaceAndAgentStatus
67
import com.coder.toolbox.sdk.CoderRestClient
78
import com.coder.toolbox.sdk.ex.APIResponseException
@@ -20,15 +21,20 @@ import com.jetbrains.toolbox.api.remoteDev.environments.EnvironmentContentsView
2021
import com.jetbrains.toolbox.api.remoteDev.states.EnvironmentDescription
2122
import com.jetbrains.toolbox.api.remoteDev.states.RemoteEnvironmentState
2223
import com.jetbrains.toolbox.api.ui.actions.ActionDescription
24+
import kotlinx.coroutines.Job
2325
import kotlinx.coroutines.delay
2426
import kotlinx.coroutines.flow.MutableStateFlow
2527
import kotlinx.coroutines.flow.update
2628
import kotlinx.coroutines.isActive
2729
import kotlinx.coroutines.launch
2830
import kotlinx.coroutines.withTimeout
31+
import java.io.File
32+
import java.nio.file.Path
2933
import kotlin.time.Duration.Companion.minutes
3034
import kotlin.time.Duration.Companion.seconds
3135

36+
private val POLL_INTERVAL = 5.seconds
37+
3238
/**
3339
* Represents an agent and workspace combination.
3440
*
@@ -55,6 +61,9 @@ class CoderRemoteEnvironment(
5561

5662
override val actionsList: MutableStateFlow<List<ActionDescription>> = MutableStateFlow(getAvailableActions())
5763

64+
private val proxyCommandHandle = SshCommandProcessHandle(context)
65+
private var pollJob: Job? = null
66+
5867
fun asPairOfWorkspaceAndAgent(): Pair<Workspace, WorkspaceAgent> = Pair(workspace, agent)
5968

6069
private fun getAvailableActions(): List<ActionDescription> {
@@ -141,9 +150,37 @@ class CoderRemoteEnvironment(
141150
override fun beforeConnection() {
142151
context.logger.info("Connecting to $id...")
143152
isConnected.update { true }
153+
154+
pollJob = pollNetworkMetrics()
155+
}
156+
157+
private fun pollNetworkMetrics(): Job = context.cs.launch {
158+
context.logger.info("Starting the network metrics poll job for $id")
159+
while (isActive) {
160+
context.logger.debug("Searching SSH command's PID for workspace $id...")
161+
val pid = proxyCommandHandle.findByWorkspaceAndAgent(workspace, agent)
162+
if (pid == null) {
163+
context.logger.debug("No SSH command PID was found for workspace $id")
164+
delay(POLL_INTERVAL)
165+
continue
166+
}
167+
168+
val metricsFile = Path.of(context.settingsStore.networkInfoDir, "$pid.json").toFile()
169+
if (metricsFile.doesNotExists()) {
170+
context.logger.debug("No metrics file found at ${metricsFile.absolutePath} for $id")
171+
delay(POLL_INTERVAL)
172+
continue
173+
}
174+
context.logger.debug("Loading metrics from ${metricsFile.absolutePath} for $id")
175+
delay(POLL_INTERVAL)
176+
}
144177
}
145178

179+
private fun File.doesNotExists(): Boolean = !this.exists()
180+
146181
override fun afterDisconnect() {
182+
context.logger.info("Stopping the network metrics poll job for $id")
183+
pollJob?.cancel()
147184
this.connectionRequest.update { false }
148185
isConnected.update { false }
149186
context.logger.info("Disconnected from $id")

0 commit comments

Comments
 (0)