[y-partyserver] provider.destroy() leaks reconnect timer, hanging Node processes and delaying GC
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 65/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Ít trao đổi
- Công nghệ
- node.js, typescript
- Lĩnh vực
- backend, networking
Hướng nghiên cứu
Bắt đầu tại entry point y-partyserver/provider và lần theo WebsocketProvider.destroy() qua sự kiện đóng WebSocket và việc lên lịch kết nối lại. Chạy script tái hiện Node.js từ issue, sau đó xác minh rằng việc hủy provider không để lại timer kết nối lại nào khiến event loop tiếp tục mở và process thoát mà không có độ trễ.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
I maintain YAOS a local-first sync engine running inside Obsidian, built on DOs and y-partyserver. While debugging a CI pipeline that inexplicably took 140 seconds instead of 36 seconds, we discovered that y-partyserver is leaking timers directly into the event loop every time a connection is torn down.
The Bug
When provider.destroy() is called on a WebsocketProvider in y-partyserver, the WebSocket's onclose event listener unconditionally queues a reconnect timer via setTimeout(setupWS, backoff, provider).
While the setupWS callback correctly checks this.shouldConnect and aborts (meaning it doesn't actually reconnect), the setTimeout handle itself is never stored or cleared during the destroy() lifecycle.
The Real-World Impact
-
Delayed Garbage Collection (Electron/SPA): In long-lived environments like ours, the setTimeout closure retains the entire provider instance and its massive associated Y.Doc in memory until the timer naturally fires (up to 2.5s). In environments with flapping networks where connections are repeatedly destroyed and recreated, this creates a massive GC backlog and stutters the UI thread.
-
Node.js / CI Hangs: The Node event loop refuses to exit until the backoff timer fires. In test suites that instantiate and destroy multiple providers, this compounds into massive CI delays, forcing developers to use process.exit(0) hacks just to allow scripts to terminate cleanly.
This issue is inherited DNA from y-websocket. The exact same architectural flaw was reported upstream 6 months ago (see yjs/y-websocket#198), but it has not merged. Since y-partyserver ships its own adapted provider implementation, it needs to be patched here.
Steps to Reproduce
Running this Node.js script proves the event loop is held hostage by the leaked timer, even after the provider is explicitly destroyed:
import YSyncProvider from "y-partyserver/provider";
import WebSocket from "ws";
async function run() {
const ydoc = new Y.Doc();
const provider = new YSyncProvider("ws://127.0.0.1:8787", "room", ydoc, {
WebSocketPolyfill: WebSocket
});
// Wait for initial connection logic
await new Promise(r => setTimeout(r, 100));
console.log("Destroying provider...");
provider.destroy();
// Wait a tick for the ws 'close' event to fire and schedule the leak
await new Promise(r => setTimeout(r, 100));
const handles = process._getActiveHandles().filter(
h => h.constructor.name === 'Timeout' || h.constructor.name === 'TimerWrap'
);
console.log(`Active timers preventing exit: ${handles.length}`);
// Process hangs here for up to 2.5 seconds instead of exiting immediately
}
run();
- Ngôn ngữ chính
- TypeScript
- Star
- 1.3k
- Fork
- 84
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của cloudflare/partykit
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
cloudflare/partykit#425 · 1 bình luận ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
cloudflare/partykit#424 · 1 bình luận ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
cloudflare/partykit#423 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
cloudflare/partykit#419 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
cloudflare/partykit#411 ·
Tất cả issue của cloudflare/partykit
Issue tương tự
-
area:desktop area:ui bug platform:macos
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
anthropics/claude-code#106183 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
-
feature:App-Tour feature:Chat ready Web
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
digitalfabrik/integreat-app#4523 · 2 reaction ·
Maintainer thường phản hồi trong vòng 3 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Required Lexical field accepts two empty paragraphsCó thể đã có người làm @lazerg đã nhận hôm nay. Đang mởBug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
payloadcms/payload#19222 ·
Maintainer thường phản hồi trong vòng 1 ngày