Skip to content

fix(tunnel): join tunnel goroutine on handler exit - #1013

Merged
skevetter merged 2 commits into
mainfrom
pkg-tunnel-network/join-handler-first-tunnel
Aug 13, 2026
Merged

skevetter merged 2 commits into
mainfrom
pkg-tunnel-network/join-handler-first-tunnel

Conversation

@devsy-app

@devsy-app devsy-app Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Package reviewed

pkg/tunnel — pipebridge.go awaitPair (the goroutine-join path of RunPair).

Issue found

awaitPair waits on two goroutines: the tunnel forwarder and the user handler. The
two completion branches were asymmetric:

  • When the tunnel finished first, the branch cancelled the context, closed the
    stdin/stdout pipe write ends, and then joined the handler goroutine
    (handlerErr = <-handlerChan) so awaitPair only returned once both sides were done.
  • When the handler finished first, the branch only did a non-blocking
    select { case tunnelErr = <-tunnelChan: default: }. It did not cancel the
    context, did not close the pipe write ends, and did not join the tunnel
    goroutine. awaitPair returned immediately while the tunnel goroutine kept running.

Because the tunnel forwarder blocks reading from its stdin pipe, and the stdin write
end is never closed on the handler-first path, the tunnel goroutine blocks forever on
that read — it is orphaned/leaked. This is a goroutine leak plus a file-descriptor leak
(the pipe write ends are left open). The tunnel goroutine is never joined, so any
error it returns is also silently dropped.

Change

Make the handler-first branch symmetric with the tunnel-first branch: on handler
completion, cancel the context, close the stdout/stdin pipe write ends, and join
the tunnel goroutine (tunnelErr = <-tunnelChan) before returning. This ensures both
goroutines are reaped and their errors are surfaced through ClassifyTunnelErrors,
matching the existing tunnel-first behavior.

This is a focused correctness fix (no behavioral change for the already-correct
tunnel-first path), keeping RunPair symmetric regardless of which side completes first.

Verification

  • task cli:format — clean.
  • task cli:lint:ci — 0 new issues.
  • task cli:test — pkg/tunnel passes (ok ... coverage: 37.3%). The only failing
    package is pkg/git (TestRepoClone*), a known pre-existing failure on
    origin/main unrelated to this change (my change does not touch pkg/git).
  • New regression test TestRunPairJoinsTunnelWhenHandlerFinishesFirst:
    • On the old code it hangs (the orphaned tunnel goroutine never exits), failing
      after the 2s test timeout with tunnel goroutine was orphaned when handler finished first.
    • On the fixed code it passes (the tunnel goroutine exits promptly once the pipe is
      closed and is joined before RunPair returns).
  • No proto files changed, so task cli:build:grpc was not required.

This PR was created by an AI agent as part of an automated daily package review job.

awaitPair returned without joining the tunnel goroutine when the handler completed first, leaving the tunnel blocked on its stdin pipe read and orphaning both the goroutine and the pipe write ends. Mirror the tunnel-first branch: cancel the context, close the pipe write ends, then join the tunnel goroutine so its error is surfaced and no goroutine is leaked. Add TestRunPairJoinsTunnelWhenHandlerFinishesFirst as a regression guard.
@netlify

netlify Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for devsydev ready!

Name Link
🔨 Latest commit 8ae61e7
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a7c9f4880a3cd00083da7f5
😎 Deploy Preview https://deploy-preview-1013--devsydev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for images-devsy-sh canceled.

Name Link
🔨 Latest commit 8ae61e7
🔍 Latest deploy log https://app.netlify.com/projects/images-devsy-sh/deploys/6a7c9f48f5b0bf00081dfc79

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 7 complexity · 1 duplication

Metric Results
Complexity 7
Duplication 1

View in Codacy

AI Reviewer: run a review on demand. To trigger the first review automatically, go to your organization or repository integration settings. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@skevetter
skevetter marked this pull request as ready for review August 13, 2026 13:36
@skevetter
skevetter merged commit 7cb3d93 into main Aug 13, 2026
115 of 117 checks passed
@skevetter
skevetter deleted the pkg-tunnel-network/join-handler-first-tunnel branch August 13, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant