apache / apache/texera

Frontend leaks y-websocket (/rtc) connections, exhausting the shared-editing connection cap and breaking collaborative cursors

Open
#6,239 6 comments 0 reactions 0 assignees View on GitHub
Dominant language
Scala
Stars
314
Forks
187
Avg merge
1d 21h
Merged PRs (30d)
214

Description

### What happened?

The Texera frontend leaks `y-websocket` (`/rtc`) connections to the shared-editing server. During a collaborative editing session (roughly a dozen users co-editing at once), the number of established connections to the y-websocket server grows far out of proportion to the number of users and keeps climbing while people edit. Once a gateway/proxy's per-cluster connection limit is reached, new upstream connections are refused, so users **stop seeing each other's cursors** and awareness/presence stops syncing for anyone who (re)connects.

Symptoms:
- Tens of connections per user (far more than the expected ~1 per open tab).
- The connection count **climbs in real time while users edit**.
- It does **not** drop when a user leaves the workspace, and it **refills within seconds after the y-websocket server restarts** — because the leaked providers are detached, self-reconnecting objects living in open browser tabs.

The y-websocket server itself is not resource-constrained — this is a client-side connection leak, not a server capacity problem.

**Root cause — two distinct leaks, both on the `SharedModel` → `WebsocketProvider` code path:**

**Leak B (dominant, per-edit).** `WorkflowCompilingService` runs a compile-on-edit subscription that, on *every* operator/link/property edit, builds a throwaway `WorkflowGraph` for validation (`ValidationWorkflowService.getValidTexeraGraph()`). `WorkflowGraph`'s constructor **unconditionally** creates a `SharedModel`, which **unconditionally** opens a new `/rtc` WebSocket (auto-connecting, random room). The throwaway graph is read once (by `ExecuteWorkflowService.getLogicalPlanRequest`) and **never destroyed** → a brand-new WebSocket leaks on every edit and reconnects forever. A user building a 20-operator workflow generates dozens of edits → dozens of permanent sockets. This drives the disproportionate per-user count and the real-time climb.

**Leak A (secondary, per-navigation).** `SharedModel.destroy()` calls `wsProvider.disconnect()` (and only when currently connected) instead of `wsProvider.destroy()`. In `y-websocket@1.4.0`, `disconnect()` does **not** clear the provider's internal reconnect timer (`_checkInterval`), so the provider is never garbage-collected and — if it wasn't OPEN at destroy time (e.g. mid-reconnect during a workflow switch) — keeps reconnecting → a zombie socket per workflow switch/navigation.

Relevant source (all under `frontend/src/app/workspace/service/`):
- `workflow-graph/model/shared-model.ts` — the only `new WebsocketProvider` construction site; buggy `destroy()`.
- `workflow-graph/model/workflow-graph.ts` — constructor unconditionally does `new SharedModel()`.
- `validation/validation-workflow.service.ts` — `getValidTexeraGraph()` builds the throwaway graph per edit.
- `compile-workflow/workflow-compiling.service.ts` — the compile-on-edit subscription that drives it.

**Expected:** Opening a workflow should establish exactly **one** `/rtc` WebSocket. Editing (add/delete operators, edit properties, add/remove links) should not open any additional sockets. Switching or closing a workflow should tear the socket down cleanly (no lingering/reconnecting sockets).

### How to reproduce?

Client-side (browser DevTools → Network → **WS** filter):
1. Open a workflow. Observe **one** `/rtc` WebSocket.
2. Add/delete operators, edit operator properties, add/remove links repeatedly. **Observed:** a new `/rtc` WS appears on each edit and stays open (and keeps reconnecting), instead of the count staying at one.
3. Switch workflow A → B, or navigate away / close the tab. **Observed:** old `/rtc` sockets linger and reconnect instead of closing.

The same leak can be observed server-side by counting established connections to the y-websocket server while a single user edits a workflow: the count climbs steadily with each edit and never falls, even though only one browser tab is open.

### Version/Branch

1.3.0-incubating-SNAPSHOT (main)

### Commit Hash (Optional)

_Both leaks are present in current `main` and reproduce with `y-websocket@1.4.0` / `yjs@13.5.41`._

### What browsers are you seeing the problem on?

Chrome

### Relevant log output

```shell

```

Contributor guide

Open the contributing guide

Research direction

Start with frontend/src/app/workspace/service/workflow-graph/model/shared-model.ts and workflow-graph.ts, then trace getValidTexeraGraph() in validation/validation-workflow.service.ts from the compile-on-edit subscription in compile-workflow/workflow-compiling.service.ts. Reproduce with the browser DevTools WS filter while editing and switching workflows. Done means one /rtc socket per open workflow, no new sockets during edits, and no lingering or reconnecting sockets after teardown.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.