v157 · webtransport draining

Capsule timeline inspector

Inspect the wire-level HTTP/3 capsules on the extended CONNECT stream — DRAIN_WEBTRANSPORT_SESSION (0x78ae) versus CLOSE_WEBTRANSPORT_SESSION (0x2843) — and compare how the ready → draining → closed Promise lifecycle and in-flight stream failure counts change under varying server drain grace periods.

Configure server retirement strategy & grace period

Adjust the drain grace period and in-flight stream duration below to see how DRAIN_WEBTRANSPORT_SESSION (0x78ae) prevents stream resets compared to an immediate CLOSE_WEBTRANSPORT_SESSION (0x2843).

With DRAIN_WEBTRANSPORT_SESSION (0x78ae)

Capsule Type: 0x78ae (varint: 0x80 0x00 0x78 0xae) Capsule Length: 0x00 (0 payload bytes)

Promise sequence: wt.ready (t=0s) → wt.draining (t=1.0s) → wt.closed (t=5.0s)

Streams completed cleanly: 12 / 12

Aborted streams (RESET_STREAM): 0

Immediate CLOSE_WEBTRANSPORT_SESSION (0x2843)

Capsule Type: 0x2843 (varint: 0x40 0x28 0x43) Capsule Length: 0x11 | Code: 0x000001f7 | Msg: "Server shutdown"

Promise sequence: wt.ready (t=0s) → wt.draining (never resolves) → wt.closed (t=1.0s)

Streams completed cleanly: 0 / 12

Aborted streams (RESET_STREAM): 12

Promise lifecycle & stream state timeline across the retirement window
Timestamp HTTP/3 Control Stream Event wt.ready wt.draining wt.closed Client Action

code path

// Observing all three lifecycle promises on a WebTransport instance:
const wt = new WebTransport("https://edge.example.com/session");

wt.ready.then(() => {
  console.log("[t=0.0s] Extended CONNECT 200 OK; session ready");
});

if ("draining" in wt) {
  wt.draining.then(() => {
    console.log("[0x78ae] DRAIN_WEBTRANSPORT_SESSION received; draining");
  });
}

wt.closed.then(({ closeCode, reason }) => {
  console.log("[0x2843] CLOSE_WEBTRANSPORT_SESSION:", closeCode, reason);
});

see also