Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c83e59d
fix: api 서버와 websocket 분리를 위해 backend 서버 네임 변경
fru1tworld Jan 19, 2025
ea3f356
feature/split api websocket
fru1tworld Jan 19, 2025
3908f9f
fix: 분리 후 중복되는 코드 삭제
fru1tworld Jan 19, 2025
dc21f92
fix: 불필요한 파일 삭제 및 하위 subTree connection 연결되어있는 경우 저장되는 오류 해결
fru1tworld Jan 19, 2025
30e38dc
feat: load-balancer server 초기 세팅 nest 생성 redis container 설정 docker-co…
fru1tworld Jan 19, 2025
3a13cee
fix: 하위 subTree 삭제됐는데 note를 생성할 수 있는 로직 수정
fru1tworld Jan 20, 2025
59e882e
fix: 삭제된 트리에서 노트가 생성되던 문제 해결 및 Validation 계층추가로 결합도 낮추기
fru1tworld Jan 20, 2025
71817fd
feat: redis 환경 설정 및 연결 여부 확인
fru1tworld Jan 20, 2025
1b4ad5a
feat: load-balancer server && WebSocket Server 분산 작업 및 docker-compose 작업
fru1tworld Jan 21, 2025
a077710
fix: url 주소 변경됨에 따라 urlParse 로직 일부 수정
fru1tworld Jan 21, 2025
7111626
fix: room2 연결 안되던 문제 해결
fru1tworld Jan 21, 2025
d9d6952
fix: cron이 작동하지 않는 문제 해결
fru1tworld Jan 21, 2025
d6971ee
feat: lb-server 기능 개발
fru1tworld Jan 21, 2025
93ce46a
fix: lb-server key값 수정
fru1tworld Jan 21, 2025
84893fd
feat: load-balancer 로직 구현
fru1tworld Jan 22, 2025
55ed609
feat: lb 요청 로직 추가
parkblo Jan 22, 2025
c81d30e
fix: lb 요청 로직 비동기로 작동하도록 수정
parkblo Jan 22, 2025
ba88e13
fix: window 상에서 redis 포트 사용 불가로 docker-compose override 수정
fru1tworld Jan 22, 2025
75cd898
fix: 웹소켓 연결 시 순환참조 수정
parkblo Jan 22, 2025
d932e9e
fix: note 생성 요청에 spaceId 추가
parkblo Jan 22, 2025
0158fd8
fix: validation 검증 로직 수정
fru1tworld Jan 22, 2025
1cd6ec5
feat: 노트 에디터 로드밸런싱 로직 적용
parkblo Jan 22, 2025
6850239
Merge branch 'dev' into feature/load-balancer
fru1tworld Jan 22, 2025
ad2e696
Merge branch 'feature/load-balancer' of https://github.com/boostcampw…
parkblo Jan 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 123 additions & 7 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3.8"

services:
mysql:
image: mysql:8.0
Expand All @@ -23,15 +21,17 @@ services:
retries: 3
command: --bind-address=0.0.0.0

collaborative:
collaborative_room1:
build:
context: .
dockerfile: ./packages/collaborative/Dockerfile
container_name: collaborative
container_name: collaborative-room1
ports:
- "3001:3001"
- "9001:9001"
depends_on:
redis:
condition: service_healthy
mysql:
condition: service_healthy
mongodb:
Expand All @@ -47,7 +47,75 @@ services:
- MONGO_USER=honey
- MONGO_PASSWORD=1234
- MONGO_DB=dev_db
- LOG_LEVEL=info
- LOG_LEVEL=debug
- REDIS_HOST=redis-container
- REDIS_USERNAME=honey
- REDIS_PORT=6530
- REDIS_PASSWORD=1234
- SERVER_ID=room1
- WS_PORT=9001
networks:
- app-network

