Nest 포함 GraphQL 구독: 실행 중인 여러 서버에서 게시하는 방법

오늘 Redis와 NestJS를 사용하여 GraphQL(GQL) 구독을 설정하는 방법을 배울 것입니다.
본문의 선결 조건:
  • GraphQL에서의 경험
  • NestJS의 기본 지식 (만약 당신이 NestJS가 무엇인지 모른다면, give it a try, 그리고 돌아오세요.)

  • Docker이 당신의 기계에 설치되어 있습니다.
  • "왜 우리가 Redis를 필요로 합니까?"라고 스스로에게 물어볼 수도 있다.Apollo가 제공하는 기본 구독은 상자를 열면 바로 사용할 수 있습니다. 맞습니까?
    그럼 상황을 봐야지.서버에 인스턴스가 하나만 있을 경우 Redis가 필요하지 않습니다.
    단, 응용 프로그램을 확장하고 추가 서버 실례를 생성할 때, 한 실례에 발표된 이벤트가 다른 실례의 구독자에게 수신될 수 있도록 확보해야 한다.이것은 기본 구독이 당신을 위해 할 수 없는 일입니다.
    따라서 기본 구독을 사용하여 기본적인 GQL 응용 프로그램을 구축하는 것부터 시작합니다.
    먼저 @nestjs/cli을 설치합니다.
    npm i -g @nestjs/cli
    
    그런 다음 새 NestJS 프로젝트를 만듭니다.
    nest new nestjs-gql-redis-subscriptions
    

    이제 nestjs-gql-redis-subscriptions/src/main.ts을 열고 변경합니다.
    await app.listen(3000);
    
    받는 사람:
    await app.listen(process.env.PORT || 3000);
    
    이것은 우리가 필요할 때 envvar를 통해 포트를 지정할 수 있도록 합니다.
    NestJS는 매우 신뢰할 수 있는 GQL 지원을 가지고 있지만, 이를 이용하기 위해 추가 의존 항목을 설치해야 합니다.
    cd nestjs-gql-redis-subscriptions
    npm i @nestjs/graphql apollo-server-express graphql-tools graphql graphql-subscriptions
    
    우리는 또한 graphql-subscriptions을 설치했는데, 이것은 우리의 응용 프로그램에 구독을 가져왔다.
    구독의 실제 상황을 보기 위해 우리는 "탁구"응용 프로그램을 구축할 것입니다. 그 중에서 ping은 GQL mutation을 통해, pong은 GQL subscription을 통해 발송됩니다.src 디렉터리에서 types.graphql 파일을 만들고 우리의 모드를 거기에 두십시오.
    type Query {
      noop: Boolean
    }
    
    type Mutation {
      ping: Ping
    }
    
    type Subscription {
      pong: Pong
    }
    
    type Ping {
      id: ID
    }
    
    type Pong {
      pingId: ID
    }
    
    그런 다음 app.module.ts으로 이동하여 GraphQLModule을 다음과 같이 가져옵니다.
    // ... other imports
    import { GraphQLModule } from '@nestjs/graphql';
    import { PubSub } from 'graphql-subscriptions';
    
    @Module({
      imports: [
        GraphQLModule.forRoot({
          playground: true,
          typePaths: ['./**/*.graphql'],
          installSubscriptionHandlers: true,
        }),
      ],
      providers: [
        {
          provide: 'PUB_SUB',
          useValue: new PubSub(),
        },
      ],
    })
    export class AppModule {}
    
    GraphQLModule.forRoot에 전달되는 옵션을 살펴보겠습니다.
  • playground-http:localhost:${PORT}/graphqlGQL Playground을 노출한다.우리는 이 도구를 사용하여'탁구'사건을 구독하고'탁구'돌변을 보낼 것이다.
  • installSubscriptionHandlers - 구독 지원 활성화
  • typePaths-GQL 유형에 정의된 경로입니다.
  • 또 다른 재미있는 디테일은 다음과 같다.
    {
      provide: 'PUB_SUB',
      useValue: new PubSub(),
    }
    
    이것은 게시/구독 엔진의 기본 (메모리) 구현입니다. 이벤트를 발표하고 구독을 만들 수 있습니다.
    이제 GQL 서버를 구성한 후에 해상도를 만들 때가 되었습니다.src 폴더에서 ping-pong.resolvers.ts 파일을 만들고 다음 내용을 입력합니다.
    import { Resolver, Mutation, Subscription } from '@nestjs/graphql';
    import { Inject } from '@nestjs/common';
    import { PubSubEngine } from 'graphql-subscriptions';
    
    const PONG_EVENT_NAME = 'pong';
    
    @Resolver('Ping')
    export class PingPongResolvers {
      constructor(@Inject('PUB_SUB') private pubSub: PubSubEngine) {}
    
      @Mutation('ping')
      async ping() {
        const pingId = Date.now();
        this.pubSub.publish(PONG_EVENT_NAME, { [PONG_EVENT_NAME]: { pingId } });
        return { id: pingId };
      }
    
      @Subscription(PONG_EVENT_NAME)
      pong() {
        return this.pubSub.asyncIterator(PONG_EVENT_NAME);
      }
    }
    
    우선, 우리는 PingPongResolvers으로 @Resolver('Ping')류를 장식해야 한다.NestJS 공식 문서는 그 목적을 잘 설명합니다.
    너는 새둥지에 문의해도 된다.js 공식 문서 Working with GraphQL

    The @Resolver() decorator does not affect queries or mutations (neither @Query() nor @Mutation() decorators). It only informs Nest that each @ResolveProperty() inside this particular class has a parent, which is a Ping type in this case.


    그리고 ping의 돌연변이를 정의했습니다.그 주요 직책은 pong 사건을 발표하는 것이다.
    마지막으로 구독 정의가 생겼습니다. 구독한 클라이언트에게 적당한 이벤트를 보내는 것을 책임집니다.PingPongResolversAppModule에 추가해야 합니다.
    // ...
    @Module({
      // ...
      providers: [
        PingPongResolvers,
        {
          provide: 'PUB_SUB',
          useValue: new PubSub(),
        },
      ],
    })
    export class AppModule {}
    
    현재, 우리는 이미 응용 프로그램을 시작하고, 우리의 실제 실현을 볼 준비가 되어 있다.
    실제로 메모리 구독 문제를 이해하기 위해 두 개의 응용 프로그램을 실행합니다. 하나는 포트 3000에 있고, 다른 하나는 포트 3001에 있습니다.
    터미널 창에서 다음을 실행합니다.
    # port 3000 is the default port for our app
    npm start
    
    다음 예제에서는
    PORT=3001 npm start
    
    다음 프레젠테이션은 다음과 같습니다.

    보시다시피: 3001에서 실행된 실례는: 3000 실례에서 발표된 어떤 이벤트도 얻지 못했습니다.
    다음 그림은 다양한 각도에서 볼 수 있습니다.

    분명히: 3001: 3000에 게시된 이벤트를 볼 수 없습니다.
    이제 우리 응용 프로그램을 좀 조정해서 이 문제를 해결합시다.우선, Redis 구독 종속성을 설치해야 합니다.
    npm i graphql-redis-subscriptions ioredis
    
    graphql-redis-subscriptionsPubSubEngine 인터페이스의 Redis 감지 실현을 제공합니다: RedisPubSub.이전에 이 인터페이스를 사용한 적이 있습니다. 메모리를 통해 -PubSub을 실현합니다.ioredis-은(는) graphql-redis-subscriptions에서 사용하는 Redis 클라이언트입니다.
    우리의 RedisPubSub을 사용하기 시작하려면 AppModule을 조금만 조정하면 됩니다.
    이 항목을 변경하려면 다음과 같이 하십시오.
    // ...
    {
      provide: 'PUB_SUB',
      useValue: new PubSub(),
    }
    // ...
    
    다음을 수행합니다.
    // ...
    import { RedisPubSub } from 'graphql-redis-subscriptions';
    import * as Redis from 'ioredis';
    //  ...
    
    // ...
    {
      provide: 'PUB_SUB',
      useFactory: () => {
        const options = {
          host: 'localhost',
          port: 6379
        };
    
        return new RedisPubSub({
          publisher: new Redis(options),
          subscriber: new Redis(options),
        });
      },
    },
    // ...
    
    docker 컨테이너에서 redis를 시작하여 localhost:6379에서 사용할 수 있도록 합니다(위 RedisPubSub 인스턴스에 대한 옵션).
    docker run -it --rm --name gql-redis -p 6379:6379 redis:5-alpine
    

    이제 애플리케이션을 중지하고 다시 시작해야 합니다(다른 터미널 세션에서):
    npm start
    
    화목하다
    PORT=3001 npm start
    
    이 때, 구독은 예상대로 작동하고, 응용 프로그램의 한 사례에 발표된 이벤트는 클라이언트가 수신하고, 다른 사례에 구독합니다.

    다음은 엔진 덮개 아래에서 발생한 일입니다.

    요약:
    본고에서 우리는 Redis와 GQL을 사용하여 크로스 서버 응용 프로그램에 가입하는 여러 가지 실례를 통해 이벤트를 발표하는 방법을 배웠다.
    우리는 또한 GQL 구독 이벤트 발표/구독 흐름을 더욱 잘 이해해야 한다.
    소스 코드:
    https://github.com/rychkog/gql-redis-subscriptions-article
    이 문장을 좋아합니까?This Dot Labs으로 가서 우리를 보세요!우리는 자바스크립트와 전단의 모든 업무에 종사하는 기술 컨설팅 회사입니다.Angular, React 및 Vue 등의 소스 소프트웨어에 집중합니다.

    좋은 웹페이지 즐겨찾기