Ciro Iriarte created GUACAMOLE-2303:
---------------------------------------

             Summary: [RFC] Opt-in work-preserving session resume across 
transient network drops
                 Key: GUACAMOLE-2303
                 URL: https://issues.apache.org/jira/browse/GUACAMOLE-2303
             Project: Guacamole
          Issue Type: New Feature
            Reporter: Ciro Iriarte


h2. Summary

This RFC proposes an *opt-in, work-preserving session resume* capability so a 
Guacamole session survives a transient network drop instead of dying and 
forcing the user back to a fresh login with lost work. It is *off by default* 
and changes no existing behavior.

h2. Problem

When the browser{{<->}}server link stalls, the client tunnel's 
{{receiveTimeout}} (default 15000ms) fires and the tunnel self-closes. The 
built-in reconnect then establishes a *brand-new* connection -- the previous 
guacd session is gone, so the user is returned to a login/parameter prompt and 
loses whatever they were doing. A transient drop is therefore not recoverable 
today.

Two points make this reach real users rather than only long outages:
* The 15s threshold is easier to hit than a 15s outage, because TCP 
retransmission backoff amplifies short drops. On a controlled {{netem}} rig, an 
~8s blackout produced a ~14s frozen tunnel; a 20s blackout killed the session.
* Common WAN/mobile events exceed it: Wi-Fi AP handoff + DHCP renewal, cellular 
dead zones (trains/tunnels/elevators), VPN reconnects, laptop sleep/resume, NAT 
rebinding, and background-tab timer throttling (client pings pause, then a 
reverse-proxy idle timeout closes the socket).

h2. Proposal

A three-tier, opt-in mechanism that lets a reconnecting client *rejoin the same 
live guacd connection* rather than start a new one:

# *guacd* -- a bounded grace window on the connection-sharing teardown path. 
When the last user of a shared connection disconnects, optionally hold the 
connection for a short configurable period ({{GUACD_RESUME_GRACE}} seconds, 
default {{0}} = off) before teardown, so a reconnecting client can rejoin it by 
connection ID. Reuses the existing {{$<uuid>}} join path; no new subsystem.
# *guacamole-client webapp* -- a session-scoped resume registry mapping a 
client-held resume token to the guacd connection ID. A reconnect presenting the 
token rebinds via {{select $uuid}} (owner-checked and time-bounded); the 
abandoned prior tunnel is reaped on resume.
# *guacamole-common-js + webapp (Angular)* -- a reconnect controller that, on a 
retryable drop after the connection had reached OPEN, reconnects over a *fresh* 
{{Guacamole.WebSocketTunnel}} on the *same* {{Guacamole.Client}} (preserving 
display, input, and streams), appending the resume token. The last-rendered 
frame is redisplayed during the gap.

Also included: suppression of a spurious teardown where a dropped tunnel 
surfaced as a terminal {{TUNNEL_ERROR}}, which armed the stock 15s 
reconnect-countdown notification and replaced the already-resumed client.

h2. Configuration and scope

* *Off by default*, entirely opt-in. {{GUACD_RESUME_GRACE}} defaults to {{0}}; 
the client reconnect controller defaults to disabled. Existing deployments are 
unaffected.
* Recommended surface: enable per-connection (an admin-set connection 
parameter) with a global server-side maximum grace. Suggested framing is 
"session resume" / "keep session alive", not a broad "WAN mode".
* Should be disable-able, and off, for share/anonymous connections and for 
security profiles that require a hard drop on disconnect.

h2. Evidence

* Recovers a hard 20s outage *10/10* end to end -- 8/8 through an nginx reverse 
proxy (the typical production topology) and 2/2 direct -- with the same guacd 
session rejoined ({{Joining existing connection $<uuid>}}) and work preserved.
* Verified on both *SSH* and *VNC* (bitmap framebuffer replays on rejoin).
* No change to steady-state input latency (that is RTT-bound and explicitly not 
a goal here).
* guacamole-common-js karma suite green, including added coverage for the 
reconnect tunnel lifecycle.

h2. Non-goals

* Not HA / session migration: the resume registry is per-JVM in-memory and 
relies on the same session affinity that Guacamole's existing in-memory 
auth-token map already requires. Cross-node resume is out of scope.
* Not a bandwidth or latency optimization; it targets *recoverability*, not 
throughput.

h2. Compatibility and risk

* The grace window intentionally holds a guacd session briefly after its last 
user leaves (a resource and disconnect-semantics change) -- hence opt-in, 
bounded, and per-connection.
* Resume tokens are currently the client-facing tunnel UUID; an opaque, 
single-use token is a recommended follow-up.
* A "reconnecting..." overlay plus manual-resume fallback is recommended before 
broad rollout, because the user's instinct to press F5/refresh destroys client 
state and prevents resume.

h2. Patch offering

Implemented on forks, branch {{wan-optimization}}:
* {{github.com/ciroiriarte/guacamole-server}} -- guacd grace window
* {{github.com/ciroiriarte/guacamole-client}} -- webapp resume rebind + client 
reconnect controller + connection diagnostics
* {{github.com/ciroiriarte/guacamole-manual}} -- reverse-proxy WAN-tuning 
documentation

Happy to submit as staged, reviewable pull requests and to align the 
configuration surface with maintainer preferences. Suggested staging:
# Connection diagnostics/telemetry (off by default).
# Client reconnect-lifecycle hardening (stale-tunnel isolation, no terminal 
error during active retry, clean tunnel swap).
# The bounded per-connection resume feature (guacd grace + webapp rebind + 
client controller).
# The "reconnecting" overlay and manual-resume fallback.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to