Skip to content

Conversation

@blu3fishez
Copy link
Collaborator

관련 이슈 번호

  • 작성자: 김찬우
  • 작성 날짜: 2024.11.25

✅ 체크리스트

  • 코드가 정상적으로 작동하는지 확인했습니다.
  • 주요 변경사항에 대한 설명을 작성했습니다.
  • 코드 스타일 가이드에 따라 코드를 작성했습니다.

🧩 작업 내용

  • [Refactor] 스터디 세션 기능 리워크 #205 에 언급된 다중 WAS 내 잘못받아오는 세션 ID 버그 수정
  • 스터디 세션 서비스 로직 분리
  • 방 삭제 로직 오류 수정
  • redis-om 사용에 따른 docker-compose.yml 업데이트

📝 작업 상세 내역

스터디 세션 서비스 로직 분리

  • 방에 참가, 생성, 퇴장 하는 로직을 전부 분리
  • 함수 하나만을 위한 서비스를 만드는게 과연 좋을지 고민
    • 개인적인 취향으로, 한 파일에 코드가 너무 길어지면 집중하지 못하는 경향이 있어서 분리해봤습니다.
  • 방에 참가하는 로직도 하나의 함수로 추상화했고,
  • 다만, 방에 참가하는 로직이 방을 생성할 때 재사용할 수 있도록 만들었는데, 이때 boolean 인자로 플래그를 설정
  • 이 방법은 좋지 않고, 후에 Exception 이나 Emit 자체를 게이트웨이에서 하도록 수정할 예정인데 이때 고칠 예정
public async joinRoom(dto: JoinRoomInternalDto, isCreate: boolean = false) {
    const { roomId, socketId, nickname } = dto;

    const room = await this.roomRepository.getRoom(roomId);
    const socket = this.socketService.getSocket(socketId);

    if (!socket) throw new Error("Invalid Socket");

    if (room.roomId === null) throw new Error("Redis: RoomEntity Entity type error");

    if (this.isFullRoom(room)) return socket.emit(EMIT_EVENT.FULL, {});

    socket.join(roomId);
    await this.socketRepository.joinRoom(socket.id, roomId);
    room.connectionList.push({
        socketId,
        createAt: Date.now(),
        nickname,
    });

    await this.roomRepository.setRoom(room);

    // TODO: 성공 / 실패 여부를 전송하는데 있어서 결과에 따라 다르게 해야하는데.. 어떻게 관심 분리를 할까?
    if (!isCreate) this.socketService.emitToRoom(roomId, EMIT_EVENT.JOIN, room);
}

다중 WAS 내 잘못받아오는 세션 ID 버그 수정

  • redis에 room_id 라는 키에 숫자를 넣어서 가져오도록 수정
  • 동시성을 완벽하게 고려하지 않은 것 같아서 살짝 고민
// TODO: 동시성 고려해봐야하지 않을까?
private async generateRoomId() {
    const client = this.socketService.getRedisClient();

    const idString = await client.get(RoomCreateService.ROOM_ID_CREATE_KEY);

    let id: number;
    if (idString && !isNaN(parseInt(idString))) {
        id = await client.incr(RoomCreateService.ROOM_ID_CREATE_KEY);
    } else {
        id = parseInt(await client.set(RoomCreateService.ROOM_ID_CREATE_KEY, "1"));
    }

    return createHash("sha256")
        .update(id + process.env.SESSION_HASH)
        .digest("hex");
}

방 삭제 로직 오류 수정

마지막 사용자가 방 퇴장 시, 방 삭제 시 socketId 를 넣고 있었어서 방 삭제가 제대로 안되고 있었습니다.

아래처럼 코드를 수정했습니다.

private async processRoomLeave(socketId: string, roomId: string) {
        const room = await this.roomRepository.getRoom(roomId);
        if (!room) return;

        room.connectionList = room.connectionList.filter(
            (connection) => connection.socketId !== socketId
        );

        if (!room.connectionList.length) return this.deleteRoom(room.roomId);

        await this.roomRepository.setRoom(room);

        if (room.host === socketId) return this.handleHostChange(socketId, room);

        this.socketService.emitToRoom(room.roomId, EMIT_EVENT.QUIT, { socketId });
    }

redis-om 사용에 따른 docker-compose.yml 업데이트

데브서버를 위한 도커 컴포즈 파일을 업데이트 했습니다.

docker desktop에서 날려버리고 새롭게 설치하세요! 그러면 데브서버 이제 다시 사용하실 수 있을거에요.

version: '3'

services:
  mysql:
    image: mysql:latest
    container_name: mysql
    ports:
      - '3306:3306'
    environment:
      MYSQL_ROOT_PASSWORD: dbcadmium
      MYSQL_DATABASE: preview
      TZ: Asia/Seoul
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./mysql-data:/var/lib/mysql

  redis:
    image: redis/redis-stack:latest
    ports:
      - "6379:6379"  # Redis port
      - "8001:8001"  # RedisInsight port
    volumes:
      - redis_data:/data
    restart: unless-stopped

📌 테스트 및 검증 결과

  • Postman 으로 테스트 하였고, 3001 번 WAS 에서 create, 3000번 WAS 에서 create 한 결과 입니다.
  • 방이 2개 있어야하는데 실제로 2개가 있는 모습
image image

💬 다음 작업 또는 논의 사항

  • 내일 또는 이후에 진행할 예정인 작업
  • 추가적인 개선 사항이나 논의가 필요한 내용

🐥 리뷰 받고 싶은 포인트

  • 의문점 드는 곳 아무데나 편하게 말씀주세요.

- 분리하면서 아예 공식 모듈로 승격
- 스터디 세션, 시그널링 서버 핸들러보다 더 상위의 기초적인 서버 설정과 서버 인스턴스를 맡는 전역 게이트웨이
- 길어지는 로직을 아예 파일로 분리했음
- 현재로써는 로직의 수가 많지 않기에 가독성 측면에서 분리가 좋다고 판단했습니다.
- `backend/src/room/services/room-create.service.ts`

해당 파일에서 새롭게 `redisClient` 를 받아와서 새로운 roomId 값을 생성하도록 개선
- 이제 redis-stack을 사용
@blu3fishez blu3fishez added 🐛 Bug Fix 해충 제거 🎁 Refactoring 리팩토링 labels Nov 25, 2024
@blu3fishez blu3fishez requested a review from twalla26 November 25, 2024 12:32
@blu3fishez blu3fishez self-assigned this Nov 25, 2024
Copy link
Collaborator

@twalla26 twalla26 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

import { WebsocketRepository } from "@/websocket/websocket.repository";

@WebSocketGateway()
export class WebsocketGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 websocket이라는 모듈을 아예 만들고 여기서 관리하고 계시군요!
좋은 방법인 것 같습니다! 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! 근데 데코레이터랑 이름이 비슷해서 조금 헷갈리지 않을까 걱정이에요 ㅋㅋ

@twalla26 twalla26 merged commit ef38c09 into dev-be Nov 25, 2024
@blu3fishez blu3fishez deleted the fix/generate-session-id branch November 25, 2024 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 Bug Fix 해충 제거 🎁 Refactoring 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants