I have been rummaging through a lot of backend-related content lately, and half the time, I don't really understand what is being said, but hey, it's an opportunity to learn.
I came across this post on X:
From my little knowledge studying backend systems, two of the options were familiar, polling and websockets, but SSE was strange. Now, if I had to answer the question in an interview, my knowledge would already eliminate the right answer.
Here's what I was thinking:
The client needs to get updates without asking, so a connection needs to be opened. You can see where I'm leaning towards. But I recognise that websockets is a bi-directional communication channel, we only need one direction, otherwise we'll be wasting resources...right?
Also, does the user have to see all the stages in the delivery? I mean it's not like we'll send a push notification every time the status changes, it's okay if the user misses one or two of the five stages as long as they get a progressive update (i.e, it was pending before, now it's out for delivery - it's fine if they missed confirmed), maybe it's okay to use polling. User needs to be updated: we send them something every 5-10 seconds when they ask, or when the client asks, the server holds the request until the update → Responds → Client immediately asks again (long polling).
Also, how does the status change? If the delivery person is the one changing the status (manually or through a change in location), isn't that technically bidirectional (like a chat)? Maybe it's WebSocket after all.thinking time: 0.2 seconds
At this point, I was confused, so I let the comment section tell me the answer. Lo and behold, it's the option I know nothing about!
What is SSE?
It's a persistent one-way HTTP connection where the server can push updates to the client whenever it wants.
Client opens ONE connection → Server keeps it open → Server pushes when ready
Sweet, just what I knew I needed but never knew what it was.
So what exactly does this look like in code?
[HttpGet("order/{orderId}/status")]
public async Task StreamOrderStatus(string orderId, CancellationToken cancellationToken)
{
// Tell the client, "this is an SSE stream, keep the connection open"
Response.Headers["Content-Type"] = "text/event-stream";
Response.Headers["Cache-Control"] = "no-cache";
Response.Headers["Connection"] = "keep-alive";
while (!cancellationToken.IsCancellationRequested)
{
var status = await _orderService.GetStatusAsync(orderId);
// SSE format — "data:" is required, double newline ends the event
await Response.WriteAsync($"data: {status}\n\n");
await Response.Body.FlushAsync();
// Poll the DB every 3 seconds for a status change
await Task.Delay(3000, cancellationToken);
}
}
What's actually happening line by line
The headers are the handshake. You're telling the client "don't close this connection, I'll keep sending you things." Without these, the client treats it like a normal HTTP response and closes after the first chunk. Side note: I haven't seen that content-type ever before.
The while loop keeps the connection alive. You're essentially saying "stay open until the client disconnects."
CancellationToken is how you know the client disconnected. When they close the app or navigate away, the token gets cancelled and the loop exits cleanly. Without this you'd have zombie connections running on your server forever.
The data: format is the SSE spec — it's just a text protocol:
data: Preparing\n\n
data: Ready\n\n
data: Out for delivery\n\n
I can tell this code is problematic. Why call the DB every few seconds when you're not sure the status has changed (just like polling, but not over the network), so we'll probably need to replace that with something else (that's event-driven like a pub/sub) - but that's not the point.
With SSE, you're still “checking” for updates—but you're doing it server-side once, instead of the client repeatedly hitting your API, which will take its toll on your infra.
So why is SSE the best fit here?
- One-way updates → perfect match
- No need for bidirectional communication (unlike WebSockets)
- More efficient than polling (no repeated requests)
That was how I learnt about SSEs and I'm passing it forward to y'all. Next time you see ‘real-time updates’ in a system design question, don’t jump straight to WebSockets; SSE might be exactly what you need.
Until my next discovery, peace out! ✌🏾
Top comments (0)