개요

현재는 클라이언트와 서버의 연동을 확인하기 위해 작업한 CRDT 문서들을 서버에 인스턴스로 저장하고 있다

이제 우리는 워크스페이스와 페이지들을 MongoDB에 직접 저장해야 한다

데이터 저장 형식

Workspace 데이터

CRDT가 적용되는 데이터 구조

DB 저장에 있어 고려해야 할 점

DB를 언제 어떻게 업데이트해야 할까?

구현해보기

인메모리 DB 가비지 컬렉터

초기 구현

@Injectable()
export class workSpaceService implements OnModuleInit {
  private workspaces: Map<string, CRDTWorkSpace>;
  private server: Server;
  constructor(@InjectModel(Workspace.name) private workspaceModel: Model<WorkspaceDocument>) {}

  // Socket.IO 서버 인스턴스 설정
  setServer(server: Server) {
    this.server = server;
  }

  async onModuleInit() {
    this.workspaces = new Map();
    // 게스트 워크스페이스 초기화
    const guestWorkspace = new CRDTWorkSpace("guest", []);
    this.workspaces.set("guest", guestWorkspace);

    // 주기적으로 인메모리 DB 정리 작업 실행
    setInterval(
      () => {
        this.cleanupWorkspaces();
      },
      process.env.NODE_ENV === "production" ? 1 * 60 * 60 * 1000 : 30 * 1000,
    );
  }

	private async cleanupWorkspaces() {
	  try {
	    for (const [roomId, workspace] of this.workspaces.entries()) {
	      // guest workspace는 제외
	      if (roomId === "guest") continue;
	
	      // room의 연결된 클라이언트 수 확인
	      const room = this.server.sockets.adapter.rooms.get(roomId);
	      const clientCount = room ? room.size : 0;
	
	      if (clientCount === 0) {
	        // DB에 workspace 상태 저장
	        await this.updateWorkspaceInDB(roomId, workspace);
	
	        // Map에서 제거
	        this.workspaces.delete(roomId);
	
	        console.log(`Workspace ${roomId} has been saved to DB and removed from memory`);
	      }
	    }
	
	    console.log("Workspace cleanup completed, current workspaces: ", this.workspaces.keys());
	  } catch (error) {
	    console.error("Error during workspace cleanup: ", error);
	  }
	}