feat(realtime): Socket.IO Redis adapter — enable horizontal scaling
- RedisIoAdapter wires @socket.io/redis-adapter with dedicated pub/sub clients - channel key 'tripz:sio' isolates on shared Redis - wired in main.ts via useWebSocketAdapter; multiple app replicas can now share WS connections Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@
|
|||||||
"@nestjs/throttler": "^6.2.0",
|
"@nestjs/throttler": "^6.2.0",
|
||||||
"@nestjs/typeorm": "^11.0.0",
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"@nestjs/websockets": "^11.0.0",
|
"@nestjs/websockets": "^11.0.0",
|
||||||
|
"@socket.io/redis-adapter": "^8.3.0",
|
||||||
"bullmq": "^5.12.0",
|
"bullmq": "^5.12.0",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.1",
|
"class-validator": "^0.14.1",
|
||||||
|
|||||||
@@ -4,11 +4,17 @@ import { ValidationPipe, Logger } from '@nestjs/common';
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
import { RedisIoAdapter } from './realtime/redis-io.adapter';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
const cfg = app.get(ConfigService);
|
const cfg = app.get(ConfigService);
|
||||||
|
|
||||||
|
// مُحوّل Socket.IO عبر Redis — يفعّل التوسّع الأفقي (عدة نسخ)
|
||||||
|
const redisIoAdapter = new RedisIoAdapter(app, cfg);
|
||||||
|
await redisIoAdapter.connectToRedis();
|
||||||
|
app.useWebSocketAdapter(redisIoAdapter);
|
||||||
|
|
||||||
app.setGlobalPrefix('api');
|
app.setGlobalPrefix('api');
|
||||||
app.useGlobalPipes(
|
app.useGlobalPipes(
|
||||||
new ValidationPipe({ whitelist: true, transform: true }),
|
new ValidationPipe({ whitelist: true, transform: true }),
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { INestApplicationContext, Logger } from '@nestjs/common';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { IoAdapter } from '@nestjs/platform-socket.io';
|
||||||
|
import { ServerOptions } from 'socket.io';
|
||||||
|
import { createAdapter } from '@socket.io/redis-adapter';
|
||||||
|
import Redis from 'ioredis';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* مُحوّل Socket.IO مدعوم بـ Redis — يجعل التطبيق قابلاً للتشغيل بعدة نسخ
|
||||||
|
* (توسّع أفقي) تتشارك اتصالات الويب سوكت عبر Redis. بلا هذا، رسالة من نسخة
|
||||||
|
* لا تصل زبوناً متصلاً بنسخة أخرى (راجع docs/09).
|
||||||
|
* مفتاح القنوات ببادئة tripz للعزل عن أي تطبيق آخر على نفس Redis.
|
||||||
|
*/
|
||||||
|
export class RedisIoAdapter extends IoAdapter {
|
||||||
|
private readonly logger = new Logger('SocketRedis');
|
||||||
|
private adapterConstructor: ReturnType<typeof createAdapter>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
app: INestApplicationContext,
|
||||||
|
private readonly config: ConfigService,
|
||||||
|
) {
|
||||||
|
super(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectToRedis(): Promise<void> {
|
||||||
|
const opts = {
|
||||||
|
host: this.config.get<string>('redis.host'),
|
||||||
|
port: this.config.get<number>('redis.port'),
|
||||||
|
db: this.config.get<number>('redis.db'),
|
||||||
|
maxRetriesPerRequest: null,
|
||||||
|
};
|
||||||
|
const pub = new Redis(opts);
|
||||||
|
const sub = pub.duplicate();
|
||||||
|
pub.on('error', (e) => this.logger.warn(`pub: ${e.message}`));
|
||||||
|
sub.on('error', (e) => this.logger.warn(`sub: ${e.message}`));
|
||||||
|
// key يعزل قنوات socket.io الخاصة بـ Tripz عن غيرها على نفس Redis
|
||||||
|
this.adapterConstructor = createAdapter(pub, sub, { key: 'tripz:sio' });
|
||||||
|
this.logger.log('Socket.IO Redis adapter ready (horizontal scale enabled)');
|
||||||
|
}
|
||||||
|
|
||||||
|
createIOServer(port: number, options?: ServerOptions): any {
|
||||||
|
const server = super.createIOServer(port, options);
|
||||||
|
if (this.adapterConstructor) server.adapter(this.adapterConstructor);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## التقنية
|
## التقنية
|
||||||
- **Socket.IO** عبر `@nestjs/websockets` Gateway.
|
- **Socket.IO** عبر `@nestjs/websockets` Gateway.
|
||||||
- **`socket.io-redis-adapter`** للتوسع الأفقي (عدة نسخ من الباك إند تتشارك الحالة).
|
- **`@socket.io/redis-adapter`** للتوسع الأفقي — **مفعّل** عبر `RedisIoAdapter` في `main.ts` (قنوات ببادئة `tripz:sio`). يسمح بتشغيل عدة نسخ تتشارك اتصالات الويب سوكت عبر Redis.
|
||||||
- **Redis** للحضور (presence) والمطابقة الجغرافية (GEO commands).
|
- **Redis** للحضور (presence) والمطابقة الجغرافية (GEO commands).
|
||||||
|
|
||||||
## المصادقة على الاتصال
|
## المصادقة على الاتصال
|
||||||
|
|||||||
Reference in New Issue
Block a user