Asynchronous Client Interaction in AWS Serverless: Polling, WebSocket, SSE or AppSync?

Xavier Lefèvre
Apr 18 · 6 min read
Image for post
Image for post

The event-driven paradigm is usually adopted with serverless architectures, dispatching asynchronous events to trigger wanted effects.

This behaviour comes natively with most AWS services:

  • if someone uploads a picture on your S3 bucket, you can make a Lambda listen and react to this event
  • if a Lambda adds a new object to your DynamoDB table, you can react in the same way

And when developing your micro-services, we find it best to connect them with the same pattern:

  • when a synchronous Lambda (for example inviteUser) dispatches an event through EventBridge triggering another Lambda (such as sendEmail) (Side note: why EventBridge is a key component in serverless architectures is well explained in this article from Ben Ellerby)

After treating events asynchronously, you will want to update the end-users by pushing data from the back-end to the front-end.

In this article we will reply to two questions: What’s the best way to do the above? How to implement it in JavaScript?

Let’s review our options

This problematic is not new, classic architectures have well-known options: (Long) Polling, WebSocket or Server-Sent Events (SSE). On top of those, AWS offers an higher level abstraction: AWS AppSync.

Let’s deep dive and assess each of them in a serverless context:

Your front-end has the responsibility of regularly asking your back-end if there is any fresh data. Hence the front will make the same call every few seconds/minutes. Sometimes one of those calls will have a fresh data to handle.

Image for post
Image for post
A quick synchronous Polling request is sent every X seconds

Long polling is different in the fact that the request is kept open by the server as long as possible until it eventually returns a fresh data or reaches a timeout.

Image for post
Image for post
A lasting synchronous Long Polling request is sent as soon as the previous one returned

Pros

  • HTTP: robust and easy to handle.

Cons

  • With Polling, you usually add a delay between requests to not make it too intensive, this naturally delays your data arrival (not real-time).
  • Implementation with Lambdas: each Polling request hits a custom Lambda, and keeps its connection alive for the allocated amount of time before sending a potential empty response.
  • Cost with Lambdas: too costly because pinging “useless” HTTP routes and Lambdas as most of the polling requests won’t see a change in data. This con is a deal-breaker.

Your front-end opens a long-lasting, bi-directional communication with your back-end through a WebSocket protocol. Thus, the back can push a message as soon as necessary.

Image for post
Image for post
The WS connection is kept open, then messages are pushed as early as possible

Pros

  • Implementation with Lambdas: WebSocket APIs is an official solution from AWS API Gateway. It handles the connections for you, and only pings your Lambdas on messages.
  • Cost with Lambdas: cheap, using AWS API Gateway pricing source we calculated that a small app with around 25,000 messages per day, triggering 25,000 Lambdas behind, would cost below $1 per month.

Cons

  • WebSocket is a different protocol for delivering data, you need to deal with two different paradigms in your app, HTTP and WS.
  • WebSocket is not automatically multiplexed (compared to HTTP/2). Implementing multiplexing both on the server and the client is a bit complicated.

Your front-end opens a long-lasting, uni-directional communication from your back-end through the HTTP protocol. Here as well, the back-end can push a message as soon as necessary.

Image for post
Image for post
Similar to WebSocket, except that it’s uni-directional (enough for our use-case) and using HTTP

Pros

  • Simple implementation and data efficient with HTTP.
  • It is automatically multiplexed over HTTP/2 out of the box.

Cons

  • Implementation with Lambdas: requires to keep a live connection between the client and your Lambdas in the back-end. Lambdas are not meant to be kept alive for a whole client session. Going around this limit is a hassle.
  • Cost with Lambdas: too costly because of the necessity to keep live Lambdas up and running. This con is a deal-breaker.

AppSync is a fully managed GraphQL API layer. It handles the parsing and resolution of requests connecting them to different data sources such as Lambdas, DynamoDB or HTTP APIs.

It, out of the box, includes real-time GraphQL subscriptions. To which you can connect with your favourite GraphQL front-end framework such as Apollo or Relay.

Pros

  • AppSync is serverless by design.
  • Easy to use, providing GraphQL schema and resolver templates is enough to generate an available GraphQL endpoint which supports GraphQL subscription.
  • Implementation with Lambdas: out of the box.
  • Cost with Lambdas: can be cheaper than WebSocket API as AppSync cost per million connection minutes is $0.08, whereas it’s $0.29 for WebSocket. However the price per million messages is higher ($1.14 for WS against $2 for AppSync).

Cons

  • GraphQL only.
  • Vendor (AWS) lock-in.
  • There is no proper way to implement custom authorizers (only accepting API KEY, AWS IAM, OpenID Connect and AWS Cognito).
  • Hard to pair with an Event-Driven micro-services approach and often results in a monolith or distributed monolith structure.

What’s the best choice then?

We recommend going for WebSocket, because:

  • It’s the only flexible and standard solution officially supported by AWS.
  • It has the smaller cost impact as the connection is kept alive by API Gateway and Lambdas are only triggered on useful events.
  • You’ll find lots of online content and libraries helping you implement WebSocket in a serverless context.

How to set it up?

Pre-requesite: In the context of the Serverless Framework on AWS in TypeScript.
Development time: This solution takes less than half a day to set-up, test and deploy (not including the front-end).

Image for post
Image for post
  1. Start and keep track of the live WebSocket connection
  2. An event, like a SaaS hook, triggers a DB update
  3. A DynamoDB event then triggering a Lambda to notify the front-end of the updated data

Code example:

Configure connect and disconnect Lambdas to keep track of the active connections. When you declare the websocket event type for the first time, Serverless Framework will create a new WebSocket API Gateway. $connect and $disconnect are official WebSocket route events.

Configure your Lambda connection handlers in your serverless.yml
The Lambda called on connect is responsible to keep the connection ID, in your DynamoDB table for instance
The Lambda called on disconnect is responsible to remove the connection ID

Then add a Lambda responsible to push WebSocket messages to the front-ends.

Configure the lambda responsible to update your front-end, preferably triggered with an EventBridge event
The Lambda will pass the message to the interested live connections

And that’s it! With a few lines of code your serverless back-end is ready to handle live WebSocket connections.


That’s the solution we now use by default on our serverless projects in my company (Theodo), until a better one arises!

Beyond that, we are closely looking out for SSE news in serverless. Because outside of serverless, we believe it solves the problem in a nicer way than WebSocket. Some amazing tools exist that we would love to be able to use (for instance Mercure: https://github.com/dunglas/mercure).

I do hope this article answered some of your questions. If you have any question or feedback, feel free to drop a comment, we’d love to hear from you!


Serverless Transformation

Tools, techniques, and case studies of using serverless to…

Thanks to Ben Ellerby and Thibaud Lemaire

Xavier Lefèvre

Written by

⚙️ Tech Enthusiast — 👨‍💻 VP Engineering @ Theodo — ☁️ Into Serverless — 🏍 Motorcycles Lover — 🏮 Traveler

Serverless Transformation

Tools, techniques, and case studies of using serverless to release fast and scale optimally.

Xavier Lefèvre

Written by

⚙️ Tech Enthusiast — 👨‍💻 VP Engineering @ Theodo — ☁️ Into Serverless — 🏍 Motorcycles Lover — 🏮 Traveler

Serverless Transformation

Tools, techniques, and case studies of using serverless to release fast and scale optimally.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store