collaborative_room2:
build:
context: .
dockerfile: ./packages/collaborative/Dockerfile
container_name: collaborative-room2
ports:
- "3002:3002"
- "9002:9002"
depends_on:
redis:
condition: service_healthy
mysql:
condition: service_healthy
mongodb:
condition: service_healthy
environment:
- MYSQL_HOST=mysql-container
- MYSQL_PORT=3306
- MYSQL_DATABASE=dev_db
- MYSQL_PASSWORD=1234
- MYSQL_USER=honey
- NODE_ENV=dev
- MONGO_HOST=mongodb-container
- MONGO_USER=honey
- MONGO_PASSWORD=1234
- MONGO_DB=dev_db
- LOG_LEVEL=debug
- REDIS_HOST=redis-container
- REDIS_USERNAME=honey
- REDIS_PORT=6530
- REDIS_PASSWORD=1234
- SERVER_ID=room2
- WS_PORT=9002
networks:
- app-network
api:
build:
context: .
dockerfile: ./packages/api/Dockerfile
container_name: api
ports:
- "3000:3000"
depends_on:
mysql:
condition: service_healthy
mongodb:
condition: service_healthy
environment:
- MYSQL_HOST=mysql-container
- MYSQL_PORT=3306
- MYSQL_DATABASE=dev_db
- MYSQL_PASSWORD=1234
- MYSQL_USER=honey
- NODE_ENV=dev
- MONGO_HOST=mongodb-container
- MONGO_USER=honey
- MONGO_PASSWORD=1234
- MONGO_DB=dev_db
- LOG_LEVEL=debug
networks:
- app-network
api:
Expand Down Expand Up @@ -77,20 +145,44 @@ services:
networks:
- app-network

frontend:
load-balancer:
build:
context: .
dockerfile: ./packages/loadbalancer/Dockerfile
container_name: lb-container
ports:
- "4242:4242"
depends_on:
redis:
condition: service_healthy
networks:
- app-network
environment:
- LOG_LEVEL=debug
- REDIS_HOST=redis-container
- REDIS_USERNAME=honey
- REDIS_PORT=6530
- REDIS_PASSWORD=1234

frotend:
build:
context: .
dockerfile: ./packages/frontend/Dockerfile
container_name: frontend
ports:
- "80:80"
depends_on:
collaborative:
load-balancer:
condition: service_started
collaborative_room1:
condition: service_started
collaborative_room2:
condition: service_started
api:
condition: service_started
networks:
- app-network

mongodb:
image: mongo:latest
container_name: mongodb-container
Expand Down Expand Up @@ -122,6 +214,30 @@ services:
timeout: 5s
retries: 10

redis:
image: redis:latest
container_name: redis-container
ports:
- "6530:6530"
networks:
- app-network
environment:
REDIS_DISABLE_COMMANDS: "FLUSHDB FLUSHALL"
command:
[
"redis-server",
"--port",
"6530",
"--requirepass",
"1234",
"--bind",
"0.0.0.0",
]
healthcheck:
test: ["CMD", "redis-cli", "-p", "6530", "ping"]
interval: 10s
timeout: 5s
retries: 3
volumes:
mysql_data:
mongo_data:
Expand Down
54 changes: 52 additions & 2 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,64 @@ services:
curl -f telnet://${MYSQL_HOST}:${MYSQL_PORT} || exit 1;
curl -f telnet://${MONGO_HOST}:27017 || exit 1;
"
networks:
- app-network
healthcheck:
test: ["CMD", "/bin/sh", "-c", "exit 0"]
interval: 10s
timeout: 5s
retries: 3

loadbalancer:
container_name: loadbalancer
ports:
- "4242:4242"
build:
target: production
environment:
# 배포 환경 세팅
- NODE_ENV=production

# Mongo 세팅
- LOG_LEVEL=${LOG_LEVEL}

# Redis 세팅
- REDIS_USERNAME=${REDIS_USERNAME}
- REDIS_PASSWORD=${REDIS_PASSWORD}
- REDIS_HOST=${REDIS_HOST}
- REDIS_PORT=${REDIS_PORT}
networks:
- app-network

collaborative:
container_name: collaborative
ports:
- "9001:9001"
build:
target: production
environment:
# 배포 환경 세팅
- NODE_ENV=production

# MySQL 세팅
- MYSQL_HOST=${MYSQL_HOST}
- MYSQL_PORT=${MYSQL_PORT}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}

# Mongo 세팅
- MONGO_HOST=${MONGO_HOST}
- MONGO_USER=${MONGO_USER}
- MONGO_PASSWORD=${MONGO_PASSWORD}
- MONGO_DB=${MONGO_DB}
- LOG_LEVEL=${LOG_LEVEL}

