Skip to content

v0.7.0 — Sync to vgi-rpc 0.17: gzip codec, error_kind, sticky sessions

Choose a tag to compare

@rustyconover rustyconover released this 18 May 15:04
· 20 commits to main since this release

Wire-protocol catch-up with the Python reference at vgi-rpc 0.17.1.
Conformance: 893 passed, 0 skipped across all transports.

What's new

HTTP content-encoding negotiation

gzip is now a co-equal codec to zstd on both request and response paths. Servers emit VGI-Supported-Encodings: zstd, gzip on every response so capability-aware clients can pick a codec from the intersection; unknown Content-Encoding returns HTTP 415. Required for Python clients running without the zstandard package installed.

Sticky sessions (HTTP-only, opt-in)

Full implementation of the cross-language sticky-sessions spec.

  • HttpServer.EnableSticky(defaultTTL) turns it on; off by default.
  • CallContext.OpenSession(state, ttl) / CloseSession() / Session() / SessionID().
  • AEAD-sealed VGI-Session token via the existing XChaCha20-Poly1305 envelope.
  • Per-worker registry with TTL reaper goroutine; per-session mutex serializes same-session calls.
  • Idempotent DELETE {prefix}/__session__ teardown endpoint.
  • Echo headers (VGI-Echo-<name>) for client-driven routing (e.g. Fly.io's fly-force-instance-id).
  • Typed SessionLostError and ServerDrainingError with vgi_rpc.error_kind metadata.
  • DrainHandle operator API for graceful shutdown.
  • Middleware runs on /init AND /exchange so producer continuations and exchange round-trips re-resolve the session on every HTTP turn.

Typed errors with metadata

MethodNotImplementedError sentinel + vgi_rpc.error_kind metadata key on EXCEPTION batches so cross-language clients can match on the kind without substring-searching the message. SessionLostError and ServerDrainingError use the same mechanism.

Implementation field on CallContext / DispatchInfo

Optional caller-supplied reference to the service implementation, set via Server.SetImplementation. Mirrors Python's CallContext.implementation so framework callbacks reach the impl without holding their own captured reference.

Wire-compat fix (potentially breaking)

AAD fix for state and session tokens. Python emits prefix + b\"\x01\" + domain + b\"\x00\" + principal for authenticated tokens; the Go port was emitting prefix + b\"\x01\" + principal (no domain, no separator). This was wire-incompatible with Python for any authenticated principal and enabled cross-domain replay. The anonymous predicate is also aligned with Python's not auth.authenticated.

Migration: any state tokens or session tokens minted under the old Go AAD format are unreadable after upgrade. For deployments that mint long-lived tokens, plan a graceful expiry window before deploying. New tokens are wire-compatible with Python.

Other

  • Panic recovery in handleUnary so a handler crash after ctx.OpenSession() doesn't leak the registry entry.
  • Conformance suite now exercises sticky on every code path: unary, producer-stream continuation, exchange-stream round-trip, and a unary↔stream shared-state round-trip.
  • Race detector clean; lint clean.

🤖 Generated with Claude Code