The Secret Life of AWS: The Real-Time Loop (Amazon API Gateway WebSockets)
The Secret Life of AWS: The Real-Time Loop (Amazon API Gateway WebSockets)
How to push asynchronous backend updates to your frontend using WebSockets
#AWS #APIGateway #WebSockets #CloudArchitecture
Margaret is a senior software engineer. Timothy is her junior colleague. They work in a grand Victorian library in London — the kind of place where code quality is the unspoken objective, and craftsmanship is the only thing that matters.
Episode 65
Timothy was reading a furious customer feedback form. He turned his monitor toward Margaret as she walked into the studio.
"Our event-driven architecture is lightning fast, but it is causing a severe customer experience problem," Timothy explained. "A customer clicked 'Checkout' on our website. The API Gateway instantly returned a success response, and the browser showed a green checkmark. But three seconds later, the backend Saga realized the item was out of stock and triggered the automated refund."
"So the customer thought they bought the item, only to receive an apology email ten minutes later," Margaret observed.
"Exactly," Timothy sighed. "Because our microservices are fully decoupled and asynchronous, the frontend browser has no idea what is actually happening in the backend. I was thinking we could just write some JavaScript in the browser to ping the database every single second to ask if the order is done yet."
"That is called Polling," Margaret warned. "And if you have a million users pinging your database every second, you will accidentally launch a Distributed Denial of Service attack against your own architecture. For simple one-way streaming, some teams use Server-Sent Events, but for a true interactive application, we do not want the client to ask for updates. We want the backend to push the updates. We need Amazon API Gateway WebSockets."
The Persistent Connection
Margaret opened the AWS Console and navigated to API Gateway, selecting the WebSocket API type.
"A standard HTTP request is stateless: the client asks, the server answers, and the connection drops," Margaret explained. "A WebSocket is a persistent, bidirectional connection. The browser opens a tunnel to API Gateway and leaves it open. API Gateway assigns that browser a unique connectionId."
"If the connection stays open, doesn't that mean our Lambda functions have to stay awake the entire time?" Timothy asked. "That would ruin our serverless billing model."
"That is the magic of API Gateway," Margaret smiled. "API Gateway holds the persistent connection for you. Your Lambda functions remain completely serverless and asleep. We just save the connectionId into a DynamoDB table, keyed by the customer's userId, when they connect. We can even secure these connections using a Lambda authorizer, just like our REST APIs. The default limit is 500 concurrent WebSocket connections per region, but we can easily increase that via a service quota request as we scale."
Pushing from the Backend
Margaret updated the final step of Timothy's Step Functions Saga. She added a new Lambda function that executes only when the order is definitively finalized or explicitly refunded.
She opened the Node.js handler for this new function:
const { ApiGatewayManagementApiClient, PostToConnectionCommand } = require("@aws-sdk/client-apigatewaymanagementapi");
// The endpoint is your specific API Gateway WebSocket URL
const client = new ApiGatewayManagementApiClient({ endpoint: process.env.WEBSOCKET_URL });
exports.handler = async function notifyFrontend(event) {
const connectionId = await getDynamoDBConnectionId(event.userId);
const orderStatus = event.status;
const command = new PostToConnectionCommand({
ConnectionId: connectionId,
Data: Buffer.from(JSON.stringify({ message: orderStatus }))
});
try {
await client.send(command);
console.log("Successfully pushed update to the browser.");
} catch (error) {
if (error.$metadata.httpStatusCode === 410) {
console.log(`Connection ${connectionId} is stale. The user closed their browser.`);
await deleteDynamoDBConnectionId(connectionId);
} else {
throw error;
}
}
}
Closing the Loop
"Notice the paradigm shift," Margaret pointed out. "The browser makes the initial request and then just sits there, listening. Meanwhile, your event bus routes the data, your idempotency keys prevent duplicates, and your Step Functions Saga orchestrates the transaction."
"And the moment the Saga finishes," Timothy realized, reading the code, "this Lambda function looks up the connectionId and uses the API Gateway Management API to fire a message directly down the open tunnel to the specific user's browser."
"Precisely," Margaret said. "If the inventory check fails, the frontend instantly receives the refunded message, and the JavaScript immediately updates the UI to tell the customer to try a different item. It handles stale connections gracefully using the 410 status code. No refreshing. No polling. Pure real-time communication."
Timothy updated his architecture diagram. His application was no longer a one-way street; he had successfully bridged the asynchronous gap between his serverless backend and his users.
Key Concepts Introduced
The Asynchronous UX Gap
In event-driven architectures, backend processing often happens in the background after the initial API request has already returned a successful response to the user. This creates a disconnect where the frontend UI does not reflect the true, final state of the backend transaction.
Polling vs WebSockets vs SSE
Polling is an anti-pattern where a client repeatedly asks the server for updates, wasting massive amounts of compute and database resources. Server-Sent Events provide a simple alternative for one-way server-to-client streaming. However, WebSockets provide a persistent, bidirectional communication channel over a single TCP connection, establishing the enterprise standard for real-time applications.
Amazon API Gateway WebSockets
A fully managed service that handles the heavy lifting of maintaining persistent WebSocket connections. It decouples the persistent connection from the compute layer, meaning AWS Lambda functions do not need to stay awake while waiting for data. Connections can be secured using IAM or custom Lambda authorizers, and connections are mapped to individual users via a fast database like DynamoDB.
API Gateway Management API
The AWS SDK interface used by backend services to send data back to connected clients. By calling the PostToConnectionCommand with a specific connectionId, the backend can push real-time JSON payloads directly into a user's browser the moment a background Saga or asynchronous task completes. Catching a 410 Gone HTTP status code is a required best practice to clean up stale connections when users close their browsers.
Aaron Rose is a software engineer and technology writer at tech-reader.blog.
Catch up on the latest explainer videos, podcasts, and industry discussions below.
.jpeg)

Comments
Post a Comment