# Redis 세팅
- REDIS_USERNAME=${REDIS_USERNAME}
- REDIS_PASSWORD=${REDIS_PASSWORD}
- REDIS_HOST=${REDIS_HOST}
- REDIS_PORT=${REDIS_PORT}
networks:
- app-network
api:
container_name: api
ports:
Expand Down
21 changes: 0 additions & 21 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,3 @@
services:
api:
build:
context: .
dockerfile: ./packages/api/Dockerfile
restart: unless-stopped
environment:
- NODE_ENV=development
networks:
- app-network

frontend:
build:
context: .
dockerfile: ./packages/frontend/Dockerfile
restart: unless-stopped
environment:
- NODE_ENV=development
networks:
- app-network

networks:
app-network:
driver: bridge
2 changes: 1 addition & 1 deletion packages/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ MONGO_USER=your-mongo-username
MONGO_PASSWORD=your-mongo-password
MONGO_DB=your-mongo-database

# Redis 설정 (추가된 telnet 기반 체크를 위해 필요)
# Redis 설정
REDIS_HOST=your-redis-host
REDIS_PORT=6379

Expand Down
4 changes: 3 additions & 1 deletion packages/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getTypeOrmConfig } from './common/config/typeorm.config';
import { NoteModule } from './note/note.module';
import { SpaceModule } from './space/space.module';
import { TestModule } from './test/test.module';
import { ValidationModule } from './common/validation/validation.module';

@Module({
imports: [
Expand All @@ -22,8 +23,9 @@ import { TestModule } from './test/test.module';
inject: [ConfigService],
useFactory: getTypeOrmConfig,
}),
SpaceModule,
ValidationModule,
NoteModule,
SpaceModule,
TestModule,
],
})
Expand Down
17 changes: 17 additions & 0 deletions packages/api/src/common/validation/validation.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { NoteDocument, NoteSchema } from 'src/note/note.schema';
import { SpaceDocument, SpaceSchema } from 'src/space/space.schema';
import { ValidationService } from './validation.service';

@Module({
imports: [
MongooseModule.forFeature([
{ name: NoteDocument.name, schema: NoteSchema },
{ name: SpaceDocument.name, schema: SpaceSchema },
]),
],
providers: [ValidationService],
exports: [ValidationService],
})
export class ValidationModule {}
18 changes: 18 additions & 0 deletions packages/api/src/common/validation/validation.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ValidationService } from './validation.service';

describe('ValidationService', () => {
let service: ValidationService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ValidationService],
}).compile();

service = module.get<ValidationService>(ValidationService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
58 changes: 58 additions & 0 deletions packages/api/src/common/validation/validation.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { SpaceDocument } from 'src/space/space.schema';
import { MAX_SPACES } from '../constants/space.constants';
import { ERROR_MESSAGES } from '../constants/error.message.constants';
import { NoteDocument } from 'src/note/note.schema';

@Injectable()
export class ValidationService {
private readonly logger = new Logger(ValidationService.name);
constructor(
@InjectModel(NoteDocument.name)
private readonly noteModel: Model<SpaceDocument>,
@InjectModel(SpaceDocument.name)
private readonly spaceModel: Model<SpaceDocument>,
) {}
async validateNoteExsts(urlPath: string) {
const note = await this.noteModel.findOne({ urlPath });

if (!note) {
throw new Error(ERROR_MESSAGES.SPACE.NOT_FOUND);
}

return note;
}
async validateSpaceLimit(userId: string) {
const spaceCount = await this.spaceModel.countDocuments({ userId });

if (spaceCount >= MAX_SPACES) {
throw new Error(ERROR_MESSAGES.SPACE.LIMIT_EXCEEDED);
}
}

async validateParentNodeExists(parentContextNodeId: string | null) {
if (parentContextNodeId) {
const space = await this.spaceModel.findOne({
id: parentContextNodeId,
});

if (!space) {
throw new Error(ERROR_MESSAGES.SPACE.PARENT_NOT_FOUND);
}
}
}

async validateSpaceExists(id: string) {
const space = await this.spaceModel.findOne({ id });

this.logger.debug(`validation result : ${space}`);

if (!space) {
throw new Error(ERROR_MESSAGES.SPACE.NOT_FOUND);
}

return space;
}
}
Loading