Skip to content

Commit

Permalink
Merge branch 'dev-be' into feture-be-#333
Browse files Browse the repository at this point in the history
  • Loading branch information
NewCodes7 authored Dec 23, 2024
2 parents 5f50df1 + 7309170 commit 7ddb652
Show file tree
Hide file tree
Showing 15 changed files with 526 additions and 116 deletions.
57 changes: 48 additions & 9 deletions BE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion BE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@nestjs/mapped-types": "*",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-socket.io": "^10.4.6",
"@nestjs/platform-socket.io": "^10.4.15",
"@nestjs/schedule": "^4.1.1",
"@nestjs/swagger": "^8.0.5",
"@nestjs/typeorm": "^10.0.2",
Expand All @@ -56,6 +56,7 @@
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"pinpoint-node-agent": "^0.9.0-next.0",
"prom-client": "^15.1.3",
"redis": "^4.7.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
Expand Down
4 changes: 3 additions & 1 deletion BE/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { AuthModule } from './auth/auth.module';
import { ScheduleModule } from '@nestjs/schedule';
import { GameRedisMemoryService } from './game/redis/game-redis-memory.service';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { MetricModule } from './metric/metric.module';

@Module({
imports: [
Expand Down Expand Up @@ -55,7 +56,8 @@ import { APP_INTERCEPTOR } from '@nestjs/core';
InitDBModule,
WaitingRoomModule,
TimeModule,
AuthModule
AuthModule,
MetricModule
],
controllers: [AppController, TimeController],
providers: [
Expand Down
85 changes: 43 additions & 42 deletions BE/src/common/interceptor/SocketEventLoggerInterceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class SocketEventLoggerInterceptor implements NestInterceptor {
return next.handle();
}

const startTime = Date.now();
const startedAt = process.hrtime();
const ctx = context.switchToWs();
const client: Socket = ctx.getClient();
const event = ctx.getData();
Expand All @@ -76,48 +76,53 @@ export class SocketEventLoggerInterceptor implements NestInterceptor {
try {
traceContext.addLog(`[${className}.${methodName}] Started`);
const result = await firstValueFrom(next.handle());
const executionTime = Date.now() - startTime;
const endedAt = process.hrtime(startedAt);
const delta = endedAt[0] * 1e9 + endedAt[1];
const executionTime = delta / 1e6;

const logs = traceContext.getLogs();

// μ‹œμŠ€ν…œ λ©”νŠΈλ¦­ μˆ˜μ§‘
const metrics = await this.systemMetricsService.getMetrics();

if (executionTime >= this.EXECUTION_TIME_THRESHOLD) {
this.logger.warn(
'\n=============================\n' +
'🐒 Slow Socket Event Detected!\n' +
logs.join('\n') +
`\nTotal Execution Time: ${executionTime}ms\n` +
'\nSystem Metrics:\n' +
`CPU Usage: ${metrics.cpu.toFixed(2)}%\n` +
'\nMemory Usage:\n' +
`System Total: ${metrics.memory.system.total}GB\n` +
`System Used: ${metrics.memory.system.used}GB (${metrics.memory.system.usagePercentage}%)\n` +
`System Free: ${metrics.memory.system.free}GB\n` +
`Process Heap: ${metrics.memory.process.heapUsed}MB / ${metrics.memory.process.heapTotal}MB\n` +
`Process RSS: ${metrics.memory.process.rss}MB\n` +
'\nMySQL Connections:\n' +
`Total: ${metrics.mysql.total}, ` +
`Active: ${metrics.mysql.active}, ` +
`Idle: ${metrics.mysql.idle}, ` +
`Waiting: ${metrics.mysql.waiting}\n` +
'\nRedis Connections:\n' +
`Connected Clients: ${metrics.redis.connectedClients}, ` +
`Used Memory: ${metrics.redis.usedMemoryMB}MB\n` +
// `ν΄λΌμ΄μ–ΈνŠΈ 큐 길이: ${metrics.redis.queueLength}\n` +
// `ν˜„μž¬ μ²˜λ¦¬μ€‘μΈ λͺ…λ Ήμ–΄ 수 : ${metrics.redis.cmdstat}\n` +
'============================='
);
} else {
this.logger.log(
'\n=============================\n' +
'πŸš€ Socket Event Processed\n' +
logs.join('\n') +
`\nTotal Execution Time: ${executionTime}ms\n` +
'============================='
// 정상 μ²˜λ¦¬μ‹œμ—λŠ” κ°„λ‹¨ν•œ 둜그만
);
}
this.logger.log(`${methodName} - ${executionTime}ms`);

// if (executionTime >= this.EXECUTION_TIME_THRESHOLD) {
// this.logger.warn(
// '\n=============================\n' +
// '🐒 Slow Socket Event Detected!\n' +
// logs.join('\n') +
// `\nTotal Execution Time: ${executionTime}ms\n` +
// '\nSystem Metrics:\n' +
// `CPU Usage: ${metrics.cpu.toFixed(2)}%\n` +
// '\nMemory Usage:\n' +
// `System Total: ${metrics.memory.system.total}GB\n` +
// `System Used: ${metrics.memory.system.used}GB (${metrics.memory.system.usagePercentage}%)\n` +
// `System Free: ${metrics.memory.system.free}GB\n` +
// `Process Heap: ${metrics.memory.process.heapUsed}MB / ${metrics.memory.process.heapTotal}MB\n` +
// `Process RSS: ${metrics.memory.process.rss}MB\n` +
// '\nMySQL Connections:\n' +
// `Total: ${metrics.mysql.total}, ` +
// `Active: ${metrics.mysql.active}, ` +
// `Idle: ${metrics.mysql.idle}, ` +
// `Waiting: ${metrics.mysql.waiting}\n` +
// '\nRedis Connections:\n' +
// `Connected Clients: ${metrics.redis.connectedClients}, ` +
// `Used Memory: ${metrics.redis.usedMemoryMB}MB\n` +
// // `ν΄λΌμ΄μ–ΈνŠΈ 큐 길이: ${metrics.redis.queueLength}\n` +
// // `ν˜„μž¬ μ²˜λ¦¬μ€‘μΈ λͺ…λ Ήμ–΄ 수 : ${metrics.redis.cmdstat}\n` +
// '============================='
// );
// } else {
// this.logger.log(
// '\n=============================\n' +
// 'πŸš€ Socket Event Processed\n' +
// logs.join('\n') +
// `\nTotal Execution Time: ${executionTime}ms\n` +
// '============================='
// // 정상 μ²˜λ¦¬μ‹œμ—λŠ” κ°„λ‹¨ν•œ 둜그만
// );
// }

subscriber.next(result);
subscriber.complete();
Expand Down Expand Up @@ -205,10 +210,6 @@ export function Trace() {
* @function TraceClass
* @description 클래슀의 λͺ¨λ“  λ©”μ„œλ“œμ— 좔적을 μ μš©ν•˜λŠ” λ°μ½”λ ˆμ΄ν„°
*/
/**
* @class TraceClass
* @description 클래슀의 λͺ¨λ“  λ©”μ„œλ“œμ— 좔적을 μ μš©ν•˜λŠ” λ°μ½”λ ˆμ΄ν„°
*/
export function TraceClass(
options: Partial<{ excludeMethods: string[]; includePrivateMethods: boolean }> = {}
) {
Expand Down
37 changes: 2 additions & 35 deletions BE/src/game/game.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import { parse, serialize } from 'cookie';
import { v4 as uuidv4 } from 'uuid';
import { SetPlayerNameDto } from './dto/set-player-name.dto';
import { KickRoomDto } from './dto/kick-room.dto';
import { SocketEventLoggerInterceptor } from '../common/interceptor/SocketEventLoggerInterceptor';
import { ExceptionMessage } from '../common/constants/exception-message';
import { MetricInterceptor } from '../metric/metric.interceptor';

@UseInterceptors(SocketEventLoggerInterceptor)
@UseInterceptors(MetricInterceptor)
@UseInterceptors(GameActivityInterceptor)
@UseFilters(new WsExceptionFilter())
@WebSocketGateway({
Expand All @@ -53,39 +53,6 @@ export class GameGateway {
private readonly gameRoomService: GameRoomService
) {}

@SubscribeMessage('slowEvent')
async handleSlowEvent(@ConnectedSocket() client: Socket): Promise<void> {
// μ˜λ„μ μœΌλ‘œ 지연 λ°œμƒμ‹œν‚€λŠ” ν…ŒμŠ€νŠΈ μ½”λ“œ
await this.gameService.longBusinessLogic();
await new Promise((resolve) => setTimeout(resolve, 1500));
// μ‹€μ œ 둜직
// ...
}

// @SubscribeMessage(SocketEvents.CREATE_ROOM)
// @UsePipes(new GameValidationPipe(SocketEvents.CREATE_ROOM))
// async handleCreateRoom(
// @MessageBody() gameConfig: CreateGameDto,
// @ConnectedSocket() client: Socket
// ): Promise<void> {
// const roomId = await this.gameRoomService.createRoom(gameConfig, client.data.playerId);
// client.emit(SocketEvents.CREATE_ROOM, { gameId: roomId });
// }

// @SubscribeMessage(SocketEvents.JOIN_ROOM)
// @UsePipes(new GameValidationPipe(SocketEvents.JOIN_ROOM))
// @UseGuards(WsJwtAuthGuard)
// async handleJoinRoom(
// @MessageBody() dto: JoinRoomDto,
// @ConnectedSocket() client: Socket
// ): Promise<void> {
// if (client.data.user) {
// dto.playerName = client.data.user.nickname;
// }
// const players = await this.gameRoomService.joinRoom(client, dto, client.data.playerId);
// client.emit(SocketEvents.JOIN_ROOM, { players });
// }

@SubscribeMessage(SocketEvents.UPDATE_POSITION)
@UsePipes(new GameValidationPipe(SocketEvents.UPDATE_POSITION))
async handleUpdatePosition(
Expand Down
2 changes: 1 addition & 1 deletion BE/src/game/game.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { SystemMetricsService } from '../common/service/SystemMetricsService';
PlayerSubscriber,
RoomCleanupSubscriber,
SocketEventLoggerInterceptor,
SystemMetricsService
SystemMetricsService,
],
exports: [GameService]
})
Expand Down
2 changes: 1 addition & 1 deletion BE/src/game/interceptor/gameActivity.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class GameActivityInterceptor implements NestInterceptor {
const data = context.switchToWs().getData();
if (data.gameId) {
await this.gameRoomService.updateRoomActivity(data.gameId);
this.logger.debug(`λ°© ${data.gameId} ν™œλ™μ‹œκ°„ κ°±μ‹  μ™„λ£Œ / after ${Date.now() - before}ms`);
// this.logger.debug(`λ°© ${data.gameId} ν™œλ™μ‹œκ°„ κ°±μ‹  μ™„λ£Œ / after ${Date.now() - before}ms`);
}

return of(result);
Expand Down
3 changes: 3 additions & 0 deletions BE/src/game/redis/subscribers/player.subscriber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export class PlayerSubscriber extends RedisSubscriber {
private async handlePlayerChanges(changes: string, playerId: string, server: Namespace) {
const playerKey = REDIS_KEY.PLAYER(playerId);
const playerData = await this.redis.hgetall(playerKey);
const result = { changes, playerData };

switch (changes) {
case 'Join':
Expand All @@ -98,6 +99,8 @@ export class PlayerSubscriber extends RedisSubscriber {
await this.handlePlayerKicked(playerId, playerData, server);
break;
}

return result;
}

private async handlePlayerJoin(playerId: string, playerData: any, server: Namespace) {
Expand Down
Loading

0 comments on commit 7ddb652

Please sign in to comment.