Repository navigation
Conversation
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
marked this pull request as ready for review
September 24, 2026 19:49
fioan89
requested review from
code-asher,
jeremyruppel and
matifali
and removed request for
code-asher
September 24, 2026 19:49
| if (log.id <= lastLogID) { | ||
| false | ||
| } else { | ||
| lastLogID = log.id |
There was a problem hiding this comment.
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?
Collaborator
Author
There was a problem hiding this comment.
I'm not happy how the progress watcher turned out, I'll try to simplify and improve it.
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.
Workspace progress could be overwritten by delayed polling responses or callbacks from replaced builds and connections, and watcher notifications could race with shutdown. We changed the workspace progress watcher to track each build and connection separately and serialize state changes with notifications. The watcher now rejects obsolete events and polling results before they can affect the current build, while REST requests remain outside the lock so network waits do not delay cleanup. We changed the connection handler to resume log streaming as soon as a connection opens and simplified its capped retry backoff. We added watcher regression coverage for build replacement, delayed responses, reconnects, shutdown, and failures during connection setup.
Workspace progress mixed build lifecycle, socket recovery, and polling state, making cleanup difficult to follow. Synchronous log requests could delay the provider's workspace refresh, while log socket failures could leave progress stalled. We changed the workspace progress watcher to process events in one coroutine and documented its states and transitions. Each build session now owns its log stream and pending request so replacement cancels old work and excludes late results. We retained a callback lock so shutdown waits for active notifications, and scope cancellation ends the watch. We changed the watcher's socket flows to recover independently and restore REST fallback whenever the log stream becomes unavailable. Retries now reset after receiving data, and log tracking accepts an initial zero ID while rejecting older output. We changed the remote environment to deliver snapshots without waiting for log retrieval, while the watcher retains only the latest queued poll. We shared active build statuses between the environment and watcher and added regression coverage for build transitions, reconnects, cancellation, shutdown, and workspace refreshes during slow requests.
Silent WebSocket disconnects could leave workspace progress frozen, and exceptions from progress callbacks could escape into the host-owned coroutine scope. We added 30-second heartbeat pings to the HTTP client so unresponsive connections trigger the workspace progress watcher's existing recovery and polling fallback. We changed the watcher to report progress callback errors and close only the affected watcher, while preserving coroutine cancellation and cleanup when failure reporting also throws. We clarified shutdown ownership in the watcher and made its socket callback names consistent. We added regression coverage showing that callback failures release sockets and pending requests without cancelling the parent scope or interrupting sibling watchers.
Workspace Start actions showed only generic queued progress while the CLI prepared a build, leaving authentication waits and other preparation output invisible. We restored live stdout and stderr reporting in CoderCLIManager while retaining complete command output and exit-code failures. We changed CoderRemoteEnvironment to send each Start action's CLI output to its own WorkspaceProgressWatcher, and we added preparation events to the watcher so CLI messages appeared until build progress took over. The watcher ignored subsequent CLI output to keep stale messages from replacing build progress or appearing after shutdown. We added coverage for live output from both streams, failures before build creation, and the transition from CLI preparation to build progress. All 80 focused tests passed, and static checks completed with warnings.
CoderCLIManagerTest produced an extra trailing space in stderr messages on Windows because cmd.exe included the space before the redirection operator in the echoed output. This caused two progress tests to fail their exact output assertions. We changed the test scripts to place stderr redirection before each echo command so the messages remained consistent across Windows and POSIX shells. We retained the existing assertions and production behavior. Both affected tests passed locally on macOS; Windows validation remained pending.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Workspace action progress was previously refreshed only by the five-second polling loop, which made 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.