1. High-Level Summary (TL;DR)
- Impact: [Medium] - Significantly improves the stability of SSE tunnel connections and fixes stdout stream separation (logs/status moved to stderr where they belong).
- Key Changes:
- Logging Refactor: Switched tracing logs and CLI completion messages (
push complete,pull complete) to usestderrinstead ofstdout, keepingstdoutas a clean data channel for piping (e.g.tunnix exec remote -- 'cat file' | gzip > file.gz). - Connection Timeout: Introduced a strict 15-second timeout (
SSE_CONNECT_TIMEOUT) for establishing SSE connections to prevent indefinite hangs. - Stabilized Recovery: Eliminated session ID rotation on HTTP 503 "unknown session" errors. It now forces an SSE reconnect to stabilize recovery and prevent rotation "death spirals."
- Race Condition Fix: Fixed a synchronization race condition in the reconnect signaling flow by registering interest before firing the signal.
- Architecture Docs: Updated the internal wiki to accurately reflect the new connection recovery and session handling logic.
- Logging Refactor: Switched tracing logs and CLI completion messages (
2. Visual Overview (Code & Logic Map)
graph TD
classDef method fill:#bbdefb,color:#0d47a1,stroke:#0d47a1;
classDef action fill:#fff3e0,color:#e65100,stroke:#e65100;
subgraph "src/tunnel.rs"
A["send_message()"]:::method --> B{"try_post()"}:::method
B -- "Success" --> C["Return Ok"]:::action
B -- "Failure (e.g. 503)" --> D["reconnect_signal.notify_one()"]:::action
D --> E["Wait for sse_ready"]:::action
E --> F["try_post() retry"]:::method
G["sse_read_loop()"]:::method --> H["GET /stream/{sid}"]:::action
H -- "SSE_CONNECT_TIMEOUT (15s)" --> I["Drain reconnect_signal"]:::action
I --> J["sse_ready.notify_waiters()"]:::action
end
D -. "Triggers" .-> G
J -. "Wakes up" .-> E
3. Detailed Change Analysis
🔄 Tunnel Connection & Recovery
- What Changed: Modified the recovery strategy in
send_message()when a POST request fails. Previously, a 503 error caused the client to generate a new session ID and clear response channels. Now, the session ID remains stable, and the client forces an SSE reconnect. This allows the server to recreate the session on the nextGET /stream/{sid}and announce freshness via aResetevent. (Source:src/tunnel.rs) - What Changed: Added a 15-second timeout (
SSE_CONNECT_TIMEOUT) to the SSEGETrequest. Because thehttp_clienthas no global timeout, a half-open connection could wedgesend().awaitforever. (Source:src/tunnel.rs) - What Changed: Added logic to securely drain any
reconnect_signalpermits that were buffered during connection setup. This ensures that a stale reconnect signal doesn't immediately tear down a freshly established stream. (Source:src/tunnel.rs) - What Changed: Fixed a race condition in
send_message()by callingready.as_mut().enable()before notifying the reconnect signal, guaranteeing the notification isn't missed by the event loop. (Source:src/tunnel.rs) - What Changed: Changed
try_postto takebytes::Bytesinstead of&[u8], eliminating unnecessary copying when a message retry occurs. (Source:src/tunnel.rs)
Configuration Updates
| Constant | Old Value | New Value | Description |
|---|---|---|---|
RECONNECT_WAIT
| 10s | 20s | Time send_message waits for the SSE stream to become ready after forcing a reconnect.
|
SSE_CONNECT_TIMEOUT
| N/A | 15s | Strict bound on establishing the SSE GET connection. |
📝 CLI & Logging
- What Changed: Changed the default
tracing_subscriberoutput fromstdouttostderr. Also updated "push complete" and "pull complete" messages to useeprintln!instead ofprintln!. Rationale:tunnix execstreams remote process output throughstdout(src/exec.rs). If tracing logs were interleaved onstdout, piped output liketunnix exec remote -- 'cat file' | gzip > file.gzwould be corrupted. Moving logs and status banners tostderrfollows the Unix convention of reservingstdoutfor data andstderrfor diagnostics. (Source:src/main.rs,src/exec.rs)
📚 Documentation
- What Changed: Updated
wiki/architecture.mdto document the newsession_idhandling, explaining why it is deliberately not rotated on 503 errors and documenting the new timeout parameters. (Source:wiki/architecture.md)
4. Impact & Risk Assessment
- Breaking Changes: None. Status messages and logging now correctly go to
stderr, reservingstdoutexclusively for data output (e.g. remote process streams fromtunnix exec). This was a bug — status messages never belonged onstdoutand could corrupt piped output.