Skip to content

[Factory Experiment] fix(proxy): join spawned tasks before cleanup to prevent orphaning - #163

Closed
timanglade wants to merge 2 commits into
NetSys:mainfrom
timanglade:tpa/im-67-proxy-task-orphaning-on-early-exit
Closed

timanglade wants to merge 2 commits into
NetSys:mainfrom
timanglade:tpa/im-67-proxy-task-orphaning-on-early-exit

Conversation

@timanglade

Copy link
Copy Markdown
Collaborator

Part of an experiment with setting up an automated software factory. Authored by Gas Town on Kilo, using DeepSeek V4 Pro / DeepSeek V4 Flash running on Fireworks. The factory was only fed the content of IM-67, then left completely unsupervised.

Summary

  • Kept JoinHandles for the spawned DNS handler and local acceptor tasks in Handle::run
  • After run_external_acceptor returns, cancel the token and join both spawned tasks
  • Ensures defer!(nftables_clean()) only fires after all handlers have stopped
  • Prevents a race where nftables rules are removed while the local listener is still accepting connections

Details

Previously, run_external_acceptor consumed the cancel token. When it exited (stream end or cancellation), defer!(nftables_clean()) fired immediately — before the spawned DNS and local acceptor tasks could observe the daemon's cancel.cancel(). This left a window where nftables rules were gone but listeners were still active.

The fix clones cancel for run_external_acceptor, then calls cancel.cancel() and tokio::join! on both handles before returning. This guarantees all handlers have stopped before nftables cleanup runs.

@timanglade timanglade changed the title fix(proxy): join spawned tasks before cleanup to prevent orphaning [Factory Experiment] fix(proxy): join spawned tasks before cleanup to prevent orphaning Jun 19, 2026
@timanglade

Copy link
Copy Markdown
Collaborator Author

I don't seem to have permissions to assign reviewers anymore, but pinging @ejj-agent to see if I can get it to review this PR via a comment. cc @ejj.

@ejj
ejj requested a review from ejj-agent June 20, 2026 20:50

@ejj-agent ejj-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI-generated review draft. This has not been reviewed by a human. Any comments made are non-binding; feel free to ignore them by resolving. This uses the same AI-review process Ethan uses to review his own code.

Overall review body

I reviewed the proxy lifecycle change in src/proxy/mod.rs for correctness, simplicity, diff hygiene, and tests. I did not find any substantive concerns worth posting: the diff is narrowly scoped, the cancellation/join ordering matches the intended cleanup sequencing for the DNS and local acceptor tasks, and the existing targeted unit test still passes.

Checks run locally on the PR head: cargo test test_parse_connect_target.

AI-PR-Review: #163 dc0a77e

@timanglade
timanglade force-pushed the tpa/im-67-proxy-task-orphaning-on-early-exit branch from dc0a77e to 247b78d Compare June 20, 2026 22:20
@timanglade timanglade closed this Jun 20, 2026
@timanglade
timanglade force-pushed the tpa/im-67-proxy-task-orphaning-on-early-exit branch from 247b78d to 2942493 Compare June 20, 2026 22:22
When run_external_acceptor exits (stream end or cancellation),
defer!(nftables_clean()) used to fire immediately, removing nftables
rules before the spawned DNS handler and local acceptor tasks could
observe cancellation. Now we cancel and join both spawned tasks before
returning, so nftables rules stay in place until all handlers stop.
@timanglade timanglade reopened this Jun 20, 2026
@timanglade

Copy link
Copy Markdown
Collaborator Author

Sorry for the noise, agent messed up the rebase due to a different factory experiment having created a branch with the same name, Should be all good now.

Reverted all source and interface doc renames back to modular structure
(src/*/mod.rs, context/interfaces/src/*/mod.md). Restored .claude/CLAUDE.md.
The proxy fix in src/proxy/mod.rs is preserved: clones CancellationToken
before moving into run_external_acceptor, stores JoinHandles for spawned
DNS and local acceptor tasks, and calls cancel.cancel() + tokio::join!
before returning to ensure nftables_clean() only fires after handlers stop.
@timanglade

Copy link
Copy Markdown
Collaborator Author

I'm not sure why Gas Town picked up this PR again and started doing more work on it when it did; another good reason to avoid it for now I guess. Closing this PR.

@timanglade timanglade closed this Jun 25, 2026
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