Skip to main content

serve

Function serve 

Source
pub async fn serve(opts: Opts) -> Result<()>
Expand description

Serve the UI until Ctrl-C, finishing a run the loop has in flight.

The server itself owns no state, so nothing here is graceful for the HTTP side’s sake: the connections go with the dropped listener, which costs a phone one change-stream reconnection it was going to make anyway.

The signal branch is not optional now that the loop lives in this process. daemon::serve_until listens for Ctrl-C itself, and a registered handler is what stops the signal terminating the process - so without a branch of our own, the first Ctrl-C after the operator started the loop would stop the loop and leave magi web listening forever, unkillable from the terminal it was started in.

What it waits for is the loop, not the sockets. A run in flight is finished first, for the reason daemon::serve gives: killing the graph mid-node leaves worktrees, branches and agent sessions behind and throws away every agent call already paid for. Bind the port, waiting briefly for a predecessor to let go of it.

A restart hands the address from one process to the next, and the old one holds its listener until it unwinds. A single bind can lose that race, and for a restart triggered from a phone that means the deck never comes back with no terminal around to say why.

Bounded, and only for the one error a wait can fix: anything else fails at once, because retrying it would turn a clear message into a silence.