Server-Sent Events (SSE)

What is SSE?

Server-Sent Events (SSE) is a technology that allows servers to send real-time updates to clients through a persistent HTTP connection. Unlike other real-time communication techniques such as WebSockets, SSE provides one-way communication from the server to the client.

Technical Features of SSE

  • One-way communication: The server can send data to the client, but the client cannot send data back to the server through the same SSE connection.
  • Use of standard HTTP: SSE uses conventional HTTP protocol, making it easy to implement and compatible with existing infrastructures.
  • Data format: Data is sent in plain text format with the MIME type text/event-stream. Each event can include fields such as event, data, id, and retry.
  • Automatic reconnection: If the connection is interrupted, the browser will attempt to reconnect automatically after a specified interval.
  • Browser compatibility: Most modern browsers support SSE, including Chrome, Firefox, Safari, and Edge.
  • Support for multiple custom events: Different types of events can be defined using event: eventName and handled on the client side.

Comparison with Other Technologies

SSE vs. WebSockets

  • Communication direction: SSE is one-way (server -> client), whereas WebSockets allow bidirectional communication.
  • Underlying protocol: SSE uses standard HTTP, while WebSockets require a different protocol initiated with an HTTP upgrade request.
  • Efficiency: WebSockets are more efficient for applications requiring frequent communication in both directions, while SSE is suitable for periodic updates from the server to the client.
  • Compatibility and security: SSE works well with proxies and firewalls due to its use of standard HTTP, whereas WebSockets may face compatibility issues in certain network configurations.
  • Scalability: SSE is easier to scale with standard load balancers, while WebSockets require a more complex infrastructure.

Practical Example: Real-Time Order Tracking

Imagine managing a restaurant with an online ordering service and needing to notify users when their order status changes without requiring them to refresh the page. SSE is an ideal solution.

Server (Node.js with Express and Order Status Simulation)

const express = require('express');
const cors = require('cors');
const app = express();

app.use(cors());

const orderStatuses = ["Received", "Preparing", "Ready for delivery", "Delivered"];
let currentStatus = 0;

app.get('/order/:id', (req, res) => {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');

    const sendStatus = () => {
        if (currentStatus < orderStatuses.length) {
            res.write(`data: ${JSON.stringify({ orderId: req.params.id, status: orderStatuses[currentStatus] })}\n\n`);
            currentStatus++;
        } else {
            clearInterval(intervalId);
            res.end();
        }
    };

    const intervalId = setInterval(sendStatus, 5000);

    req.on('close', () => {
        clearInterval(intervalId);
        res.end();
    });
});

app.listen(3000, () => console.log('SSE server running at http://localhost:3000'));

Client (HTML + JavaScript)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Order Tracking</title>
</head>
<body>
    <h1>Order Status</h1>
    <div id="status"></div>

    <script>
        const orderId = 12345; // Simulated order ID
        const eventSource = new EventSource(`http://localhost:3000/order/${orderId}`);

        eventSource.onmessage = function(event) {
            const data = JSON.parse(event.data);
            document.getElementById('status').innerText = `Order #${data.orderId} - Status: ${data.status}`;
        };

        eventSource.onerror = function() {
            console.error('SSE connection error');
        };
    </script>
</body>
</html>

Advantages of This Approach

  • Real-time updates without needing to refresh the page.
  • Lower resource consumption compared to constant polling.
  • Simple implementation, without the need for WebSockets or complex configurations.
  • Automatic reconnection in case of connection failure.
  • Natural scalability in HTTP servers without requiring complex infrastructure.
  • Efficient use on mobile devices, avoiding unnecessary open connections.

Advanced Considerations for IT Experts

Optimizing SSE for Production

  • Use of HTTP/2: SSE performs better with HTTP/2, which allows multiple streams within a single connection, reducing latency.
  • Backpressure management: On high-traffic servers, handling buffers is crucial to prevent memory overload.
  • Load balancing: When using reverse proxies like Nginx, proper configuration is needed to support SSE connections without interruptions.

Handling Large Volumes of Connections

  • Use of non-blocking event loops: In Node.js, frameworks like Fastify or servers with stream support can improve performance.
  • Persistence of events for late clients: Redis or in-memory databases can store past events and send them to reconnecting clients.
  • Avoiding connection saturation: In large-scale applications, setting connection lifetime limits and controlled retry mechanisms is recommended.

Disadvantages of SSE

  • One-way communication.
  • Limitations on simultaneous connections in browsers.
  • Limited support in some mobile environments due to power-saving policies.

Conclusion

Server-Sent Events is an ideal solution for real-time updates from server to client with a simple and HTTP-based implementation. With proper optimizations, it can be highly scalable and efficient.