nest
nest copied to clipboard
Cluster mode and Socketio sticky sessions
trafficstars
Is there an existing issue for this?
- [X] I have searched the existing issues
Current behavior
Please someone. How can i implement sticky session for a Nest app running in cluster mode.The Nest docs have no info about this and Socketio have no docs for nest(.I have posted a question on Socketio github discussions and Nest discord but nothing.I already implemented adapter but the sticky sessions from ** @socket.io/sticky** i can't setup.Maybe someone did this.
Minimum reproduction code
a
Steps to reproduce
No response
Expected behavior
This is main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
import { Logger, ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { SocketIOAdapter } from './core/socket/adapters/socket.io.adapter';
import * as cluster from 'cluster';
import * as os from 'os';
const clusterInstance = cluster as unknown as cluster.Cluster;
import { NODE_ENV } from './common/enums/node.env.enum';
async function bootstrap() {
const logger = new Logger();
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }));
app.enableCors({
origin: '*',
});
const socketIOAdapter = new SocketIOAdapter(app);
app.useWebSocketAdapter(socketIOAdapter);
const configService: ConfigService = app.get(ConfigService);
const port: number = configService.get('port');
const nodeEnv: string = configService.get('NODE_ENV');
if (nodeEnv !== NODE_ENV.PRODUCTION) {
const config = new DocumentBuilder()
.setTitle('Chat application')
.setDescription('The corporative chat application written in Nest')
.setVersion('1.0')
.addBearerAuth({ type: 'http', name: 'accessToken' })
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);
}
await app.listen(port);
logger.log(
`Find docs on http://localhost:${port}/api/docs`,
'NestApplication',
);
}
const runningOnCluster: boolean =
Object.values(NODE_ENV)
.filter((env) => env !== NODE_ENV.LOCAL)
.findIndex((env) => env === process.env.NODE_ENV) > -1;
if (runningOnCluster) {
if (clusterInstance.isPrimary) {
const cpuCount = os.cpus().length;
for (let i = 0; i < cpuCount; i += 1) {
clusterInstance.fork();
}
clusterInstance.on('online', (worker) => {
Logger.log(`${worker.process.pid} is online`, 'NestApplication::Cluster');
});
clusterInstance.on('exit', ({ process }) => {
Logger.log(`${process.pid} died`, 'NestApplication::Cluster');
});
} else {
bootstrap();
}
} else {
bootstrap();
}
and this is redis streams adatper
import { INestApplicationContext } from '@nestjs/common';
import { IoAdapter } from '@nestjs/platform-socket.io';
import { Server, ServerOptions } from 'socket.io';
import { WsAuthMiddleware } from '../../../core/socket/middlewares/ws.auth.middleware';
import { createAdapter } from '@socket.io/redis-streams-adapter';
import { ConfigService } from '@nestjs/config';
import {
DEFAULT_NAMESPACE,
REDIS_CLIENT,
} from 'src/common/constants/constants';
import { WsQueryValidationMiddleware } from '../middlewares/ws.query.validation.middleware';
import { RedisClientType } from 'redis';
export class SocketIOAdapter extends IoAdapter {
private configService: ConfigService;
private redisClient: RedisClientType;
private adapterConstructor: ReturnType<typeof createAdapter>;
constructor(private app: INestApplicationContext) {
super(app);
this.configService = this.app.get(ConfigService);
this.redisClient = this.app.get(REDIS_CLIENT);
this._createClient();
}
private _createClient(): void {
const streamName = this.configService.get<string>('redisConfig.streamName');
this.adapterConstructor = createAdapter(this.redisClient, { streamName });
}
createIOServer(port: number, options?: ServerOptions): Server {
const server: Server = super.createIOServer(port, {
...options,
cors: {
origin: (_req: any, callback: (arg0: null, arg1: boolean) => void) => {
callback(null, true);
},
credentials: true,
},
transports: ['polling', 'websocket'],
allowUpgrades: true,
});
server.adapter(this.adapterConstructor);
server.of(DEFAULT_NAMESPACE).use(WsAuthMiddleware);
server.of(DEFAULT_NAMESPACE).use(WsQueryValidationMiddleware);
return server;
}
}
Package
- [ ] I don't know. Or some 3rd-party package
- [ ]
@nestjs/common - [ ]
@nestjs/core - [ ]
@nestjs/microservices - [ ]
@nestjs/platform-express - [ ]
@nestjs/platform-fastify - [X]
@nestjs/platform-socket.io - [ ]
@nestjs/platform-ws - [ ]
@nestjs/testing - [ ]
@nestjs/websockets - [ ] Other (see below)
Other package
No response
NestJS version
No response
Packages versions
"@nestjs/websockets": "^10.3.8",
"@socket.io/redis-streams-adapter": "^0.2.2",
"@socket.io/sticky": "^1.0.4",
Node.js version
No response
In which operating systems have you tested?
- [X] macOS
- [X] Windows
- [X] Linux
Other
No response