[ 
https://issues.apache.org/jira/browse/GUACAMOLE-2303?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ciro Iriarte updated GUACAMOLE-2303:
------------------------------------
    Description: 
h2. Summary

Add an optional session-resume capability so a short network drop doesn't end a 
Guacamole session. Today a stall longer than ~15s closes the tunnel, and the 
built-in reconnect starts a new session, so the user loses their work. This 
lets the client rejoin the same live session instead. It's off by default.

h2. Problem

When the browser-to-server link stalls, the client tunnel's receiveTimeout 
(default 15000ms) fires and the tunnel closes. The built-in reconnect then 
opens a new connection, so the previous guacd session is gone and the user is 
back at a login/parameter prompt with their work lost. There's currently no way 
to recover a session after a drop.

The 15s threshold is easier to hit than it sounds:
* TCP retransmission backoff stretches short drops. On a netem test rig, an ~8s 
outage left the tunnel frozen for ~14s, and a 20s outage closed the session.
* Ordinary WAN/mobile events go past it: Wi-Fi handoff and DHCP renewal, 
cellular dead zones, VPN reconnects, laptop sleep/resume, NAT rebinding, and 
background-tab throttling (the client's pings pause and a proxy idle timeout 
then closes the socket).

h2. Proposal

Let a reconnecting client rejoin its existing guacd connection instead of 
starting a new one. Three parts:

# guacd: an optional grace window on connection-sharing teardown. When the last 
user of a connection disconnects, hold it for a configurable number of seconds 
(GUACD_RESUME_GRACE, default 0 = off) before tearing it down, so a reconnecting 
client can rejoin by connection ID. This uses the existing {{$<uuid>}} join 
path.
# guacamole-client webapp: a session-scoped registry mapping a resume token to 
the guacd connection ID. A reconnect that presents the token rejoins via 
{{select $uuid}} (owner-checked, time-limited), and the old tunnel is closed.
# guacamole-common-js and the Angular client: a reconnect controller that, 
after a drop on a connection that had reached OPEN, opens a fresh 
WebSocketTunnel on the same Guacamole.Client (keeping display, input, and 
streams), sends the resume token, and redisplays the last frame during the gap.

This also fixes a related problem: a dropped tunnel was reported as a terminal 
TUNNEL_ERROR, which started the existing 15s reconnect-countdown notification 
and replaced the client that had already resumed.

h2. Configuration and scope

* Off by default. GUACD_RESUME_GRACE defaults to 0 and the client controller is 
disabled, so existing installs behave exactly as before.
* Suggested control: enable it per connection, with a server-side maximum 
grace. Calling it "session resume" rather than a broad "WAN mode" seems clearer.
* It should be possible to turn off, and it should be off for share/anonymous 
connections and anywhere a hard drop on disconnect is required.

h2. Evidence

* Recovers a 20s outage in every trial (8/8 through an nginx reverse proxy, 2/2 
direct), rejoining the same guacd session (guacd logs {{Joining existing 
connection $<uuid>}}) with work intact.
* Tested on SSH and VNC (VNC replays its framebuffer on rejoin).
* No change to steady-state input latency, which is bound by round-trip time 
and isn't the target here.
* guacamole-common-js karma tests pass, including new coverage for the 
reconnect tunnel lifecycle.

h2. Non-goals

* Not HA or session migration. The registry is per-JVM and in-memory, and 
relies on the same session affinity the existing in-memory auth-token map 
already needs. Rejoining across nodes is out of scope.
* Not a bandwidth or latency optimization; it's about recovering from a drop.

h2. Compatibility and risk

* The grace window holds a guacd session briefly after its last user leaves, 
which changes teardown timing and uses resources, so it's opt-in and bounded.
* The resume token is currently the client-facing tunnel UUID; an opaque 
single-use token would be a good follow-up.
* A "reconnecting" overlay with a manual retry is worth adding before enabling 
this widely, since users tend to hit refresh, which throws away the client 
state and prevents the resume.

h2. Patch

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

I can submit these as separate PRs and adjust the configuration to whatever 
you'd prefer. A reasonable order:
# diagnostics/telemetry (off by default)
# client reconnect-lifecycle hardening (ignore stale tunnels, don't raise a 
terminal error during an active retry, clean tunnel swap)
# the resume feature (guacd grace + webapp rebind + client controller)
# the reconnecting overlay and manual retry


  was:
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.


        Summary: [RFC] Optional session resume so a short network drop does not 
end the session  (was: [RFC] Opt-in work-preserving session resume across 
transient network drops)

