4.1 KiB
4.1 KiB
Process and Session Lifecycle Roadmap
Generated via AI on April 14th, 2026
Why this exists
The current implementation now has a minimum-correct ownership model:
Sessionowns both the proxy server and spawned process.Session.Stop()directly requests process shutdown and proxy shutdown.- process exit status is emitted for both success (
ExitCode=0) and failures.
This document captures the next iteration so lifecycle behavior remains predictable as the project grows.
Current baseline (after the minimal fix)
- Process startup and waiting are split:
- startup returns a process handle immediately
- waiting happens in a background goroutine
- Unix signaling still targets process groups (
Setpgid+ negative PID) with TERM -> KILL escalation. - Proxy shutdown is called explicitly by session stop.
http.ErrServerClosedis treated as normal during proxy shutdown.
Known limitations we should address next
-
Exit reason ambiguity
- We emit
ProcessSignaledwhen stopping andProcessExitedwhen wait returns, but we do not explicitly encode whether exit was natural, requested by user, or forced by kill escalation.
- We emit
-
Platform parity
- Non-Unix builds only signal the direct process and cannot reliably kill full process trees.
-
Shutdown ordering is not coordinated
- process stop and proxy shutdown are both requested, but there is no single orchestrated timeout policy across the whole session.
-
Session completion is implicit
- no explicit "session done" event or
Wait()API to know when all workers have quiesced.
- no explicit "session done" event or
-
Message channel lifecycle
- channel is currently long-lived and not explicitly closed; this is safe for current flow, but not ideal for future composition/testing.
Proposed future design
1) Introduce lifecycle controllers
Add small controller types with clear contracts:
ProcessControllerStart(cmd, env) errorStop(ctx) error(TERM then KILL by deadline)Wait() ProcessResult
ProxyControllerStart(listener) errorStop(ctx) errorWait() error
Reasoning:
- encapsulates resource ownership and synchronization
- avoids session-level ad hoc goroutines
- easier to unit-test
2) Move to context-driven shutdown
Use a parent context for a session and cancellation for coordinated stop.
Reasoning:
- one source of truth for shutdown intent
- natural propagation to future subcomponents
- easier timeout management than cross-goroutine signal channels
3) Add explicit process exit metadata
Define fields such as:
ExitReason:natural,signal,forced_kill,start_failed,runtime_errorSignal: optional signal value when applicable
Reasoning:
- accurate UI and logs
- better postmortem behavior for flaky commands
4) Add session-level graceful stop policy
Implement deterministic sequence with deadlines, for example:
- request process graceful stop
- wait up to
Xfor process completion - force kill process group if needed
- shutdown proxy with timeout
Y - wait for goroutines/controllers to finish
- emit
SessionStopped
Reasoning:
- easier reasoning about final state
- avoids races between TUI exit and backend teardown
5) Improve non-Unix behavior
If Windows support becomes a requirement, evaluate job objects or equivalent process-tree control.
Reasoning:
- current direct-process signaling can leak descendants
- parity with Unix lifecycle expectations
Implementation notes for the next pass
- Keep
internal/process/signal_unix.gologic as the Unix baseline. - Rename
DestorytoDestroywith a compatibility shim or bulk rename. - Handle
net.ErrClosedandhttp.ErrServerClosedas expected proxy shutdown outcomes. - Add targeted tests:
- clean exit (
ExitCode=0) - non-zero exit
- TERM then forced KILL
- spawned child process cleanup on Unix process groups
- proxy shutdown does not emit fatal on normal close
- clean exit (
Suggested milestones
- Controller extraction without behavior change
- Exit reason metadata and event model updates
- Context-based coordinated stop
- Platform-specific process-tree improvements (if needed)