partyserver: with hibernation off, a client close without a status code (1005) is never answered, so the client stays in CLOSING

Aperta Adatta ai principianti
#429 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
69/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
typescript
Ambito
networking

Direzione di ricerca

Inizia leggendo l’implementazione di closeQuietly e la modifica in #394; l’issue indica i codici di chiusura riservati e fornisce una riproduzione con hibernate: false. Riproduci la chiusura senza codice e controlla lo stato del socket dopo 6 secondi. Poi verifica che, dopo la correzione, il client riceva un frame Close ed esca da CLOSING.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Since #394, closeQuietly skips the reply for the reserved codes 1005, 1006 and 1015. 1006 and 1015 mean that no Close frame arrived. 1005 does not: it is what the server reports when the client sent a real Close frame with an empty body, which is what ws.close() with no arguments does. The transport is still open, and the client waits in CLOSING for the server's Close frame.

On a non-hibernating server (static options = { hibernate: false }) that frame never comes. y-partyserver's provider calls ws.close() with no code in disconnect(), so every YProvider.disconnect() ends this way. The provider keeps wsconnected === true until the socket finally dies, and a connect() in the meantime does nothing.

The #394 notes say compatibility dates on or after 2026-04-07 auto-reply to Close frames. That does not happen for these sockets: the result below is on compatibility date 2026-11-01.

Repro (wrangler 4.159.0, workerd 1.20261109.1, partyserver 0.5.10, y-partyserver 2.2.0, compatibility date 2026-11-01, hibernate: false):

  1. Start a YServer subclass with hibernate: false (for example via unstable_startWorker).
  2. Open a raw WebSocket to /parties/<party>/<room>, wait for open, then call ws.close() with no code.
  3. With the stock onClose, the client is still in readyState 2 (CLOSING) after 6000 ms.
  4. Add if (code === 1005) connection.close(1000, 'Closed') to onClose. The close completes in 14 ms and the client sees 1000.

In our production Worker that reply has run on every pause, reload and tab close since 2026-11-09. wrangler tail during a test run (57 events) showed no exceptions and no Network connection lost rejections.

Suggested fix: in closeQuietly, skip the reply only for 1006 and 1015. For 1005, reply with ws.close() (no code) or with 1000. A peer that sent a code-less Close frame is still there to receive the answer.

Lingua principale
TypeScript
Stelle
1.3k
Fork
84
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di cloudflare/partykit

Tutte le issue di cloudflare/partykit

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.