gRPC
The gRPC listener (default port 50051, RUSTYBIN_GRPC_PORT, plaintext h2c) serves,
on one port:
rustybin.echo.v1.EchoService(proto/echo.proto), all four call types plus a failure RPC;grpc.health.v1.Health, following the HTTP/healthtoggle (SERVING/NOT_SERVINGfor""andrustybin.echo.v1.EchoService);- server reflection
grpc.reflection.v1andgrpc.reflection.v1alpha, so tools work without the.protofile; - gRPC-Web (
application/grpc-web,application/grpc-web-text) over HTTP/1.1 and HTTP/2, with permissive CORS for browser clients.
| RPC | Behaviour |
|---|---|
Echo (unary) | Returns message, the request metadata (headers), instance_id, and the deadline (grpc_timeout, deadline_ms) when the client set one |
ServerStream | count responses (default 3, max 100), 50 ms apart, with index |
ClientStream | Reads up to 1000 messages (else RESOURCE_EXHAUSTED) and returns them joined with spaces, index = number received |
BidiStream | Echoes each message as it arrives (max 1000) |
Fail | Fails with code (0 to 16; 0 returns a normal response), message, rich error details (google.rpc.ErrorInfo with reason, domain rustybin and metadata; google.rpc.RetryInfo when retry_delay_ms is set) and the trailer x-rustybin-fail: true |
Use Fail for gRPC-to-HTTP status mapping and retry policy demos.
With grpcurl
$GRPC is the listener's host:port, for example localhost:50051:
grpcurl -plaintext "$GRPC" list
grpcurl -plaintext -H 'x-tenant: demo' -d '{"message": "hello"}' \
"$GRPC" rustybin.echo.v1.EchoService/Echo
grpcurl -plaintext -import-path proto -proto echo.proto \
-d '{"message": "no reflection needed"}' "$GRPC" rustybin.echo.v1.EchoService/Echo
grpcurl -plaintext -d '{"message": "tick", "count": 3}' \
"$GRPC" rustybin.echo.v1.EchoService/ServerStream
grpcurl -plaintext -d '{"message": "a"} {"message": "b"} {"message": "c"}' \
"$GRPC" rustybin.echo.v1.EchoService/ClientStream
grpcurl -plaintext -d '{"code": 14, "message": "backend down", "reason": "DEMO_OUTAGE", "retry_delay_ms": 500}' \
"$GRPC" rustybin.echo.v1.EchoService/Fail 2>&1 || true
grpcurl -plaintext -d '{"service": "rustybin.echo.v1.EchoService"}' \
"$GRPC" grpc.health.v1.Health/Check
gRPC-Web
gRPC-Web is served on the same port, so a browser (or a gateway's gRPC-Web
translation) can call it over HTTP/1.1. The body is a length-prefixed protobuf
frame; the response ends with a trailer frame carrying grpc-status.
# One length-prefixed frame: flag 0x00, length 7, EchoRequest{message: "hello"}.
POST {{grpc_url}}/rustybin.echo.v1.EchoService/Echo
Content-Type: application/grpc-web+proto
X-Grpc-Web: 1
hex,00000000070a0568656c6c6f;
HTTP 200
[Asserts]
header "Content-Type" == "application/grpc-web+proto"
# The reply frame contains "hello"; the trailer frame carries grpc-status:0.
bytes contains hex,68656c6c6f;
bytes contains hex,677270632d7374617475733a30;
OPTIONS {{grpc_url}}/rustybin.echo.v1.EchoService/Echo
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-grpc-web
HTTP 200
[Asserts]
header "Access-Control-Allow-Origin" == "https://app.example.com"
On the HTTP and HTTPS ports
With RUSTYBIN_GRPC_ON_HTTP=true the HTTP and HTTPS listeners serve the same gRPC
services (EchoService, health, reflection, gRPC-Web) for requests with
content-type: application/grpc*; everything else is the usual HTTP surface. A
TLS-terminating proxy or platform edge can then forward gRPC on port 443 to the
HTTP listener as cleartext HTTP/2 (h2c), next to the web traffic. The HTTPS listener
offers HTTP/2 through ALPN in this mode. The separate gRPC port keeps working.
$HTTP_ADDR and $HTTPS_ADDR are the listeners' host:port:
# Cleartext HTTP/2 (h2c) on the HTTP port, what a proxy sends after TLS termination.
grpcurl -plaintext -d '{"message": "same port as the web"}' \
"$HTTP_ADDR" rustybin.echo.v1.EchoService/Echo
# HTTP/2 over TLS on the HTTPS port (ALPN h2; -insecure: demo certificate).
grpcurl -insecure "$HTTPS_ADDR" list
grpcurl -plaintext -d '{"service": "rustybin.echo.v1.EchoService"}' \
"$HTTP_ADDR" grpc.health.v1.Health/Check
gRPC requests on the HTTP ports skip the HTTP middleware (inspector, fault headers,
CORS of the HTTP routes); plan limits apply to EchoService as on the gRPC port, and
rustybin_protocol_requests_total{protocol="grpc"} counts them.
Behind a gateway
Route HTTP/2 traffic for /rustybin.echo.v1.EchoService/* to port 50051 with an
h2c (cleartext HTTP/2) upstream. Echo returns the metadata it received, so
headers added by the gateway (authentication, tracing, consumer identity) are
visible in the response; instance_id shows which replica answered.