Skip to content

Stream workspace action progress over WebSockets - #366

Open
fioan89 wants to merge 5 commits into
mainfrom
websocket-workspace-progress
Open

fioan89 wants to merge 5 commits into
mainfrom
websocket-workspace-progress

Conversation

@fioan89

@fioan89 fioan89 commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator

Workspace action progress was previously refreshed only by the five-second polling loop, which made start, stop, update-and-start, and update-and-restart operations appear stale between polls.

We added a workspace progress watcher that uses Coder's workspace and build-log WebSockets on supported deployments. The remote environment uses those events only for the progress description, while the workspace poller remains responsible for workspace and agent state.

We added version gating and failure handling so older deployments and unavailable WebSocket connections continue through the existing polling path. We also added coverage for streaming output, state isolation, lifecycle cleanup, and fallback behavior.

Workspace action progress was previously refreshed only by the five-second polling loop, which made start, stop, update-and-start, and update-and-restart operations appear stale between polls.

We added a workspace progress watcher that uses Coder's workspace and build-log WebSockets on supported deployments. The remote environment uses those events only for the progress description, while the workspace poller remains responsible for workspace and agent state.

We added version gating and failure handling so older deployments and unavailable WebSocket connections continue through the existing polling path. We also added coverage for streaming output, state isolation, lifecycle cleanup, and fallback behavior.
Workspace action progress was previously refreshed only every five seconds, and the streaming capability and transport responsibilities were spread across the environment, watcher, and REST client.

We added workspace progress WebSockets to the CLI feature set and changed the remote environment to choose between streaming and REST polling before invoking either path. The Coder API facade now defines the streaming endpoints, while the REST client owns WebSocket transport and event decoding.

We changed the workspace progress watcher to consume ID-based streaming methods and remain focused on build progression. Runtime failures still fall back to polling, and the updated coverage verifies feature selection, streaming behavior, state isolation, and failure handling.
Workspace action progress was previously available only every five seconds, and the first streaming implementation added unnecessary abstractions to an environment class whose mixed ordering made the behavior difficult to follow.

We removed the watcher interface, shortened the concrete watcher name, and changed the callback holder into three named function parameters. The remote environment now constructs the watcher directly, while the watcher keeps workspace-first argument ordering and remains focused on streamed build progress.

We reorganized CoderRemoteEnvironment in depth-first call order, grouped overridden entry points with their supporting methods, and moved file-level extensions below the class. The polling fallback and workspace and agent state ownership remain unchanged.
@fioan89
fioan89 marked this pull request as ready for review September 24, 2026 19:49
@fioan89
fioan89 requested review from code-asher, jeremyruppel and matifali and removed request for code-asher September 24, 2026 19:49
Comment thread src/main/kotlin/com/coder/toolbox/sdk/WorkspaceProgressWatcher.kt
if (log.id <= lastLogID) {
false
} else {
lastLogID = log.id

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how to better express this in kotlin, but because the lock routine returns a boolean, the lastLogID assignment here feels like a side effect. is there a good/clean way to tease these apart?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not happy how the progress watcher turned out, I'll try to simplify and improve it.

Comment thread src/main/kotlin/com/coder/toolbox/sdk/WorkspaceProgressWatcher.kt Outdated
Comment thread src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt Outdated
Comment thread src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt Outdated
Workspace action progress was previously available only every five seconds, and the initial streaming path contained repeated action workflows and lifecycle details that were difficult to interpret.

We changed CoderRemoteEnvironment to share the workspace build request workflow and replaced the ambiguous retry flag with an explicit watcher restart path. The environment still uses polling for workspace and agent state and falls back to REST progress requests when streaming becomes unavailable.

We changed WorkspaceProgressWatcher to use its activity property consistently, isolated duplicate-log tracking, and distinguished expected build-log completion from abnormal socket closure. We also added coverage showing that abnormal closure disables streaming and activates failure handling.
Workspace build progress was provided only every five seconds by polling, leaving actions without timely feedback. We changed CoderRemoteEnvironment to share the action lifecycle and show queued progress immediately, while its polling loop remains responsible for workspace and agent state.

We changed WorkspaceProgressWatcher to stream build progress when supported, reconnect failed sockets with backoff, and retrieve logs through REST while streaming is unavailable. We changed CoderRestClient to report socket openings and removed CLI text-progress callbacks so the watcher owns progress descriptions. We added tests for action lifecycle, streaming, fallback, and reconnection.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants