에러 해결하였습니다.. app.module.ts > typeOrmModuleOptions에 keepConnectionAlive: true 옵션이 빠져있어 발생한 에러였습니다. 검색해보니 '어플리케이션 종료 시 DB 연결 유지'에 대한 내용인데 제가 다른 옵션과 착각하고 주석 처리했었습니다. 현재 옵션 활성화 하였고 e2e 테스트 정상적으로 진행되는거 확인했습니다. const typeOrmModuleOptions = { useFactory: async ( configService: ConfigService, ): Promise<TypeOrmModuleOptions> => ({ namingStrategy: new SnakeNamingStrategy(), // ... keepConnectionAlive: true, }), 검색해보니 beforeEach에 있는 app.init() 메소드에서 어플리케이션을 초기화하며 DB 연결도 초기화되는데, 어플리케이션을 재초기화하는 것이지 종료한 적은 없었기에 여전히 'default'라는 이름으로 활성화된 DB 연결이 존재하였고, DB 연결 재초기화 중 'default라는 이름으로 새로운 DB 연결이 실패하였다' 에러가 발생한 것이며 keepConnectionAlive: true 옵션을 줌으로써 DB 연결은 어플리케이션의 생명주기와는 별도로 존재하게 되고, 이미 활성화된 DB 연결이 존재하므로 새로운 DB 연결을 시도하지 않는다 라고 합니다.. 공부가 되었네요. app.e2e-spec.ts의 afterEach 메소드는 제거하였습니다. ============================================================= 안녕하세요 강사님 강의따라 진행하다 에러가 발생하여 질문글 남깁니다. 에러 메세지는 아래와 같습니다. [Nest] 26544 - 2023. 11. 25. 오후 11:01:36 ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)... AlreadyHasActiveConnectionError: Cannot create a new connection named "default", because connection with such name already exist and it now has an active connection session. at AlreadyHasActiveConnectionError.TypeORMError [as constructor] (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\error\TypeORMError.ts:7:9) at new AlreadyHasActiveConnectionError (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\error\AlreadyHasActiveConnectionError.ts:8:9) at ConnectionManager.Object.<anonymous>.ConnectionManager.create (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\connection\ConnectionManager.ts:57:23) at C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\globals.ts:77:35 at step (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:143:27) at Object.next (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:124:57) at C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:117:75 at new Promise (<anonymous>) at Object.__awaiter (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:113:16) at createConnection (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\typeorm\globals.js:55:20) [Nest] 26544 - 2023. 11. 25. 오후 11:01:39 ERROR [TypeOrmModule] Unable to connect to the database. Retrying (2)... AlreadyHasActiveConnectionError: Cannot create a new connection named "default", because connection with such name already exist and it now has an active connection session. at AlreadyHasActiveConnectionError.TypeORMError [as constructor] (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\error\TypeORMError.ts:7:9) at new AlreadyHasActiveConnectionError (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\error\AlreadyHasActiveConnectionError.ts:8:9) at ConnectionManager.Object.<anonymous>.ConnectionManager.create (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\connection\ConnectionManager.ts:57:23) at C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\src\globals.ts:77:35 at step (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:143:27) at Object.next (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:124:57) at C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:117:75 at new Promise (<anonymous>) at Object.__awaiter (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\tslib\tslib.js:113:16) at createConnection (C:\Users\admin\OneDrive\바탕 화면\typeorm-in-the-nest\node_modules\typeorm\globals.js:55:20) FAIL test/app.e2e-spec.ts (10.952 s) AppController (e2e) √ / (GET) (845 ms) hello jest × two plus two is four (5014 ms) ● AppController (e2e) › hello jest › two plus two is four thrown: "Exceeded timeout of 5000 ms for a hook. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test." 7 | let app: INestApplication; 8 | > 9 | beforeEach(async () => { | ^ 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); at app.e2e-spec.ts:9:3 at Object.<anonymous> (app.e2e-spec.ts:6:1) Test Suites: 1 failed, 1 total Tests: 1 failed, 1 passed, 2 total Snapshots: 0 total Time: 11.106 s Ran all test suites. Jest did not exit one second after the test run has completed. This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot 읽어보니 이미 'default'라는 이름의 연결이 존재하고, 현재 활성화 중이므로 같은 이름의 연결을 또 생성할 수 없다는 것 같고, 검색해보니 beforeEach 메소드 안에 Test.createTestingModule이 매 테스트마다 DB 연결을 시도하는 상황이라고 나왔습니다.. 하여 아래와 같이 afterEach 메소드를 사용하여 매 테스트마다 어플리케이션을 종료해주도록 코드를 수정하였습니다. describe('AppController (e2e)', () => { let app: INestApplication; beforeEach(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); await app.init(); }); // 테스트 2개 이상 사용할 경우 필요한 메소드 afterEach(async () => { await app.close(); }); it('/ (GET)', () => { return request(app.getHttpServer()) .get('/') .expect(200) .expect('typeorm in nest, just coding'); }); describe('hello jest', () => { it('two plus two is four', () => { expect(2 + 2).toBe(4); }); }); // 생략 수정 후 강의에서 진행했던 내용은 모두 완료가 되었는데.. 이제 궁금한 점은 강사님과 코드 내용이 같고 도커나 DB 연결에 대하여 특별히 수정한 내용이 없는데 왜 이런 상황이 발생하는 것인지. 버전이 달라 발생한 상황인 것인지.. 그리고 afterEach를 사용하였을때 당장 테스트 진행은 가능하지만 이대로 사용해도 괜찮을지 안좋은 것은 아닌지가 궁금합니다..
[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core
강의 내용중엔 빠졌지만 refresh token을 db에 저장해야하는것으로 알고있는데요 테이블 설계시 refresh 토큰을 User 테이블 내에 칼럼으로 넣을까 생각을했었는데 의미가 맞지않는것같아서요 아래처럼 one to one 관계로 해서 관리하는건 올바른 방법일까요? class TokenModel { @PrimaryGenerateKey() @OneToOne(() => UserModel, user => user.refresh) id: string; @Column() refreshToken: string; } class User { ... @OneToOne(() => TokenModel, token => token.id) refresh: TokenModel }
[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core
안녕하세요 코드팩토리님!! Transaction 파트에서 궁금한게 있어서 질문 드립니다. Transaction 적용후 테스트로 에러 발생해 보니 정상적으로 포스트가 생성되지는 않습니다. 그런데 이후 정상적으로 포스트를 한개 생성하니 이전 마지막 포스트가 10이었으면 이번에는 12번으로 생성됩니다. 에러 발생후 포스트는 생성되지 않지만 id 값은 증가하는데 정상적인 현상인가요?? 참고로 에러는 코드팩토리님 처럼 중간에 throw new InternalServerErrorException()을 넣고 저장하면 밑에 코드가 전부 지워져서그냥 images[]에 이미지 넣을때 알파벳 몇개 지워서 일부로 에러 발생하는 방식으로 에러 테스트 했습니다.
안녕하세요, 저는 Spring에서 Nest로 넘어온 네린이입니다. 스프링에서는 통합테스트 작성시에도 데이터베이스에 데이터가 삽입되거나 업데이트 되지않도록 롤백시키는 방법이 존재하는데 Nest에서는 어떻게 해야하나요? 제가 생각하는 방법은 직접 쿼리러너를 통해 afterEach를 통해서 매번테스트후에 롤백을 시키는방법을 생각했습니다.
[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core
코팩님 강의 잘보고있습니다. :) 'DefaultValuePipe 사용해보기'라는 강의에서 궁금한 것이 있어서 질문드립니다. new와 그냥 클래스는 제가 이해한 바로는 그냥 클래스처럼 넣게 되면 DI를 통한 nest에서 싱글톤 패턴으로 ParseIntPipe를 주입해주는 것이고 new키워드를 붙이게 되면 인스턴스가 생성하게 됨으로 nest에서 DI로 주입해주는 것이 아닌 ParseIntPipe클래스의 인스턴스가 생성되는 방식인가요? 감사합니다.
[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core
RBAC까지 다뤄주시다니 정말 흥미로운 내용이었습니다! 다만 현재 로직상으로는 RefreshTokenGuard이 적용된 Access 토큰 갱신, Refresh 토큰 갱신 API에 IsPublic을 적용하면 RefreshTokenGuard도 미적용되지 않나요? 실제 저 API들을 Access Token으로 호출해보면 Guard가 아니라 Service 단에서 Exception이 발생하는 것 같더라구요.
왼쪽은 엣지 inprivate, 오른쪽은 크롬 시크릿 모드 브라우저입니다. 서로의 채팅 입력 시간이 9시간 전으로 표시되고 있습니다. 실제로 서버의 createdAt은 한국 표준시라고는 되어있지만 실제 시간보다 9시간 느린 시간이 저장되었고 entities/channelChats.ts의 설정 내용은 강사님의 깃헙 내용과 동일했습니다. aws - rds에서 확인해본 DB도 지역이 ap-northeast-2a, 서울로 잘 지정되어 있었습니다. 혹시 작업 중에 이런 경우 보신 적 있으신가요? 어디를 더 살펴봐야 서버에 제대로 된 현재 시간이 저장될 수 있을지 조언 부탁드립니다.
[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core
영상에서는 단순히 포스트 컨트롤러에서 @UseGuards(AccessTokenGuard)를 추가한 후 잘 작동하는 것 같은데 저는 디펜던시 에러가 나타나네요.. ERROR [ExceptionHandler] Nest can't resolve dependencies of the RefreshTokenGuard (?, UsersService). Please make sure that the argument AuthService at index [0] is available in the PostsModule context. 디펜던시 에러 해결하는 강의를 다시 보고 포스트 모듈에서 필요한 부분들을 추가하여 해결은 했습니다. AuthService, UsersService와 JwtModule.register({}), UsersModel까지 추가해주니까 영상처럼 토큰을 보내줬을 때 포스트 기능이 잘 작동합니다.. 궁금한 것은 영상에서는 포스트 모듈에 별다른 수정 없이 단순히 포스트 컨트롤러에서 @UseGuards만 추가해도 잘 작동하는 것 같은데.. 저는 왜 포스트 모듈에서 필요한 부분을 추가해 주어야 했는지 모르겠네요.. 제가 놓친 부분이 있었을까요..? 감사합니다.
tcp통신을 이용해서 마이크로 서비스를 만들고 있습니다. 마이크로 서비스는 3000번으로 포트를 켜놨고, 게이트웨이의 포트는 4000번으로 실행을 하게끔 해놨습니다. 제가 우선 테스트를 위해서 user의 레포지토리에서 데이터를 전체 긁어오게끔 간단한 로직을 짜놨는데요. // 게이트웨이 컨트롤러 @Get("/users") @UseGuards() async GetUsers() { return this.organizationService.getUsers(); } // 게이트웨이 서비스 getUsers() { return this.clients.send("get:getUsers", {}); } // 마이크로 서비스 @MessagePattern({ cmd: "get:getUsers" }) async getUsers() { console.log("걸림"); return pipe( await this.userRepository.find({ relations: [ /* 관계 설정 */], }), (users) => ({ success: true, users: { users: users.map((user) => ( // 유저 정보들 ), }, }), ); } localhost:3000/api/users 경로로 요청 결과는 500에러가 나오고 콘솔에는 [Nest] 3096 - 2023. 11. 16. 오후 2:45:20 ERROR [ExceptionsHandler] There is no matching message handler defined in the remote service. 이렇게 메시지 핸들러가 일치하지 않다는데 대체 뭐가 잘못된건지를 모르겠습니다. 메시지 패턴 이름도 같게 해놨는데 말이죠.