Migration
그동안 미루고 미루었던 서버 리팩토링을 진행하기로 했다. 그 과정을 기록한다.
이슈
현재 MailBadara 서버의 문제는 바로, 구독자들에게 뉴스레터를 전달할 때 순간적으로 메모리 사용량이 튀어서 Koyeb(호스팅 플랫폼)의 무료 플랜 메모리 오버로 프로세스가 강제로 종료된다는 것이다. Koyeb에선 프로세스가 죽을 때 즉시 재실행시켜주기 때문에 메일 전송 로직은 완료되기는 한다. 끝날 때까지 몇 번 씩 프로세스가 죽을 뿐..
서비스가 작동"은" 해서 로직을 더 이상 수정하지 않고 이 상태로 배포하고 말았는데, 한 달이 지난 지금. 더 이상 미룰 수 없다 생각했고 진행 중이다.
슈팅
이를 해결할 방법은 2가지다.
- node에서 bun으로 migration
- node보다 훨씬 빠르고 효율적인 bun이라면 메모리로 괜찮지 않을까 생각했다.
- 그러나 이제 막 오픈된 런타임이기 때문에 섣불리 도입하기에는 부담되는 것이 사실이다.
- 또한 bun으로 바꾼다 해도 효율이 드라마틱하게 바뀔지도 의문이다.
- 메일 전송 로직 개선
- 현재 MailBadara는 매일 오전 11시와 오후 6시에 모든 학과를 대상으로 메일을 전송한다.
- 주로 전송할 메일이 많은 경우, 전송을 마치고 프로세스가 죽는 경우가 잦기 때문에 메일 전송 로직을 개선해야 한다.
- 한 순간에 다량의 메일을 모든 학과를 대상으로 전송하는 것이 아니라, 특정 시간에는 특정 학과에만 메일을 전송하도록 한다면 한 순간의 서버 부담을 줄일 수 있을 것이다.
결국 2번 솔루션을 선택했다. 확실치 않은 Bun으로 당장 바꿔서 성능 테스트까지 진행하기엔 일이 너무 커질 것 같았다.
서버 리팩토링(1)
MVC 패턴 적용
서버 로직을 개선하기 전에, 먼저 난잡한 프로젝트 구조를 개선했다. 처음부터 디자인 패턴 따윈 넣지 않고 개발했기 때문에 라우터는 app.js에 몰아넣고 util 함수는 필요한대로 js로 생성되었고.. 여러모로 엉성했다.
MVC 패턴을 적용해서 프로젝트 구조를 먼저 리팩토링했다. 크게 어려운 건 아니었으니까 자세한 과정은 생략한다.
TypeScript
JavaScript에서 TypeScript로 migration했다. 처음엔 빠르게 개발하려고 JS를 사용했는데 개발하면서 여러 난관에 부딪혔다. 함수가 깊어지면서 주고받는 argument도 복잡해졌고 객체 구조가 감당하지 못할 정도로 커졌다. 객체 구조를 까먹기도 해서 번번이 Object 에러가 발생했고, "다음엔 TS로 하자"고 생각했다. 그래서 이번 기회에 리팩토링하면서 ts migration도 진행하기로 했다.
이것도 크게 어려운 것은 없었고 typescript, @types/axios, @types/node, @types/cron 등 ts 라이브러리 설치하고 package.json도 수정하고 tsconfig.json도 작성하면 세팅은 끝이다. 나머지는 js 파일을 전부 ts로 변경하면서 type을 적용했다.
- package.json
{
"name": "server",
"version": "3.0.0",
"main": "app.js",
"license": "MIT",
"type": "module",
"dependencies": {
"axios": "^1.6.2",
"cheerio": "^1.0.0-rc.12",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"ioredis": "^5.3.2",
"mongoose": "^7.5.3",
"node-cron": "^3.0.2",
"nodemailer": "^6.9.5",
"xml2js": "^0.6.2"
},
"scripts": {
"build": "tsc",
"server": "node ./dist/app.js",
"server:dev": "nodemon --exec ts-node ./src/app.ts"
},
"devDependencies": {
"@types/cors": "^2.8.16",
"@types/express": "^4.17.21",
"@types/node": "^20.9.2",
"@types/node-cron": "^3.0.11",
"@types/nodemailer": "^6.4.11",
"@types/xml2js": "^0.4.14",
"nodemon": "^3.0.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
}
}
- tsconfig.json
{
"compilerOptions": {
/* Language and Environment */
"target": "es6",
/* Modules */
"module": "commonjs",
"rootDir": "./src",
"moduleResolution": "node",
"outDir": "./dist",
/* Interop Constraints */
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
/* Type Checking */
"strict": false,
"skipLibCheck": true
}
}
번들링?
nodejs 서버 번들링을 시도했다. React 프로젝트는 빌드 시, dist 폴더에 index-무작위값.js
파일 하나로 번들링되었기에 Node.js 서버도 간단하게 될 줄 알았다. webpack은 느리고 무겁다는 인식이 있었고, React처럼 Vite로 번들링을 시도해봤다.
dist 폴더에 app-무작위값.js
하나가 생성되었고 성공한 줄 알았는데.. 실행이 안 된다.
Error loading module: TypeError: Cannot read properties of undefined (reading 'from')
이거저거 설정을 바꿔보다가 도저히 안 되서 찾아보니, 애초에 서버는 번들링을 할 이유가 빈약하다고 하더라..
- 클라이언트처럼 번들 사이즈를 줄이는 것의 이점이 그다지 크지 않다.
- 오히려 번들링 과정에서 외부 라이브러리가 의도치 않은 오류를 발생시키는 경우가 생길 수도 있다.
결국 납득하고 vite를 적용하기 전으로 롤백시킨 후 1차 리팩토링을 마무리지었다. 내일부터는 본격적인 서버 로직을 개선할 차례다.
'프로젝트 > MailBadara' 카테고리의 다른 글
[토이프로젝트] MailBadara - (9) 디자인 리뉴얼 (1) | 2024.01.11 |
---|---|
[토이프로젝트] MailBadara - (8) 2차 서버 리팩토링 (1) | 2023.11.23 |
[토이프로젝트] MailBadara - (6) 서버 최적화 생각 중 (0) | 2023.10.16 |
[토이프로젝트] MailBadara - (5) 트러블슈팅 (0) | 2023.10.13 |
[토이프로젝트] MailBadara - (4) 프론트 최적화 (0) | 2023.10.13 |