v157 · webtransport draining

Graceful session handover

Probe the real WebTransport.prototype.draining getter in your browser, then drive a zero-downtime session migration: when Session A receives an HTTP/3 DRAIN_WEBTRANSPORT_SESSION (0x78ae) capsule, its draining Promise resolves, replacement Session B opens immediately for new bidirectional streams, and in-flight streams on Session A finish without dropping a byte.

1. Live WebTransport.prototype.draining IDL probe

Contract tested: Checks whether WebTransport exists, whether 'draining' in WebTransport.prototype is present, and whether Object.getOwnPropertyDescriptor(WebTransport.prototype, 'draining')?.get is a getter function alongside ready and closed.

Running WebTransport.prototype.draining support probe...

2. Zero-downtime session handover simulator

Spawn bidirectional streams, then trigger DRAIN_WEBTRANSPORT_SESSION (0x78ae) on Session A. Existing streams remain open on Session A until they complete, while newly created streams automatically route to replacement Session B.

Session A (primary edge node) READY

ready: resolved · draining: pending · closed: pending

Active streams: 0 · Completed: 0

Session B (replacement node) STANDBY

ready: not opened · draining: not opened · closed: not opened

Active streams: 0 · Completed: 0

Live bidirectional stream routing table
Stream ID Routed Session State Progress
No streams opened yet. Click "Open bidirectional stream" to start traffic.
Session A is READY and routing all new createBidirectionalStream() calls.

code path

class DrainingAwareTransportPool {
  constructor(url) {
    this.url = url;
    this.current = this.#connect();
  }

  #connect() {
    const wt = new WebTransport(this.url);
    if ("draining" in wt) {
      wt.draining.then(() => {
        // Server sent HTTP/3 DRAIN_WEBTRANSPORT_SESSION (0x78ae).
        // Immediately warm up a replacement session for new streams:
        const oldSession = wt;
        this.current = this.#connect();
        // Existing streams on oldSession continue until they finish.
      });
    }
    return wt;
  }

  async openBidiStream() {
    await this.current.ready;
    return this.current.createBidirectionalStream();
  }
}

see also