Build a Node.js chat application with Socket.IO on an Azure Cloud Service
5 stars based on
63 reviews
In this blog post, we review concepts and architectural patterns relevant to a chat application. We also discuss implementation details for a chat client and server, and instructions to deploy a sample chat application into your AWS account. Building a chat application requires a communication channel over socketio blockchain a client can send messages that are redistributed to other participants in the chat room.
This communication is popularly implemented using the publish-subscribe pattern PubSubwhere a message is sent to a centralized topic channel. Interested parties can subscribe to socketio blockchain channel to be notified of updates. This pattern decouples the publisher and subscribers, so that the set of subscribers can grow or shrink without the knowledge of the publisher.
PubSub is implemented on a backend server, to which clients communicate using WebSockets. WebSockets is a persistent TCP connection that provides socketio blockchain channel for data to be streamed bidirectionally between the client and server.
With a single-server socketio blockchain, one PubSub socketio blockchain can manage the state of publishers and subscribers, and also the message redistribution to clients over WebSockets. The diagram following illustrates the path that messages travel over WebSockets between two clients on a single-server PubSub architecture. A single-server architecture is valuable to illustrate the communication flow. However, most solution builders will want to design a multiserver architecture.
A multiserver architecture helps to increase reliability and create elasticity to horizontally scale your application as the number of clients grow. In a multiserver architecture, a client makes a WebSocket connection to a load balancer that forwards traffic to a pool of servers. These servers are responsible for managing the WebSocket connections and data streamed over them. Once a WebSocket connection is established with socketio blockchain PubSub application server, that connection is persisted and data streams to the application in both directions.
The load balancer distributes requests for a WebSocket socketio blockchain to healthy servers, meaning that two clients can establish a WebSocket connection to different application servers. Because multiple applications manage the client WebSocket connections, the applications must communicate among themselves to redistribute messages. This communication is necessary because a message might stream over a WebSocket up to one application server and need to be streamed down to a client connected to a different application server.
You can satisfy this requirement for shared communication among applications by externalizing the PubSub solution from the applications that are managing client connections. The diagram following illustrates the path that messages travel over WebSockets between two clients on a multiserver PubSub architecture.
A persistent connection is established through the load balancer between each client and WebSocket server. A persistent connection is also established between the WebSocket server and the PubSub server for each subscription topic, which is shared among all clients.
A custom PubSub solution is a possibility, but you can also use existing software applications to provide this functionality. Redis is a fast, open-source, in-memory data store and cache that features PubSub socketio blockchain. The application has a backend based on Node. You can find all the code for the sample application in the elasticache-redis-chatapp GitHub repository.
The sample chat application consists socketio blockchain members and messages that communicate in a shared chat room, illustrated in the screenshot following. Instead, when opening the socketio blockchain application in a browser, a member is generated on your behalf with a random user name and avatar.
This name and avatar then appear in the Members list on the left side. As other members join and leave by opening the application in their browsers, their names appear in the web application. Members can send messages, which are redistributed to other web clients and appear in the main chat window.
The web client is implemented using Vue. To reduce complexity for beginners, no JavaScript bundlers were used. However, you should consider webpackor similar software, in a production application.
However, you can find many analogous choices in the community, with more appearing every day. The full example can be found in the GitHub repository. The v-for parameter is used to define the iterator, in this case a key-value tuple for the members object data model discussed momentarily. Within the iterated loop, Mustache templating is used to access each member object and display the user name.
This approach leaves us free to focus on state modifications to underlying Vue. However, a production system would likely modularize the UI components using external. In addition to the markup and Vue. For this application, we establish five topics for communication. Each topic is listed following with the triggering event and corresponding action:. Update the list of messages with the message text and member metadata. Set the list of messages to the truncated list of historically recent messages.
Set the list socketio blockchain members to the list of members participating in the chat room. Following is a JavaScript code to implement these socketio blockchain. When messages are published to the topic, the callback function is executed. The data models are also updated according to the action set, add, delete and target data model array, object.
A bind this statement is appended to inject the Vue. Last, there is a Vue. The method publishes the message text over WebSockets, and then sets the message to an empty string. This string in turn updates the UI by using the Vue. When the web client is opened in a browser, a WebSocket is established socketio blockchain a PubSub application.
On connection, the application must assemble some data for existing members and messages to be published to the new client. It also must update other clients about the new chat room participant. In addition socketio blockchain creating the WebSocket listener, the application must also establish multiple connections to the Redis cluster.
One connection is required to make updates to Redis data models and to publish messages on a topic. An additional connection is required for each of the topic subscriptions. In this code socketio blockchain, the Redis command channel is established using the ioredis JavaScript client. A function is also defined to initialize a new subscription channel, added to a hash of all subscribers keyed socketio blockchain the channel topic.
Each subscription channel functions the same way:. This deserialization must happen because the Socket. Socketio blockchain a web client joins the chat room in a browser, the client establishes a new connection to a WebSocket. We can take action when this connection socketio blockchain established by defining a function, illustrated following:. We use the socket. This identification lets us find and remove members from the Redis data model. The other functions described following reside in the context of this callback function.
The ioredis JavaScript client uses Promises for asynchronous execution processing. Redis supports a Hash data type, but only one level deep. Values of the hash must be socketio blockchain. The callback function iterates the key-value pairs of the hash, deserialized in the next chain to initialize the member. If not, a new member is generated with a random user name using Faker. The last step in the client initialization is to retrieve a truncated list of socketio blockchain recent messages.
To do so, we can take advantage of another Redis data type called a Sorted Set. This type is similar to a Redis Set but includes a rank for each element in the set. Socketio blockchain Sorted Set is a popular data type for leaderboards.
You can also use it to store socketio blockchain chronologically ordered collection of elements when timestamp is used as the rank. Because ioredis uses Promises, we can chain the asynchronous executions together and wait for all to complete before processing the results using Promise.
Now that we have all the required data, we need to use our WebSocket connections to stream data to initialize the new client and communicate a new member has joined the chat room to the all socketio blockchain. One Socketio blockchain can be socketio blockchain to emit multiple messages. The new member must be communicated to all participants. When a new client is completing its initial WebSocket connection, we must also socketio blockchain message handler for messages to be sent by the new client.
The socketio blockchain will socketio blockchain of the message text, member username, member avatar, and the message creation timestamp. We add the message to the message history stored in a Sorted Set using the ZADD command and the message creation timestamp as the rank. When the heartbeat fails, a disconnect event is fired on the client.
When a client disconnects, socketio blockchain reverse the actions taken during the member initialization. Like we notified socketio blockchain participants of a new member joining the chat room, we must socketio blockchain notify all participants that a member is leaving the chat room.
This topic is redistributed to the remaining clients using WebSockets. That completes the code review. CloudFormation gives developers and system administrators an easy way to create and manage a collection of related AWS socketio blockchain. CloudFormation provisions and updates resources in socketio blockchain orderly and predictable fashion.
To launch the CloudFormation stack for the chat application, click the button following. The CloudFormation script creates an Elastic Beanstalk environment, application, and configuration template. It also creates the ElastiCache cluster for Redis and Amazon EC2 security groups for the load balancer, application servers, and Redis cluster.
In this way, we use best practices for least-privilege security configurations between architectural layers. One note regarding the ElastiCache for Redis configuration snippet following. SecurityGroup allows the inline specification of ingress security rules, doing so socketio blockchain a circular reference between the CacheCluster and the SecurityGroup.