Skip to content

daemon: gracefully shutdown if proxy wrapped command exits - #166

Open
patricklyc wants to merge 1 commit into
NetSys:mainfrom
patricklyc:main
Open

daemon: gracefully shutdown if proxy wrapped command exits#166
patricklyc wants to merge 1 commit into
NetSys:mainfrom
patricklyc:main

Conversation

@patricklyc

@patricklycpatricklyc commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Before this change, when the wrapped command in intermesh proxy -- <cmd> exits, a detached task calls process::exit directly, skipping the daemon's structured shutdown, leaving the host misrouted.

This commit ensures that the daemon gracefully shuts down if the wrapped command errors, exits or is killed by a signal.

Add three e2e tests to make sure the daemon exits with the correct status codes and cleans up nftable rules in all three scenarios.

@ejj
ejj requested review from ejj and ejj-agentJune 20, 2026 22:46

@ejj-agentejj-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.

I reviewed this for correctness, simplicity, diff hygiene, and test coverage. I did not find any substantive concerns worth posting. The daemon now routes wrapped-command completion through the existing shutdown path, and the added e2e coverage exercises zero exit, nonzero exit, signal termination, and nftables cleanup behavior.

Checks run locally: cargo test --no-run, cargo test --lib, and cargo fmt --check.

AI-PR-Review: #16611ae55f

@ejj-agent

Copy link
Copy Markdown
Collaborator

Comment directed by Ethan.

Small thing: the commit message would be a little clearer if it mentioned that the wrapping is via intermesh proxy (i.e. proxy -- <cmd>). Without that, “wrapped command” isn’t super clear.

Comment threadtests/e2e.rs
fn test_proxy_command_exit() {
let harness = Harness::new();

let proxy_cmd = r"intermesh proxy -- sleep 1";

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.

Comment directed by Ethan.

I don’t think this first container-main sleep 1 check adds much value over the cleanup path below. Could we drop this block and just keep the lower test path for a successful wrapped-command exit?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

The agent advised me to test the exit code contract. If that is unnecessary I can remove it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah I think chatgpt in particular is a little bit too aggressive about tests I think you can ditch it

Comment threadtests/e2e.rs
Comment threadsrc/daemon.rs Outdated
});
}
let mut task_status: Option<i32> = None;
let mut command_handle =

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.

Comment directed by Ethan.

I think this code is correct, but it isn't "obviously correct": the OptionFuture bit makes me work pretty hard to convince myself the no-command case is handled and that this branch only fires when a wrapped command exists.

Can we implement the same logic in a simpler way? For example, maybe keep the optional command task explicit and move the waiting/status decoding behind a small helper:

letmut command_handle = on_ready.map(|mut cmd| {
tokio::spawn(asyncmove{ cmd.status().await})});
...r = wait_for_wrapped_command(&mut command_handle) => {
task_status = Some(command_status_code(r));}

where wait_for_wrapped_command can make the None case explicit (e.g. it never completes when there is no wrapped command), and command_status_code handles the nested JoinHandle/io::Result cases. The exact shape isn't important; I just think the optional-command control flow should be easier to reason about here.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I have tried wrapping command_handle in async closures and helper functions, but I couldn't find anyway to fit it in a select! arm without OptionFuture. Would it help if I broke it out into two lines?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes I think breaking it into two lines and if it still isn't obviously correct adding a comment explaining it will help

@patricklycpatricklyc changed the title daemon: gracefully shutdown if wrapped command exitsdaemon: gracefully shutdown if wrapped command in intermesh proxy exitsJun 25, 2026
@patricklycpatricklyc changed the title daemon: gracefully shutdown if wrapped command in intermesh proxy exitsdaemon: gracefully shutdown if wrapped command exits with intermesh proxy Jun 25, 2026
@patricklycpatricklyc changed the title daemon: gracefully shutdown if wrapped command exits with intermesh proxy daemon: gracefully shutdown if proxy wrapped command exitsJun 25, 2026
@patricklyc
patricklycforce-pushed the main branch 2 times, most recently from 06990e6 to 9fe7fd6CompareJune 30, 2026 19:45
Before this change, when the command wrapped by intermesh proxy exits, a
detached task calls process::exit directly, skipping the
daemon's structured shutdown, leaving the host misrouted.
This commit ensures that the daemon gracefully shuts down
if the wrapped command errors, exits or is killed by a
signal.
Add three e2e tests to make sure the daemon exits with the
correct status codes and cleans up nftable rules in all
three scenarios.
Sign up for freeto 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.

3 participants

@patricklyc@ejj-agent@ejj