I've been spending quite a bit of time lately exploring the world of real-time notifications. Naively, I was under the impression that real-time communication meant one thing: WebSockets.
More specifically, I thought the term for server to browser communication was "WebSocket." I thought this for years! I even wrote a 5-part series on WebSockets on the subject thinking that's what the term meant (it's a good series, I actually do recommend it).
It wasn't until I started researching the protocol as part of my day job that I realized I was wrong. Like, way wrong. There are several ways to get data from a server to a browser outside of WebSockets.
Today we're going to cover four of the most popular stateful mechanisms: WebSockets, gRPC, MQTT, and Server-Sent Events (SSE). Each of these is unique in the way they facilitate server to client messages, with pros and cons to consider before you implement a solution.
Notification Methods
As I mentioned earlier, there is a long list of notification methods but we'll focus on the four most popular ones. I mentioned they were stateful, and it's worth describing what that means.
A stateful connection is a persistent connection between two entities that remembers previous interactions. As long as the connection is up, the two entities can communicate freely back and forth with each other, much like being on a phone call. When one side hangs up, the connection is terminated, and they can no longer communicate with each other.
Compare this to a stateless communication mechanism like Amazon SNS or other Webhook implementation where the connection is not persistent and the communication is one-way. These are intended to be used as a response to an event and inform subscribers without maintaining a continuous connection or keeping memory of previous interactions.
Back to our notification methods:
- WebSockets - Bidirectional communication over a single TCP connections. Messages are asynchronous and can be sent from client to server and server to client at the same time. This is natively supported by most browsers.
- gRPC - High-performance bidirectional streaming. This not only supports simultaneous client/server and server/client messages like WebSockets, but it also offers multi-plexing, which means multiple messages can be sent in a single direction at the same time without blocking.
- MQTT - Minimalistic publish/subscribe communication protocol. Designed for IoT use cases, MQTT offers multiple levels of delivery fidelity (Quality of Service) and defines what to do when a connection is dropped (Last Will and Testament).
- Server-Sent Events (SSE) - Simple, one-way communication from a server to a client over HTTP. Mostly intended for browser-based interactions, this mechanism offers features like automatic reconnection and native browser support.
Use Cases
Now that we know what each of these are, we should talk about when to use them. As with any question in software, the answer of course is it depends, but as a general guideline, let's take a look at certain situations where each one is the most appropriate.
- WebSockets - Online multiplayer games, chat apps, collaborative tools, etc... Use cases are generally around syncing state between multiple users.
- gRPC - Microservice communication, mobile apps, and high-performance systems. Typically you see use cases with requirements around low-latency and efficient bandwith usage.
- MQTT - IoT devices. This is generally seen in environments where connections are intermittent and clients are devices that send frequent data.
- Server-Sent Events - Live news, sports scoring, monitoring dashboards. Use cases are around getting data from a server with no communication from the client.
Of course you can use these communication mechanisms for other use cases, but generally you will find them best suited for the tasks mentioned above.
Implementation
We all know I'm an AWS guy, so when AWS has a managed service for something I will typically use it (well, at least try it out for posterity). Below are your options if you're looking to implement one of these communication mechanisms in AWS.
- WebSockets - Amazon API Gateway and AWS AppSync subscriptions. A popular non-AWS option is Socket.IO.
- gRPC - AWS does not provide a native service for gRPC. Momento Topics is a popular option for a managed gRPC-based communication tool.
- MQTT - AWS IoT Core offers a managed MQTT message broker, giving you easy access to your devices. Fun fact, this is what powers the notifications in Serverlesspresso.
- Server-Sent Events - AWS does not provide a native service for managing SSE. However, many popular frameworks have built-in support for it, like express-sse for Node.js, Django for Python, rails for Ruby, and Spring for Java.
Testing
Testing server-to-client communications typically has been a tricky task. Personally, I've built server-side workflows that emit events and had to write custom scripts that connect, sit, and wait for the client to do assertions. It's a whole big thing and not a particularly easy way to validate your code. That said, I've found an easier alternative for testing when doing development work.
Postman offers support for WebSockets, gRPC, MQTT, and server-sent events. It even provides a wrapper around Socket.IO if you choose to use that.
Now, all these options are for manual testing, which really only scales when you are in active development. But being able to guess and check your work as you build is a huge productivity boost.
For WebSockets, you can add your endpoint and auth headers, hit Connect and go. This was an invaluable resource for me to debug when I was implementing WebSockets via Amazon API Gateway.
If you're building an app that communicates with IoT devices, the MQTT option in Postman will let you select which topics to subscribe to along with the Quality of Service (QOS) for each. You can even configure the Last Will and Testament for the connection to test that out too.
The gRPC request testing capabilities are complete as well, allowing you to import a .proto definition file for your schema and add metadata to your messages. You can run assertions via an After response script that can check for things like specific metadata or trailers.
The simplest one which makes you go why didn't I think of that is server-sent events. Since SSE just uses an HTTP connection, you can use a standard HTTP request in Postman to setup the connection. It will manage the connection and stream the events in the response section as they come in.
I've yet to find a good, managed solution for automated testing in a CI pipeline. For now, I'm sticking with custom scripts when I absolutely have to do it. It's an overhead that you'll need to consider when building your notification mechanisms.
Go Build
There's a reason there is so much support for real-time notifications: they are important! These types of notifications are quickly becoming a de facto standard and if your application doesn't implement one of them, you're likely falling behind. It's something users are inadvertantly beginning to assume exist as part of a core feature set. They don't want to wait or reload pages.
The world has gone async, and real-time notifications are the tool that ties it all back to your users.
If you're looking to get started, you have lots of options:
- Amazon API Gateway WebSocket tutorial - This will teach you about the many components of WebSockets and comes with functionally complete source code you can deploy.
- AWS AppSync Subscriptions - If you're more of a GraphQL person, Michael Liendo has you covered in this complete guide.
- Building a reaction app with Momento Topics - Use a managed gRPC-based mechanism to build browser-to-browser commnications without implementing backend services.
- Developing real-time web apps with Server-Sent Events - An oldie but a goodie from Auth0 showing how to build with SSE using a React front-end.
There's not a right or wrong way to implement real-time notifications (don't quote me on that). All of us have our own unique business needs that make one mechanism more advantageous over another. The best thing you can do is go out and try. Don't be afraid to iterate. See what works well for you, meets your latency SLAs, and provides a maintainable code base for your devs over the life of your app.
Good luck and if you have any questions, feel free to reach out!
Happy coding!
Top comments (0)