-
Notifications
You must be signed in to change notification settings - Fork 0
๐ ๋์์ฑ ์ด์๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ LockManager ๋ง๋ค๊ธฐ
๊น์ํ edited this page Nov 23, 2024
·
1 revision
GameManager์์ Map์ ๋ง์ด ์ฌ์ฉํ๊ฒ ๋๋๋ฐ Map์ ๋์์ฑ ์ด์์์ ์์ ๋กญ์ง ์๋ค.
๊ทธ๋์ ๋์์ฑ ์ด์๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์๋ฐ์์๋ ConcurrentHashMap๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ์ ์๋๋ฐ ๋ ธ๋์์๋ ์๋ค. ๊ทธ๋์ ์ง์ Customํด์ ๋ง๋ค์ด์ผ ํ๊ณ ์ง์ ๋ง๋ค์ด ์ฌ์ฉํ๊ธฐ๋ก ํ๋ค.
npm install async-mutex
- ์ง์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค๋ ํ๋ก๋ํธ ํ๊ฒฝ์์ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์๊ณ ๋ง์ด ์ฌ์ฉํ๋ async-mutex๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ์๊ฐํ๋ค.
import { Mutex } from 'async-mutex';
export class LockManager<K> {
private locks = new Map<K, Mutex>();
private globalMutex = new Mutex();
private getLock(key: K): Mutex {
let lock = this.locks.get(key);
if (!lock) {
lock = new Mutex();
this.locks.set(key, lock);
}
return lock;
}
async withKeyLock<T>(key: K, callback: () => Promise<T>): Promise<T> {
const lock = this.getLock(key);
const release = await lock.acquire();
try {
return await callback();
} finally {
release();
}
}
async withGlobalLock<T>(callback: () => Promise<T>): Promise<T> {
const release = await this.globalMutex.acquire();
try {
return await callback();
} finally {
release();
}
}
releaseKey(key: K): void {
this.locks.delete(key);
}
async clear(): Promise<void> {
return await this.withGlobalLock(async () => {
this.locks.clear();
});
}
}
- async-mutex์์ ์ ๊ณตํ๋
Mutex
๋ฅผ ํตํด ๋์์ฑ ์ ์ด๋ฅผ ์งํํ๋ ค๊ณ ํ๋ค. -
lock.acquire
์ ํตํด ๋ฝ์ ํ๋ํ๊ณ , ํด๋น ๋น์ฆ๋์ค ๋ก์ง์ด ๋๋๋ฉดrelease
๋ฅผ ํตํด ๋ฝ์ ๋ฐ๋ฉํ๋ ํ์์ผ๋ก ์งํ๋๋ค. - ๊ฐ์ฅ ์ค์ํ
private method withKeyLock
async withKeyLock<T>(key: K, callback: () => Promise<T>): Promise<T> {
const lock = this.getLock(key);
const release = await lock.acquire();
try {
return await callback();
} finally {
release();
}
}
- ๊ฐ ๊ฒ์๋ฐฉ๋ง๋ค ๋ฝ์ด ์กด์ฌํ๋ฉฐ ํด๋น ๋ฝ์ ํตํด ๋์์ฑ ์ ์ด๋ฅผ ํ ์ ์๋ค.
- mutex.acquire๋ฅผ ํตํด ๋ฝ์ ํ๋ํ๊ณ ํด๋น callbackํจ์๋ฅผ ์คํํ ํ ๋ค์ ๋ฝ์ ๋ฐ๋ฉํ๋ ํ์์ ์งํํ๋ค.
return await this.lockManager.withKeyLock(gameRoom.roomId, async () => {
if (this.games.has(gameRoom.roomId)) {
return;
}
const gameInfo = new Map<string, PlayerInfo>();
players.forEach((role, client) => {
gameInfo.set(client.nickname, { role, status: USER_STATUS.ALIVE });
client.job = role;
if (role === MAFIA_ROLE.MAFIA) {
gameRoom.addMafia(client);
}
});
this.games.set(gameRoom.roomId, gameInfo);
});
-
lockManager.withKeyLock(gameRoom.roodId,
๋ฅผ ํตํด ํด๋น ๋ฐฉ์ ๋ํ ๋ฝ์ ํ๋ํฉ๋๋ค. ๊ทธ ํ ํด๋นํ๋ ๋น์ฆ๋์ค ๋ก์ง์ ์คํํ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋น ๋น์ฆ๋์ค ๋ก์ง ์คํ์ด ๋๋๋ฉด ๋ค์ ๋ฝ์ ๋ฐ๋ฉํ์ฌ ๋๋ ๋๋ค. - lockManager ํตํด ๋์์ฑ ์ด์์์ ์์ ๋กญ๊ฒ ๋์๊ณ ๋น์ฆ๋์ค ๋ก์ง์ ํ๋์ ํธ๋์ญ์ ์ผ๋ก ๋ฌถ์ด ์์์ฑ์ ๋ณด์ฅํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋น์ฆ๋์ค ๋ก์ง ์์ ์์์ ๊ฒ์ฆ ๋ก์ง์ ์ถ๊ฐํ์ฌ ๋์์ฑ ์ด์์์ ์์ ๋ก์์ก์ต๋๋ค.
web12-MafiaCamp
๐ฏํ๋ก์ ํธ ๊ท์น
๐ปํ๋ก์ ํธ ๊ธฐํ
๐๊ธฐ์ ์คํ
- ๐ป Next.js 15๋ฅผ ์ ํํ ์ด์
- ๐ NestJS๋ฅผ ์ ํํ ์ด์
- ๐ฅ๏ธ OpenVidu๋ฅผ ์ ํํ ์ด์
- ๐ TypeORM์ ์ ํํ ์ด์
- ๐ฌ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํด WebSocket์ ์ ํํ ์ด์
- ๐ WebRTC ๊ฐ๋ ์ ๋ฆฌ
- ๐พ WebRTC โ Nest.js์ React๋ก ํ๋ ๊ฐ๋จ ํ์์ฑํ ์์
- ๐ฅ๏ธ GitHub Actions๋ก CI/CD ๊ตฌ์ถ ๋ฐฉ๋ฒ
- ๐ฆ Docker์ ๊ฐ๋ ๊ณผ ์ฌ์ฉ ๋ฐฉ๋ฒ
- ๐ OAuth ๊ธฐ๋ณธ ์ธ์ฆ ๊ณผ์ ๊ณผ ์์
๐๊ทธ๋ฃน ํ๊ณ
๐๊ฐ๋ฐ ์ผ์ง
๐๋ฌธ์ ํด๊ฒฐ ๊ฒฝํ
- ์น์์ผ ๋ฐฉ ๊ด๋ฆฌ ๊ตฌ์กฐ ๊ฐ์
- Pub-Sub ํจํด์ ํตํ ์ค์๊ฐ ๋ฐฉ ๋ชฉ๋ก ์กฐํ ๊ธฐ๋ฅ ๊ฐ๋ฐ
- ์ ํ ์ํ ๊ธฐ๊ณ๋ฅผ ์ด์ฉํ ๊ฒ์ ์งํ ๋ชจ๋ธ๋ง
- ๐ ๋์์ฑ ์ด์๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ LockManager ๋ง๋ค๊ธฐ
- โฐ RxJS๋ก ์ค์๊ฐ ํ์ด๋จธ ๊ตฌ์ถํ๊ธฐ
- ๐ณNext.js์ Docker๋ฅผ ์ฌ์ฉํ ๋น๋ ์ต์ ํํ๊ธฐ
- ๐ข Redis๋ฅผ ํตํ ์ ์ ์จ๋ผ์ธ ์ํ ๊ด๋ฆฌ ์์คํ ๊ตฌํํ๊ธฐ
- openvidu ์๋ฌ ๋๋ฒ๊น ์ ์ํ Docker ๊ฐ๋ฐํ๊ฒฝ ์ค์
๐งํธ๋ฌ๋ธ ์ํ
- NestJS, mkcert CA ์ธ์ฆ์ ๋ฌธ์ ํด๊ฒฐ ๋ฐฉ๋ฒ
- openvidu ICE ํ๋ณด ๊ด๋ จ ์ค๋ฅ
- Enterํค ์ด๋ฒคํธ ์ค๋ณต ํธ์ถ ๋ฌธ์
- mutex lock ๋ฌธ์
- ํฌํ ๋์์ ์ง์ ์ค๋ฅ
- openvidu ์ธ์ ์ข ๋ฃ ๋ฉ์๋ ์ค๋ฅ
- ์บ์๋ก ์ธํ ๋ฏธ๋ค์จ์ด ๋ฏธํธ์ถ ๋ฐ ํ์ด์ง ์ ํ ์ค๋ฅ
- ๋คํฌ ๋ชจ๋์์ ํ ์คํธ๊ฐ ๋ณด์ด์ง ์๋ ๋ฌธ์
- ๊ฒ์ ๋ฐฉ์์ ์๋ก๊ณ ์นจ ๋๋ ๋ธ๋ผ์ฐ์ ํญ์ ๋ซ์ ๋์ ์์ธ ์ฒ๋ฆฌ