Skip to content

Support for RFC 7692 permessage-deflate WebSocket extension #850

Description

@N3XTLAB

Summary
Hi! First, thank you for Granian — we migrated to it from uvicorn[standard] in production after benchmarking showed clear latency wins, and the Rust runtime has been excellent.

This is a feature request for RFC 7692 permessage-deflate WebSocket extension support, with full transparency about the upstream library chain implications.

Motivation — production use case
We're running Granian 2.7.4 in production for an asynchronous exchange trading platform with persistent WebSocket connections delivering high-frequency JSON payloads (orderbook deltas, market ticker updates, user account state). Typical workload:

~30–50 hot WS connections per backend worker
Order book delta broadcast: 1–10 msg/s/symbol, average payload 300–800 bytes JSON
Trade tape: bursty 50+ msg/s during high volume
Aggregate outbound BW during peak: 5–15 MB/s
Reference exchanges (Binance, Coinbase) ship permessage-deflate as default for their public WS streams. Empirically the wire-format reduction on similar JSON payloads is 50–80%, which directly impacts:

Cloudflare egress costs (we proxy through Cloudflare)
Mobile client data usage
Last-mile latency on slow networks
We discovered after migrating to Granian that our production stack quietly lost this capability — uvicorn[standard] had it default-on via the websockets Python library, while Granian's WS pipeline has no path to enable it. Browsers send Sec-WebSocket-Extensions: permessage-deflate in the handshake; Granian responds without an Extensions: header, so the extension is gracefully no-op'd and frames flow uncompressed. There's no error, just no compression.

Investigation — upstream library state (the honest part)
We did a deep audit before filing because we wanted to understand what implementation path would be reasonable. Here's the chain:

Layer Status
Granian 2.7.4 No CLI flag exposed. --ws/--no-ws is binary toggle only.
tokio-tungstenite 0.29 No deflate or permessage-deflate feature flag in Cargo.toml.
tungstenite-rs (core) No compression feature. Features = handshake, url, TLS variants only.
So this is not a simple "expose existing feature" patch — RFC 7692 is not implemented in the Granian → tokio-tungstenite → tungstenite-rs chain at all. Implementing it on Granian's side would require either:

Wait for upstream tungstenite-rs to land permessage-deflate (track or contribute upstream).
Swap WebSocket library — e.g. fastwebsockets which has been considering deflate (Deno uses it).
Implement a deflate layer inside Granian as a wrapper around the existing tungstenite WS stream.
Option 1 is the cleanest architecturally but is gated on someone else's roadmap. Option 2 means rethinking Granian's WS dependency. Option 3 is local but adds maintenance surface and duplicates work that should live in the WS library.

What we're asking for
Whatever path the maintainers decide:

Acknowledge or reject as a roadmap item with rationale, so downstream users (us and others) can plan around it.
If accepted, a tracking issue / milestone would help — we'd like to participate (sponsor work, contribute code, or just track).
If rejected, a documentation note in the WebSocket section ("Granian does not currently support permessage-deflate; users requiring it should consider [...]") would help future migrators avoid the silent regression we hit.
Why this matters more than other extensions
RFC 7692 is the only widely-deployed WebSocket extension — every major browser (Chrome, Firefox, Safari) supports it natively, every major real-time platform (Binance, Coinbase, Deribit, Discord, Slack) negotiates it by default. The "did the swap silently lose this?" failure mode is invisible until you measure wire BW, which is why we caught it late.

What we'd contribute
We're happy to:

Provide a reproducible production benchmark (before/after BW measurement on real workload).
Sponsor or contribute Rust code for an implementation, depending on the path chosen.
Document the migration trade-off for uvicorn[standard] users considering Granian (similar capability matrix).
Versions
Granian: 2.7.4
Deployed: Production (NEXT Exchange — EVE Online financial platform)
Stack: Granian + FastAPI + asyncpg, behind Caddy reverse_proxy (which correctly passes Sec-WebSocket-Extensions through)
Thanks for considering this — happy to provide more detail on any aspect of the production setup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions