You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When deploying a Node.js application that uses Socket.IO for real-time communication, scaling can be challenging due to the need for session consistency and message broadcasting across multiple instances. Using a Redis adapter and Redis emitter can help manage these challenges effectively.
Prerequisites
Kubernetes Cluster: A running Kubernetes cluster.
Redis: A Redis instance accessible by the Node.js application.
Node.js Application: An existing Node.js application using Socket.IO.
Node Code:
import express from 'express';
import http from 'http';
import { Server } from 'socket.io';
import cors from 'cors';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';
import { Emitter } from '@socket.io/redis-emitter';
const app = express();
const server = http.createServer(app);
// Get Redis external IP and port from environment variables
const redisHost = process.env.REDIS_HOST || '192.168.0.49'; // Update this to your Redis IP
const redisPort = Number(process.env.REDIS_PORT) || 31225; // Update this to your Redis port
// Create a Redis client
const redisClient = createClient({ url: `redis://${redisHost}:${redisPort}` });
const subClient = redisClient.duplicate();
// Handle Redis connection errors
redisClient.on('error', (err) => {
console.error('Redis client error:', err);
});
// Set up CORS options for Socket.IO
const io = new Server(server, {
cors: {
origin: '*',
methods: ['GET', 'POST'],
credentials: true,
},
});
// Connect to Redis and configure Socket.IO
redisClient.connect().then(() => {
console.log('Connected to Redis');
// Set the Redis adapter for Socket.IO
io.adapter(createAdapter(redisClient, subClient));
// Create a Redis emitter
const emitter = new Emitter(redisClient);
// Emit a message every 5 seconds
setInterval(() => {
const currentTime = new Date();
console.log('Emitting time:', currentTime);
emitter.emit('time', currentTime.toISOString()); // Emit the current time in ISO format
}, 5000); // Emit every 5 seconds
}).catch((err) => {
console.error('Redis connection error:', err);
});
// Enable CORS for all routes
app.use(cors());
// Handle Socket.IO connections
io.on('connection', (socket) => {
console.log('New client connected');
// Listen for the 'time' event emitted by Redis
socket.on('time', (time) => {
console.log('Time received:', time);
socket.emit('time', time); // Send the time to the connected client
});
// Listen for the 'time' event from the emitter and send to the client
socket.on('subscribeToTime', () => {
console.log('Client subscribed to time updates');
socket.join('time-updates');
});
// Listen for incoming messages and broadcast them
socket.on('sendMessage', (message) => {
io.emit('receiveMessage', message);
});
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
// Listen to Redis for 'time' events and broadcast them to all clients
subClient.on('message', (channel: string, message: string) => {
if (channel === 'time') {
const time = new Date(message);
io.to('time-updates').emit('time', time); // Emit the time to subscribed clients
}
});
// Subscribe to the 'time' channel
subClient.subscribe('time', (err) => {
if (err) {
console.error('Failed to subscribe to time channel:', err);
} else {
console.log('Subscribed to time channel');
}
});
// Start the server
const PORT = process.env.PORT || 5001;
server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
App.tsx
Client App code (react js)
import React from 'react';
import { Chat } from './Chat';
import { io } from 'socket.io-client';
// Use an environment variable or fallback to a default URL
console.log(process.env.REACT_APP_SOCKET_URL)
const socket = io(process.env.REACT_APP_SOCKET_URL || 'http://localhost:5001');
console.log(socket)
const App: React.FC = () => {
return (
<div>
<h1>Group Chat Application</h1>
<Chat socket={socket} />
</div>
);
};
export default App;
Chat.tsx
import React, { useEffect, useState } from 'react';
import { Socket } from 'socket.io-client'; // Import the Socket type
interface ChatProps {
socket: Socket; // Use the Socket type here
}
export const Chat: React.FC<ChatProps> = ({ socket }) => {
const [message, setMessage] = useState('');
const [messages, setMessages] = useState<string[]>([]);
useEffect(() => {
socket.on('receiveMessage', (message: string) => {
setMessages((prev) => [...prev, message]);
});
return () => {
socket.off('receiveMessage'); // Clean up the listener on unmount
};
}, [socket]);
const sendMessage = () => {
if (message) {
socket.emit('sendMessage', message);
setMessage('');
}
};
return (
<div>
<div>
{messages.map((msg, index) => (
<div key={index}>{msg}</div>
))}
</div>
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
sendMessage();
}
}}
/>
<button onClick={sendMessage}>Send</button>
</div>
);
};
The text was updated successfully, but these errors were encountered:
Introduction
Prerequisites
Node Code:
App.tsx
Chat.tsx
The text was updated successfully, but these errors were encountered: