aicam opened a new pull request, #6240:
URL: https://github.com/apache/texera/pull/6240

   ### What changes were proposed in this PR?
   
   Fixes two distinct `y-websocket` (`/rtc`) connection leaks in the 
shared-editing code path. Both live on `SharedModel` → `WebsocketProvider`, and 
together they let the number of open realtime connections grow far out of 
proportion to the number of users until the shared-editing connection cap is 
exhausted and collaborative cursors/awareness stop syncing.
   
   **Leak B — throwaway validation graph opens a socket per edit (dominant).**
   On every operator/link/property edit, `WorkflowCompilingService` builds a 
throwaway `WorkflowGraph` via `ValidationWorkflowService.getValidTexeraGraph()` 
just to produce a logical plan for compilation. `WorkflowGraph`'s constructor 
**unconditionally** creates a `SharedModel`, which **unconditionally** opens a 
new auto-connecting `/rtc` WebSocket in a random room. That graph is read once 
and never destroyed, so each edit leaks a socket that reconnects forever. A 
single user editing a workflow accumulates dozens of permanent sockets.
   
   Fix: thread an `enableSharedEditing` flag from `WorkflowGraph` into 
`SharedModel`. When `false`, `SharedModel` skips the `WebsocketProvider` 
entirely and uses a standalone `Awareness` so downstream reads of 
`awareness`/`clientId` keep working. 
`ValidationWorkflowService.getValidTexeraGraph()` now passes `false`, so 
validation/compilation graphs never touch the network.
   
   **Leak A — incomplete provider teardown (per-navigation).**
   `SharedModel.destroy()` called `wsProvider.disconnect()` (and only when the 
socket happened to be OPEN). In `[email protected]`, `disconnect()` does not 
clear the provider's `_checkInterval`/`_resyncInterval` reconnect timers, so 
the provider is never garbage-collected and, if it was mid-reconnect at destroy 
time (common during workflow switches), keeps re-opening a zombie socket for 
the life of the tab.
   
   Fix: call `wsProvider.destroy()` unconditionally, which clears those timers, 
removes the `beforeunload` handler, broadcasts awareness removal (peers drop 
our cursor), and closes the socket.
   
   **Supporting changes.** `wsProvider` is now optional (`WebsocketProvider | 
undefined`), so its remaining access sites in `WorkflowActionService` 
(`setTempWorkflow` / `resetTempWorkflow`) use `?.`, and the 
`mock-workflow-plan.ts` fixtures pass `enableSharedEditing = false` so unit 
tests open no sockets. Behavior for the real collaborative graph is unchanged: 
it still constructs a `WebsocketProvider` exactly as before.
   
   Files changed:
   - `frontend/src/app/workspace/service/workflow-graph/model/shared-model.ts` 
— optional/local-mode provider; correct `destroy()`.
   - 
`frontend/src/app/workspace/service/workflow-graph/model/workflow-graph.ts` — 
thread `enableSharedEditing`.
   - 
`frontend/src/app/workspace/service/validation/validation-workflow.service.ts` 
— pass `false` for the throwaway graph.
   - 
`frontend/src/app/workspace/service/workflow-graph/model/workflow-action.service.ts`
 — `wsProvider?.` null-safety.
   - 
`frontend/src/app/workspace/service/execute-workflow/mock-workflow-plan.ts` — 
fixtures open no sockets.
   
   ### Any related issues, documentation, discussions?
   
   Fixes #6239.
   
   ### How was this PR tested?
   
   Existing frontend unit tests continue to pass; the `mock-workflow-plan.ts` 
fixtures were updated to construct their graphs local-only so tests no longer 
open real `/rtc` sockets.
   
   Manual verification, client-side (browser DevTools → Network → **WS** 
filter):
   1. Open a workflow → exactly **one** `/rtc` WebSocket (unchanged).
   2. Add/delete operators, edit properties, add/remove links repeatedly → the 
count stays at **one** (before this change, a new socket appeared on every edit 
and kept reconnecting).
   3. Switch workflow A → B → the old socket closes and one new socket opens 
(count stays 1).
   4. Navigate to the dashboard / close the tab → the socket closes (count → 
0), with no lingering reconnects.
   
   The same behavior is observable server-side by counting established 
connections to the y-websocket server while a single user edits: after this 
change the count stays flat (≈ number of open collaborative tabs) and drops 
when tabs close, instead of climbing with every edit.
   
   ### Was this PR authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (Claude Opus 4.8)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to