paint-brush
Get a Serverless WebSocket Application Up and Running with Lolo in 5 Minutesby@lolocode
678 reads
678 reads

Get a Serverless WebSocket Application Up and Running with Lolo in 5 Minutes

by Lolo CodeSeptember 6th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Create a serverless websocket application in just a few minutes. We’ll demonstrate something very simple here by using a pre-made Websocket Trigger to connect and broadcast all messages to all connected clients. You'll deploy it quickly via to the cloud for free and can use it in production right away. It goes without saying that you can connect it to a frontend so you have a chat application up and running for as many users as you'd like. Although there is a limit to a few thousand events per second. If you have more than that add replicas in your Lolo app.
featured image - Get a Serverless WebSocket Application Up and Running with Lolo in 5 Minutes
Lolo Code HackerNoon profile picture

WebSockets are mainly used to create real-time applications, such as chat apps, collaboration platforms and streaming dashboards. These applications take advantage of two-way/bidirectional communication between a server and users’ browsers.


Serverless is usually associated with FaaS, an isolated stateless function that is triggered by another service. Creating a Serverless Websocket application would require you to use AWS Lambda with WebSockets in API Gateway and DynamoDB to store connections. This is overly complicated.


We’ll show you how to create something faster. Serverless iFaaS platforms don’t require initialization before the function executes so you don’t pay a price for waking up a container once it has been deployed. It’s technically always live. You also have access to a baked-in key/value store which means that you don’t end up losing state between subsequent invocations. I.e. you don’t have to start from a blank slate on every invocation. Hence the lack of need for an external database such as DynamoDB.

The Plan

We’ll demonstrate something very simple here by using a pre-made Websocket Trigger to connect and broadcast all messages to all connected clients. See the visual workflow below. You’ll need a free Lolo account to set this up yourself.


Our Lolo workflow for a simple chat websocket application.


If you want to get started right away you can simply copy the contents of this documentand paste it into a new application in a blank graph in Lolo. Save and Run the application to deploy it. That’s 1 minute of work.

Do follow along though if you want to understand how to use it or if you want to set this up from scratch.

Create an Application and add a Trigger

To begin, we need to set up a new WebSocket server that can handle inbound WebSocket requests from clients.


We do this by first creating a new application in your Lolo account and then adding the Lolo/Websocket Trigger from the Functions Gallery on the left of the graph. Add in a path name, such as /socket. You can also rename it.


Create an application, add the WebSocket trigger in the menu to the left. Remember to set a path in the node.


Process the Incoming Request

When you add this WebSocket Trigger you get three output ports in the node called reqmessage and close so you need to set up ways to process these requests. Add another inline Function (i.e. a custom function) and name it ‘Process Request.’ Remove the in port and instead add in three in ports called reqmsg and close.

Link the ports to the right in and out ports with the nodes, look below for an illustration on how to do this.


Create a custom function to process the incoming request, add in ports in the node and connect them with the other node.

We need a bit of code to do something here with the WebSocket connection. Copy and paste in the code from below. Open up the Process Request node and paste in the code below in the handler.


const connections = {};

exports.handler = async (ev, ctx) => {
  const { route, input, inputs, log, emit } = ctx;
  const { sessionId } = ev;

  // check incoming port (i.e. req, message or close)
  switch (input) {

    // on first connection
    case inputs.req:
      connections[sessionId] = {
        send: body => emit('response', { body }),
        end: () => emit('response', { end: true }),
        info: ev.headers
      }
      ev.body = { connected: true, yourConnectionId: sessionId };
      // re-route data to 'req' output port
      route(ev, 'req');
      break;

    // on subsequent messages 
    case inputs.msg:
      // re-route data to 'msg' output port
      route({ connections, message: ev.message, sessionId }, 'msg')
      break;

    // when client disconnects 
    case inputs.close:
      log.info("client has disconnected");
      delete connections[sessionId];
      break;
  }
};


The code above is checking what ports the incoming data is routed through, giving us a way to handle a new connection by adding it to connections. We are also setting up how we want to handle subsequent messages and a disconnecting client by using the in ports, msg and close.

This code above though is re-routing to other nodes via the route() method as well. As you can see we have two output routes here to ‘req’ and ‘msg.’ We thus need to add those two output ports as well.


Paste in the code in the handler and then change the out ports to req and msg.


Send back a response

Now we have two outports in the Process Request Function that needs to go somewhere, so we create another inline Function called Affirm Connectionand paste the code below.

All this does is signal the listener within the WebSocket Trigger to send a response to the client. We will route the req route to this node.

exports.handler = async(ev, ctx) => {
  const { emit, log } = ctx;
  // Log to the console that a client has connected
  log.info("client has connected");
  // send response to the client
  emit('response', ev);
};


Along with this we also need a way to handle subsequent messages. In this case, we said we would broadcast all messages to all clients when someone sends something. So, create another inline Function (i.e. a custom function) and call it Handle Messages. Paste in the code below, and see the comments to understand what it does.

exports.handler = async (ev, ctx) => {
  // extract connections, and current session id from the event data
  const { connections, sessionId } = ev;
  // send messages
  await broadcastToAll(ctx, connections, sessionId, ev);
};

const broadcastToAll = async ({ log }, connections, currentSessionId, ev) => {

  // loop through connections
  Object.keys(connections).forEach(sessionId => {
    try {
        // send message to everyone but the current sessionId
        if (currentSessionId !== sessionId) {
        connections[sessionId].send(`${sessionId} says: ${ev.message}`)
        } 
    } catch (e) {
      log.error(e)
    }
  });
};


You can remove the out ports for both of these new Functions. Now we also have to route the data visually from the Process Request node to the other two nodes we’ve created.

See these steps in action below.


Create two new custom nodes/functions, change the code and connect them with the other nodes.


Save and Deploy

Alright, that was it. You can save and deploy.

Look in the Logs for the ‘Listening to port 4000’ message to see if it is ready to use. This may take a while. We are not using any NPM modules here so should be faster but if we did we would have to wait about a minute.


Now go into the WebSocket Trigger to collect the External URL. We are going to use it to connect to this Websocket.


Open two terminals on your computer and then connect via wscat on both.


wscat -c wss://eu-1.lolo.co/:appId/socket


Remember to NPM install wscat -g (via your terminal) first if you don’t already have wscat installed.


Now you should be able to talk via the different terminals. Say hi and what’s up in either terminal and see the response broadcasted to all connected clients.


You can ask a friend to connect on a different computer and talk that way. It goes without saying that you can connect this via a frontend to build a quick chat app.


Go get your url to connect to this websocket.


Set up two terminals or use some other method to open up two connections to talk to each other. You can open up as many connections as you'd like.


Remember if you are having issues, just copy the contents of this document and paste it into an empty graph in a Lolo application to get the entire app set up for you.


Your Lolo app in free tier should be able to handle a few thousand of events per second. If you need more than that you simply add replicas when you configure your deployment to handle the increased load.


Let us know if you have any feedback. We’re keen to create better Serverless experiences.



Also published here.