Pushing updates: polling to WebSockets

System Design · lesson 21 of 32 · 4 min read

Choose between polling, SSE and WebSockets, and know what an open socket costs you.

Open this lesson in the learning hub

Key points

  • Short polling is a request every few seconds. Simple, cache-friendly, stateless - and nearly all the responses are empty.
  • Long polling holds the request open until there is news, then the client reconnects. One round trip per event, no new protocol.
  • SSE is one long-lived HTTP response the server keeps writing into. One-way, auto-reconnecting, and proxy-friendly.
  • WebSocket upgrades the connection so both sides can send. Use it when the client talks back: chat, presence, live cursors.
  • Connections are state. A gateway holding 100k sockets must be registered somewhere, and fan-out goes via Redis or Kafka, not memory.
  • Number every event and let clients resume from their last one. A dropped socket must never mean a lost message.

Example

// SSE: one-way, plain HTTP, and it reconnects on its own.
@GetMapping(path = "/prices", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
SseEmitter prices(@RequestHeader(name = "Last-Event-ID", required = false) String lastId) {
    SseEmitter emitter = new SseEmitter(Duration.ofMinutes(30).toMillis());
    feed.replayAfter(lastId, ev -> send(emitter, ev));   // no gap after a reconnect
    feed.subscribe(ev -> send(emitter, ev));
    emitter.onCompletion(() -> feed.unsubscribe(emitter));
    return emitter;
}

// WebSocket: both directions. Fan out through a broker, never from local memory -
// the recipient is almost certainly connected to a different gateway instance.
@Configuration
@EnableWebSocketMessageBroker
class WsConfig implements WebSocketMessageBrokerConfigurer {

    public void registerStompEndpoints(StompEndpointRegistry r) {
        r.addEndpoint("/ws").setAllowedOriginPatterns("https://app.example.com");
    }

    public void configureMessageBroker(MessageBrokerRegistry r) {
        r.enableStompBrokerRelay("/topic")              // RabbitMQ or ActiveMQ relay
         .setRelayHost("broker.internal");
        r.setApplicationDestinationPrefixes("/app");
    }
}

Poll for slow data, SSE for one-way streams, WebSockets when the client answers - and number every event.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the System Design course, and every lesson in it is listed on the System Design contents page.