Skip to content

Commit 49e4fe8

Browse files
authored
Merge pull request #101 from boostcampwm-2024/develop
v1.3.0 배포
2 parents 00f78e6 + d8edc8f commit 49e4fe8

File tree

165 files changed

+2618
-578
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

165 files changed

+2618
-578
lines changed

.github/workflows/cd-pipeline.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ jobs:
5454
docker build -f ./services/backend/Dockerfile.prod -t growth123/octodocs-backend . &
5555
docker build -f ./services/nginx/Dockerfile.prod -t growth123/octodocs-nginx . &
5656
docker build -f ./services/websocket/Dockerfile.prod -t growth123/octodocs-websocket . &
57+
docker build -f ./services/scheduler/Dockerfile.prod -t growth123/octodocs-scheduler . &
5758
wait
5859
5960
# Docker 이미지 푸시
@@ -63,6 +64,7 @@ jobs:
6364
docker push growth123/octodocs-backend &
6465
docker push growth123/octodocs-nginx &
6566
docker push growth123/octodocs-websocket &
67+
docker push growth123/octodocs-scheduler &
6668
wait
6769
6870
deploy:

apps/backend/nest-cli.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
"sourceRoot": "src",
55
"compilerOptions": {
66
"deleteOutDir": true
7-
}
8-
}
7+
},
8+
"entryFile": "./apps/backend/src/main.js"
9+
}

