[2.0 rc.20 / next] `await renderToStream` never settles when the render signal aborts

Chiusa
#4,646 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
55/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
nodejs, typescript
Ambito
backend

Direzione di ricerca

Start with the reproduction script in the issue and packages/web/src/server.ts: the promise form of renderToStream settles only through onCompleteAll or onFailure, and the abandon path on disconnect calls onDisconnectedBeforeShell instead, which the promise form never sets (around L2220-L2223). Run repro.mjs and confirm it prints still pending. Done means the promise rejects with signal.reason after an abort, and the script prints a rejected outcome.

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

Descrizione

When the signal passed to renderToStream aborts, the render is disposed, but the promise returned for await renderToStream(...) never settles. It neither resolves nor rejects, so the caller stays pending forever and keeps whatever it holds alive: the request, timers, a concurrency slot.

The pipe paths end on abort. Only the promise form is left hanging.

Versions

solid-js and @solidjs/web 2.0.0-rc.20 from npm, and next at ab29345. Node 26.13.0.

Reproduction

Save as repro.mjs in a project with solid-js and @solidjs/web 2.0.0-rc.20, then run node repro.mjs:

import { renderToStream, ssr, escape } from "@solidjs/web";
import { createMemo } from "solid-js";

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

function App() {
  const message = createMemo(() => sleep(500).then(() => "loaded"));
  return ssr(["<p>", "</p>"], () => escape(message()));
}

const controller = new AbortController();
const rendering = renderToStream(App, { signal: controller.signal });
setTimeout(() => controller.abort(new Error("client disconnected")), 50);

const outcome = await Promise.race([
  Promise.resolve(rendering).then(
    html => `resolved: ${html}`,
    error => `rejected: ${error?.message}`
  ),
  sleep(2000).then(() => "still pending after 2s")
]);
console.log(outcome);
process.exit(0);
Observed
still pending after 2s

Without the abort call, the same script prints resolved: <p>loaded</p>....

Expected

The promise settles once the render is abandoned. Rejecting with signal.reason would let the caller tell a cancellation apart from a finished render and release what it holds.

Cause

Inside then, the promise settles only through onCompleteAll or onFailure (packages/web/src/server.ts, L3525-L3550 on next). When abandon runs because of a disconnect, it skips onFailed and only calls onDisconnectedBeforeShell, which the promise form never sets (L2220-L2223), so neither path runs.

Lingua principale
TypeScript
Stelle
36.2k
Fork
1.1k
Merge medio
10h 10m
PR unite (30g)
505

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 solidjs/solid

Tutte le issue di solidjs/solid

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.