원래 뮤텍스가 멀티스레드 환경에서 레이스 컨디션을 방지하기 위하여 사용하는 것으로 알고 있지만, 싱글 스레드 내에서도 공유 자원에 대한 경쟁은 있었다...
물론 lockfile, flag 등의 방법은 많겠지만 이미 잘 만들어진 프레임워크가 있기 때문에 간단하게 가져다 쓰기로 했다.
현재 헬스체크 서버에서는 Map으로 서버 리스트와 포트를 관리하고 있었으나 갑작스럽게 서버가 끊기는 경우 nginx 헬퍼서버에서 끌어다 쓰기보단 자체 파일로 유지하여 복구하는 방식을 만들고 싶었다.
그래서 fs.readFileSync
와 fs.writeFileSync
를 활용하여 Map에 최초 상태 저장할 때 json에 다른 정보는 빼고 포트번호만 저장하고 서버를 시작했을 때 가져올 수 있게 유틸을 하나 만들었다.
그냥 생각나는대로 정리하지 않고 작성한 코드다 보니 검증이 부족한 점과 너저분한 코드일 수 있지만 기록을 남기고.. 추후에 리팩토링을 진행하겠다.
import fs from 'fs';
import { Mutex } from 'async-mutex';
const path = 'json/svr.json';
const lock = new Mutex();
export const getSvrJson = async () => {
try {
// json 없으면 null 반환
if (!fs.existsSync(path)) return null;
const svrData = fs.readFileSync(path, 'utf-8');
const json = JSON.parse(svrData);
return json;
} catch (err) {
console.error(err.message);
}
};
export const loadSvrFromJson = async (map) => {
try {
await lock.acquire();
if (typeof map !== 'object') throw new Error('인자 설정 잘못한듯? - loadSvrJson');
const svrData = await getSvrJson();
if (!svrData) return null;
for (const [svrIp, svrPort] of Object.entries(svrData)) {
map.set(svrIp, svrPort);
}
} catch (err) {
console.error(err.message);
} finally {
lock.release();
}
};
export const writeSvrToJson = async (svrIp, svrPort) => {
try {
await lock.acquire();
let svrData = await getSvrJson();
if (!svrData) svrData = {};
if (svrData[svrIp]) throw new Error('서버 아이피 중복');
svrData[svrIp] = { nginxPort: svrPort };
fs.writeFileSync(path, JSON.stringify(svrData));
} catch (err) {
console.error(err.message);
} finally {
lock.release();
}
};
export const deleteSvrFromJson = async (svrIp) => {
try {
await lock.acquire();
let svrData = await getSvrJson();
if (!svrData || !svrData[svrIp]) throw new Error('삭제할 아이피가 목록에 없음');
delete svrData[svrIp];
fs.writeFileSync(path, JSON.stringify(svrData));
} catch (err) {
console.error(err.message);
} finally {
lock.release();
}
};