Skip to content

Fix fast-attach falling back when SSH tunnel is not ready - #32

Closed
blooop wants to merge 2 commits into
mainfrom
fix/fast-attach-tunnel-fallback
Closed

blooop wants to merge 2 commits into
mainfrom
fix/fast-attach-tunnel-fallback

Conversation

@blooop

@blooop blooop commented Mar 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • When a workspace reports as "Running" but the devpod SSH tunnel isn't ready, setup_work_symlink() fails silently and the subsequent interactive SSH also errors with Error tunneling to container
  • Now uses the symlink SSH as a health check: if it fails, falls back to workspace_up() which properly establishes the container tunnel before attaching

Test plan

  • dl <repo> when workspace is running and tunnel is healthy — should fast-attach as before
  • dl <repo> when workspace is running but tunnel is stale — should log warning and fall back to workspace_up()
  • Unit tests pass (pixi run pytest test/)

🤖 Generated with Claude Code

Summary by Sourcery

Bug Fixes:

  • Prevent silent failure and tunneling errors during fast-attach when the SSH tunnel or work symlink setup is not ready by detecting the issue and deferring to the standard workspace startup and attach logic.

When a workspace reports as "Running" but the SSH tunnel isn't ready,
the symlink setup fails and the subsequent interactive SSH also errors.
Now falls back to workspace_up() which properly establishes the tunnel.
@sourcery-ai

sourcery-ai Bot commented Mar 4, 2026 •

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adjusts the fast-attach path to treat work symlink setup as a health check for the SSH tunnel, and falls back to the normal workspace startup flow when the tunnel is not ready instead of failing with a tunneling error.

Sequence diagram for fast-attach with SSH tunnel health check

sequenceDiagram
    actor Dev
    participant CLI as dl_main
    participant WS as WorkspaceService
    participant FS as SymlinkManager
    participant SSH as SSHClient
    participant Cache as CacheUpdater

    Dev->>CLI: invoke dl repo
    CLI->>WS: get_workspace_state(workspace_id)
    WS-->>CLI: state = Running
    CLI->>FS: setup_work_symlink(workspace_id)
    alt symlink setup succeeds (tunnel healthy)
        FS-->>CLI: true
        CLI->>SSH: workspace_ssh(workspace_id, shell_command, workdir, preserve_symlink=true)
        SSH-->>CLI: SSH session exit code
        CLI->>Cache: update_cache_background()
        Cache-->>CLI: ok
        CLI-->>Dev: return SSH exit code
    else symlink setup fails (tunnel not ready)
        FS-->>CLI: false
        CLI->>CLI: log warning "SSH tunnel not ready, falling back to workspace_up()..."
        CLI->>WS: workspace_up(workspace_id, shell_command)
        WS-->>CLI: SSH session exit code
        CLI-->>Dev: return SSH exit code
    end
Loading

Flow diagram for updated fast-attach decision logic

flowchart TD
    A[Start dl main] --> B{custom_id is None?}
    B -->|No| Z[Default workspace_up path]
    B -->|Yes| C[get_workspace_state&#40;workspace_id&#41;]
    C --> D{state == Running?}
    D -->|No| Z[Default workspace_up path]
    D -->|Yes| E[Log workspace already running]
    E --> F[setup_work_symlink&#40;workspace_id&#41;]
    F -->|False| G[Log warning SSH tunnel not ready, fallback]
    G --> Z[Default workspace_up path]
    F -->|True| H[workspace_ssh&#40;workspace_id, shell_command, workdir, preserve_symlink=true&#41;]
    H --> I[update_cache_background&#40;&#41;]
    I --> J[Return SSH exit code]
    Z --> J[Return result from workspace_up&#40;&#41;]
Loading

File-Level Changes

Change Details Files
Guard fast-attach path with a workspace symlink/tunnel health check and fall back to full workspace startup when it fails.
  • Wrap the fast-attach block in a conditional that checks the return value of setup_work_symlink instead of unconditionally calling it.
  • On symlink setup failure, log a warning about the SSH tunnel not being ready and skip the fast-attach path.
  • On success, keep the previous fast-attach behavior: call workspace_ssh with the symlink workdir, preserve the symlink, update cache in the background, and return early.
devlaunch/dl.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • Now that setup_work_symlink is used as a health check, it would be helpful to ensure its return type is explicitly boolean (and documented as such) so this new control flow is clear and less error-prone if the function is modified later.
  • Consider logging the workspace ID or more context in the warning (SSH tunnel not ready, falling back...) to make it easier to correlate logs when multiple workspaces are active.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Now that `setup_work_symlink` is used as a health check, it would be helpful to ensure its return type is explicitly boolean (and documented as such) so this new control flow is clear and less error-prone if the function is modified later.
- Consider logging the workspace ID or more context in the warning (`SSH tunnel not ready, falling back...`) to make it easier to correlate logs when multiple workspaces are active.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov

codecov Bot commented Mar 4, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.31%. Comparing base (25d0387) to head (a9afe68).

Files with missing lines Patch % Lines
devlaunch/dl.py 66.66% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #32      +/-   ##
==========================================
- Coverage   82.45%   82.31%   -0.15%     
==========================================
  Files           9        9              
  Lines        1174     1176       +2     
==========================================
  Hits          968      968              
- Misses        206      208       +2     
Files with missing lines Coverage Δ
devlaunch/dl.py 82.23% <66.66%> (-0.28%) ⬇️

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Just calling workspace_up() on an already-running container doesn't fix
a broken tunnel — devpod exits early. Stopping first forces a clean
restart so the tunnel is properly re-established.
@blooop

blooop commented Aug 14, 2026

Copy link
Copy Markdown
Owner Author

Closing as obsolete — the code this patches no longer exists.

The diff rewrites the fast-attach block around setup_work_symlink(workspace_id) and get_work_symlink_path(workspace_id). Neither function is in the tree any more:

$ grep -rn 'setup_work_symlink\|get_work_symlink_path' devlaunch/
(no matches)

The whole work-symlink mechanism was removed, and the fast-attach path was rewritten since (#145 among others). The branch is 220 commits behind main and conflicts; there is nothing to rebase it onto, because its subject was deleted rather than moved.

Its required prek check has been failing since March and the run logs have expired (HTTP 410), so the original failure is no longer even diagnosable.

If a fast-attach still falls back when the SSH tunnel is not ready, that is worth a fresh issue against the current attach path (attach_workspace, dl.py:2120) — the symptom may well survive, but no line of this patch does.

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.

1 participant