apps/backend/package.json

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@
2121
},
2222
"dependencies": {
2323
"@aws-sdk/client-s3": "^3.693.0",
24-
"@huggingface/transformers": "^3.3.3",
25-
"@langchain/community": "^0.3.28",
26-
"@langchain/core": "^0.3.37",
27-
"@langchain/openai": "^0.4.2",
24+
"@langchain/community": "^0.3.30",
25+
"@langchain/core": "^0.3.40",
26+
"@langchain/openai": "^0.4.4",
2827
"@langchain/textsplitters": "^0.1.0",
2928
"@nestjs/common": "^10.0.0",
3029
"@nestjs/config": "^3.3.0",
@@ -36,6 +35,7 @@
3635
"@nestjs/platform-socket.io": "^10.4.8",
3736
"@nestjs/platform-ws": "^10.4.7",
3837
"@nestjs/schedule": "^4.1.1",
38+
"@nestjs/schematics": "^11.0.0",
3939
"@nestjs/serve-static": "^4.0.2",
4040
"@nestjs/swagger": "^8.0.5",
4141
"@nestjs/typeorm": "^10.0.2",
@@ -107,6 +107,22 @@
107107
"**/*.(t|j)s"
108108
],
109109
"coverageDirectory": "../coverage",
110-
"testEnvironment": "node"
110+
"testEnvironment": "node",
111+
"moduleDirectories": [
112+
"node_modules",
113+
"src"
114+
],
115+
"moduleNameMapper": {
116+
"@root/(.*)$": "<rootDir>/../../$1",
117+
"@app/redis/(.*)$": "<rootDir>/../../../libs/redis/src/$1",
118+
"@app/page/(.*)$": "<rootDir>/../../../libs/page/src/$1",
119+
"@app/node/(.*)$": "<rootDir>/../../../libs/node/src/$1",
120+
"@app/edge/(.*)$": "<rootDir>/../../../libs/edge/src/$1",
121+
"@app/workspace/(.*)$": "<rootDir>/../../../libs/workspace/src/$1",
122+
"@app/user/(.*)$": "<rootDir>/../../../libs/user/src/$1",
123+
"@app/role/(.*)$": "<rootDir>/../../../libs/role/src/$1",
124+
"@app/token/(.*)$": "<rootDir>/../../../libs/token/src/$1",
125+
"@app/exception/(.*)$": "<rootDir>/../../../libs/exception/$1"
126+
}
111127
}
112128
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { ChatAbortController } from './chat-abort.controller';
3+
import { ChatAbortService } from './chat-abort.service';
4+
import { AbortResponseMessage } from './chat-abort.controller';
5+
6+
describe('AbortController', () => {
7+
let abortController: ChatAbortController;
8+
let abortService: ChatAbortService;
9+
10+
beforeEach(async () => {
11+
const module: TestingModule = await Test.createTestingModule({
12+
controllers: [ChatAbortController],
13+
providers: [ChatAbortService],
14+
}).compile();
15+
16+
abortController = module.get<ChatAbortController>(ChatAbortController);
17+
abortService = module.get<ChatAbortService>(ChatAbortService);
18+
});
19+
20+
it('should be defined', () => {
21+
expect(abortController).toBeDefined();
22+
});
23+
24+
it('요청 중단 시 성공 테스트', () => {
25+
const requestId = 'test-request';
26+
// AbortService의 abortRequest가 true를 반환하도록 spy 설정
27+
jest.spyOn(abortService, 'abortRequest').mockReturnValue(true);
28+
29+
const result = abortController.abort(requestId);
30+
31+
expect(result).toEqual({
32+
success: true,
33+
message: AbortResponseMessage.ABORT_SUCCESS,
34+
});
35+
});
36+
37+
it('존재하지 않는 requestId로 요청 중단 시 실패 테스트', () => {
38+
const requestId = 'non-existent-request';
39+
// AbortService의 abortRequest가 false를 반환하도록 spy 설정
40+
jest.spyOn(abortService, 'abortRequest').mockReturnValue(false);
41+
42+
const result = abortController.abort(requestId);
43+
44+
expect(result).toEqual({
45+
success: false,
46+
message: AbortResponseMessage.ABORT_FAIL,
47+
});
48+
});
49+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Controller, Get, Param } from '@nestjs/common';
2+
import { ChatAbortService } from './chat-abort.service';
3+
4+
export enum AbortResponseMessage {
5+
ABORT_SUCCESS = '웹 요청 중단에 성공했습니다.',
6+
ABORT_FAIL = '웹 요청 중단에 실패했습니다.',
7+
}
8+
9+
@Controller('abort')
10+
export class ChatAbortController {
11+
constructor(private readonly abortService: ChatAbortService) {}
12+
13+
@Get('/:requestId')
14+
abort(@Param('requestId') requestId: string) {
15+
const success = this.abortService.abortRequest(requestId);
16+
return {
17+
success,
18+
message: success
19+
? AbortResponseMessage.ABORT_SUCCESS
20+
: AbortResponseMessage.ABORT_FAIL,
21+
};
22+
}
23+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Module } from '@nestjs/common';
2+
import { ChatAbortService } from './chat-abort.service';
3+
import { ChatAbortController } from './chat-abort.controller';
4+
5+
@Module({
6+
providers: [ChatAbortService],
7+
controllers: [ChatAbortController],
8+
exports: [ChatAbortService],
9+
})
10+
export class ChatAbortModule {}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { ChatAbortService } from './chat-abort.service';
3+
4+
describe('AbortService', () => {
5+
let abortService: ChatAbortService;
6+
7+
beforeEach(async () => {
8+
const module: TestingModule = await Test.createTestingModule({
9+
providers: [ChatAbortService],
10+
}).compile();
11+
12+
abortService = module.get<ChatAbortService>(ChatAbortService);
13+
});
14+
15+
it('AbortController를 생성 성공 테스트', () => {
16+
const requestId = 'test';
17+
18+
const controller = abortService.createController(requestId);
19+
20+
expect(controller).toBeDefined(); // AbortController가 생성되었는지 확인
21+
expect(controller.signal.aborted).toBe(false); // 아직 중단되지 않았는지 확인
22+
23+
const storedController = abortService.getController(requestId);
24+
expect(storedController).toBe(controller); // 저장된 컨트롤러가 동일한지 확인
25+
});
26+
27+
it('요청을 중단하고 캐시 삭제 성공 테스트', () => {
28+
const requestId = 'test';
29+
const controller = abortService.createController(requestId);
30+
31+
expect(controller.signal.aborted).toBe(false); // 초기 상태 확인
32+
33+
const success = abortService.abortRequest(requestId);
34+
35+
expect(success).toBe(true); // 요청 중단이 성공했는지 확인
36+
expect(controller.signal.aborted).toBe(true); // AbortController가 중단되었는지 확인
37+
expect(abortService.getController(requestId)).toBeUndefined(); // 캐시에서 삭제되었는지 확인
38+
});
39+
40+
it('존재하지 않는 requestId로 요청 중단 실패 테스트', () => {
41+
const success = abortService.abortRequest('non-existent-id');
42+
expect(success).toBe(false); // 존재하지 않는 요청은 중단할 수 없어야 함
43+
});
44+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Injectable } from '@nestjs/common';
2+
3+
@Injectable()
4+
export class ChatAbortService {
5+
private controllers: Map<
6+
string,
7+
{ controller: AbortController; timestamp: number }
8+
> = new Map();
9+
private ttl: number = 60000;
10+
11+
constructor() {
12+
setInterval(() => this.cleanup(), 10000);
13+
}
14+
15+
createController(requestId: string): AbortController {
16+
const controller = new AbortController();
17+
const timestamp = Date.now();
18+
this.controllers.set(requestId, { controller, timestamp });
19+
return controller;
20+
}
21+
22+
getController(requestId: string): AbortController | undefined {
23+
return this.controllers.get(requestId)?.controller;
24+
}
25+
26+
abortRequest(requestId: string): boolean {
27+
const entry = this.controllers.get(requestId);
28+
if (entry) {
29+
if (entry.controller.signal.aborted) {
30+
// 이미 취소된 경우, 추가 작업을 하지 않음
31+
console.log(`Request with ID ${requestId} is already aborted.`);
32+
return false;
33+
}
34+
35+
entry.controller.abort();
36+
this.controllers.delete(requestId);
37+
return true;
38+
}
39+
return false;
40+
}
41+
42+
private cleanup(): void {
43+
const now = Date.now();
44+
this.controllers.forEach((entry, requestId) => {
45+
if (now - entry.timestamp > this.ttl) {
46+
this.controllers.delete(requestId);
47+
}
48+
});
49+
}
50+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { IsString } from 'class-validator';
3+
4+
export class AbortFailResponseDto {
5+
@ApiProperty({
6+
example: '웹 요청 중단에 실패했습니다.',
7+
description: '웹 요청 결과 메시지',
8+
})
9+
@IsString()
10+
message: string;
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { IsString, IsBoolean } from 'class-validator';
3+
4+
export class AbortSuccessResponseDto {
5+
@ApiProperty({
6+
example: '웹 요청 중단에 성공했습니다.',
7+
description: '웹 요청 결과 메시지',
8+
})
9+
@IsString()
10+
message: string;
11+
}

0 commit comments

Comments
 (0)