在使用Next.js+URQL环境时,使用PostgreSQL的Pub/Sub来进行GraphQL订阅

我在株式会社mofmof工作的shwld,使用Next.js + 服务器端TypeScript + 函数方式创建了一个清洁的应用程序,这篇文章是2022年的Advent Calendar的第21天,我将介绍实现意图等内容。

我之前写过关于如何在Mailgun上实现邮件发送功能的文章。

使用Next.js构建GraphQL Subscription环境。

客户端(next-urql)

withUrqlClient((_ssrExchange, _ctx) => ({
  url: `${API_HOST}/api/graphql`,
  exchanges: [
    dedupExchange,
    cache,
    fetchExchange,
    yogaExchange(),
  ],
})

原始来源:/apps/web/src/graphql/withGraphQLClient.tsx

中文释义:/apps/web/src/graphql/withGraphQLClient.tsx 的来源

服务器端

Pub/Sub实现

我正在使用 pg-pubsub。

这次我考虑使用PostgreSQL的Pub/Sub功能,原因是为了减少基础设施成本。另外,最初我们没有使用GraphQL Yoga。但是在调研过程中发现有一些免费的Redis,而且后来我们改用了Yoga,所以我觉得如果要正常地实现,使用Redis和Yoga是最好的选择。

由于幸运的是,Pub/Sub客户端的实现已在基础设施层进行,因此迁移变得更简单。

import PGPubsub from 'pg-pubsub';
import type { Pubsub } from 'domain-interfaces';
import asyncify from 'callback-to-async-iterator';

const storyChannelName = (projectId: string) => `project-${projectId}-stories`;

export const createPubsubClient = (): Pubsub => {
  const pubsubInstance = new PGPubsub(process.env.DATABASE_URL);

  return {
    story: {
      subscribe({ projectId }) {
        return asyncify(async handler => {
          pubsubInstance.addChannel(storyChannelName(projectId), handler);
        });
      },
      publish(item) {
        pubsubInstance.publish(storyChannelName(item.object.projectId), item);
      },
    },
  };
};

来源:/基础设施/数据库-发布订阅/源代码/索引.ts

订阅

const subscribed = context.pubsub.story.subscribe({
  projectId: args.projectId,
});
for await (const it of subscribed) {
  if (it.triggeredBy.id === context.currentUser.id) continue;

  yield {
    subscribeStoryUpdate: it.object,
  };
}

来源:/use-cases/graphql-resolvers/src/modules/story/subscription-resolvers/story.update/subscribe-story-update.ts

以下是一种可能的中文释义:

来源:/use-cases/graphql-resolvers/src/modules/story/subscription-resolvers/story.update/subscribe-story-update.ts。

发表

context.pubsub.story.publish({
  object: story,
  triggeredBy: user,
})

来源:/use-cases/graphql-resolvers/src/modules/story/mutation-resolvers/story.update/update-story.ts#L58-L60

解释:在指定位置的代码文件中,完成“故事更新”功能的地方。

下次会通知你

明天我将写一篇关于背景工作者的文章。

广告
将在 10 秒后关闭
bannerAds