# 5. Choosing Previous: [4. Back-pressure](04-backpressure.md) --- ## The decision table | If | Pick | Because | |---|---|---| | Service-to-service RPC, polyglot team, you want a schema | **gRPC** | The `.proto` is a contract other languages generate from. Deadlines are absolute and propagate. Boot 4 makes it a first-class starter. | | A stream whose consumer can fall behind | **RSocket** | `request(n)` is the only demand signal that crosses the wire. 100 vs 1.3 million is not a tuning difference. | | A browser is one of the peers | **WebSocket**, with STOMP on it | gRPC needs grpc-web and a proxy. RSocket over WebSocket works but the client ecosystem is thin. | | Server pushes, client never speaks | **none of these** — use SSE | See [`../sse-websocket`](../../sse-websocket/README.md). | | You want the lowest possible median latency and control both ends | **raw WebSocket** | It is fastest here because it does the least. Read the p99 before deciding that is what you want. | | Long-lived bidirectional exchange with independent streams | **RSocket channel** or **gRPC bidi** | Both give you two independent streams; only RSocket gives each of them demand. | ## What each one really costs **gRPC** costs a build step, a schema you must version, and an operational story for HTTP/2 through your proxies. In exchange you get the best-supported cross-language RPC there is, and deadlines — which is a bigger deal than it sounds, because an absolute deadline that propagates across hops is the single most effective defence against one slow dependency taking down a system. **RSocket** costs ecosystem. It is the least deployed of the three, the client libraries outside Java and JavaScript are thin, and if you are not already reactive, `Mono` and `Flux` in your service signatures is a real commitment. In exchange you get the only demand signalling in the list, plus resumption and leasing. **Raw WebSocket** costs everything you then invent: routing, correlation, error shape, versioning, and the demand mechanism you will eventually need. That is the cost STOMP exists to prevent, and if you find yourself designing a text protocol with a command word at the front — as [`WebSocketQuoteHandler`](../src/main/java/com/ankurm/protocols/WebSocketQuoteHandler.java) deliberately does — that is the signal to stop and use one. ## Should you use any of them? Three cases where the answer is no: - **Request/response between two services that both speak HTTP already.** A REST endpoint with a `RestClient` and a timeout is fine, and everything in your organisation already knows how to observe, cache, proxy and debug it. Reach for gRPC when the schema or the deadline propagation is the thing you need, not because it benchmarks faster. - **Streaming that is really batching.** If the consumer processes a page at a time anyway, paginated HTTP has back-pressure for free: the consumer asks for the next page when it is ready. That is `request(n)` with a URL. - **Events that outlive the connection.** None of these three persist anything. A dropped connection loses the messages in flight. If that matters, the answer is a broker — [`../kafka-basics`](../../kafka-basics/README.md), [`../rabbitmq`](../../rabbitmq/README.md), and the comparison in [`../broker-comparison`](../../broker-comparison/README.md). ## And the benchmark caveat, one more time Every number in this module was measured with client and server in one JVM on one machine. That deletes the network, which is where protobuf's 35 bytes would pay and where the tail latencies would look completely different. The measurement that does transfer is [chapter 4](04-backpressure.md), because "how many did the server produce for a consumer that wanted a hundred" is a property of the protocol and not of the link. --- Previous: [4. Back-pressure](04-backpressure.md)