v157 · networking · webtransport

WebTransport draining

Chrome 157 implements WebTransport.prototype.draining, a Promise that resolves when the server sends an HTTP/3 DRAIN_WEBTRANSPORT_SESSION capsule (0x78ae). Instead of abruptly tearing down active streams during a server deployment or load-balancer scale-in, the server signals that the session is retiring so the client can open a replacement session for new work while existing streams finish cleanly.

concepts

  1. Graceful session handover

    Run the live WebTransport.prototype.draining IDL probe, spawn bidirectional streams on Session A, and fire a DRAIN_WEBTRANSPORT_SESSION signal. Watch active streams finish uninterrupted on Session A while new streams cut over automatically to replacement Session B.

  2. Capsule timeline inspector

    Compare the HTTP/3 DRAIN_WEBTRANSPORT_SESSION (0x78ae) and CLOSE_WEBTRANSPORT_SESSION (0x2843) wire capsules alongside the three-stage ready → draining → closed Promise lifecycle and in-flight stream survival counts.

  3. Load-balancer drain budget

    Model active WebTransport stream duration distributions (p50, p95, p99) against your edge load-balancer or Kubernetes drain grace window to size the gap between DRAIN_WEBTRANSPORT_SESSION and final termination.

why it shipped

Long-lived WebTransport sessions multiplex dozens of bidirectional and unidirectional streams plus datagrams over a single HTTP/3 connection. Before WebTransport.prototype.draining, a server node preparing for a rolling restart or autoscaling scale-in had no standard WebTransport API surface to tell the browser "stop opening new streams on this session, but finish the ones you already started." Calling CLOSE_WEBTRANSPORT_SESSION (0x2843) or closing the underlying QUIC connection immediately aborts in-flight media segments, RPC calls, or state sync transfers.

HTTP/3 WebTransport defines the DRAIN_WEBTRANSPORT_SESSION capsule (type = 0x78ae, empty payload) sent on the CONNECT control stream. When Chrome 157 receives this capsule, it resolves the wt.draining Promise without closing existing streams. Application code awaiting wt.draining can immediately dial a warm replacement session to a healthy backend instance, route all subsequent createBidirectionalStream() and createUnidirectionalStream() calls to the new session, and close the draining session once its remaining streams drain to zero.

the API

let activeTransport = new WebTransport("https://edge.example.com/wt");
await activeTransport.ready;

// React to the server's HTTP/3 DRAIN_WEBTRANSPORT_SESSION (0x78ae) capsule:
activeTransport.draining.then(async () => {
  console.info("Session draining; opening replacement WebTransport session...");
  const replacement = new WebTransport("https://edge.example.com/wt");
  await replacement.ready;
  // Cut over new stream creation to the replacement session while
  // in-flight streams on the old session complete naturally.
  activeTransport = replacement;
});

WebTransport.prototype.draining is a getter returning a Promise<undefined>. Each WebTransport instance initializes an internal [[Draining]] promise on construction, resolves it when the DRAIN_WEBTRANSPORT_SESSION capsule arrives on the session's HTTP/3 CONNECT stream, and rejects it if the session is abruptly closed or fails before draining.

research notes

references