> [RFC] Optional session resume so a short network drop does not end the session
> ------------------------------------------------------------------------------
>
>                 Key: GUACAMOLE-2303
>                 URL: https://issues.apache.org/jira/browse/GUACAMOLE-2303
>             Project: Guacamole
>          Issue Type: New Feature
>            Reporter: Ciro Iriarte
>            Priority: Major
>
> h2. Summary
> Add an optional session-resume capability so a short network drop doesn't end 
> a Guacamole session. Today a stall longer than ~15s closes the tunnel, and 
> the built-in reconnect starts a new session, so the user loses their work. 
> This lets the client rejoin the same live session instead. It's off by 
> default.
> h2. Problem
> When the browser-to-server link stalls, the client tunnel's receiveTimeout 
> (default 15000ms) fires and the tunnel closes. The built-in reconnect then 
> opens a new connection, so the previous guacd session is gone and the user is 
> back at a login/parameter prompt with their work lost. There's currently no 
> way to recover a session after a drop.
> The 15s threshold is easier to hit than it sounds:
> * TCP retransmission backoff stretches short drops. On a netem test rig, an 
> ~8s outage left the tunnel frozen for ~14s, and a 20s outage closed the 
> session.
> * Ordinary WAN/mobile events go past it: Wi-Fi handoff and DHCP renewal, 
> cellular dead zones, VPN reconnects, laptop sleep/resume, NAT rebinding, and 
> background-tab throttling (the client's pings pause and a proxy idle timeout 
> then closes the socket).
> h2. Proposal
> Let a reconnecting client rejoin its existing guacd connection instead of 
> starting a new one. Three parts:
> # guacd: an optional grace window on connection-sharing teardown. When the 
> last user of a connection disconnects, hold it for a configurable number of 
> seconds (GUACD_RESUME_GRACE, default 0 = off) before tearing it down, so a 
> reconnecting client can rejoin by connection ID. This uses the existing 
> {{$<uuid>}} join path.
> # guacamole-client webapp: a session-scoped registry mapping a resume token 
> to the guacd connection ID. A reconnect that presents the token rejoins via 
> {{select $uuid}} (owner-checked, time-limited), and the old tunnel is closed.
> # guacamole-common-js and the Angular client: a reconnect controller that, 
> after a drop on a connection that had reached OPEN, opens a fresh 
> WebSocketTunnel on the same Guacamole.Client (keeping display, input, and 
> streams), sends the resume token, and redisplays the last frame during the 
> gap.
> This also fixes a related problem: a dropped tunnel was reported as a 
> terminal TUNNEL_ERROR, which started the existing 15s reconnect-countdown 
> notification and replaced the client that had already resumed.
> h2. Configuration and scope
> * Off by default. GUACD_RESUME_GRACE defaults to 0 and the client controller 
> is disabled, so existing installs behave exactly as before.
> * Suggested control: enable it per connection, with a server-side maximum 
> grace. Calling it "session resume" rather than a broad "WAN mode" seems 
> clearer.
> * It should be possible to turn off, and it should be off for share/anonymous 
> connections and anywhere a hard drop on disconnect is required.
> h2. Evidence
> * Recovers a 20s outage in every trial (8/8 through an nginx reverse proxy, 
> 2/2 direct), rejoining the same guacd session (guacd logs {{Joining existing 
> connection $<uuid>}}) with work intact.
> * Tested on SSH and VNC (VNC replays its framebuffer on rejoin).
> * No change to steady-state input latency, which is bound by round-trip time 
> and isn't the target here.
> * guacamole-common-js karma tests pass, including new coverage for the 
> reconnect tunnel lifecycle.
> h2. Non-goals
> * Not HA or session migration. The registry is per-JVM and in-memory, and 
> relies on the same session affinity the existing in-memory auth-token map 
> already needs. Rejoining across nodes is out of scope.
> * Not a bandwidth or latency optimization; it's about recovering from a drop.
> h2. Compatibility and risk
> * The grace window holds a guacd session briefly after its last user leaves, 
> which changes teardown timing and uses resources, so it's opt-in and bounded.
> * The resume token is currently the client-facing tunnel UUID; an opaque 
> single-use token would be a good follow-up.
> * A "reconnecting" overlay with a manual retry is worth adding before 
> enabling this widely, since users tend to hit refresh, which throws away the 
> client state and prevents the resume.
> h2. Patch
> Implemented on forks, branch wan-optimization:
> * github.com/ciroiriarte/guacamole-server -- guacd grace window
> * github.com/ciroiriarte/guacamole-client -- webapp rebind, client reconnect 
> controller, diagnostics
> * github.com/ciroiriarte/guacamole-manual -- reverse-proxy WAN-tuning docs
> I can submit these as separate PRs and adjust the configuration to whatever 
> you'd prefer. A reasonable order:
> # diagnostics/telemetry (off by default)
> # client reconnect-lifecycle hardening (ignore stale tunnels, don't raise a 
> terminal error during an active retry, clean tunnel swap)
> # the resume feature (guacd grace + webapp rebind + client controller)
> # the reconnecting overlay and manual retry



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

Reply via email to