跨上下文创建的数据加载器缓存(graphQl ApolloServer)

Posted

技术标签:

【中文标题】跨上下文创建的数据加载器缓存(graphQl ApolloServer)【英文标题】:Dataloader caches across context creations (graphQl ApolloServer) 【发布时间】:2020-05-27 00:43:25 【问题描述】:

我已将 DataLoaders 集成到我的 graphQL 请求中,但由于某种原因,缓存在请求之间被记忆。我可以读到在 ApolloServer 配置中将函数传递给上下文应该为每个请求创建一个新上下文,但由于某种原因,即使在那时,DataLoaders 也会被记忆。

这是我的代码

阿波罗配置:

export default new ApolloServer(
  resolvers,
  typeDefs,
  context: ( req, res ) => generateContext(req, res)
);

生成上下文:

const generateContext = (req: Express.Request, res: Express.Response) => (
  ...generateLoaders(),
  res,
  req
);

生成加载器:

import * as questionLoaders from './questionLoaders';

const generateLoaders = () => (
  questionLoaders
);

问题加载器:

const batchQuestions = async (ids: number[]) => 
  const questions = await Question.query().findByIds(ids);
  return ids.map((id) => questions.find((q) => q.id === id));
;

export const questionLoader = new dataloader((ids: number[]) => batchQuestions(ids));

【问题讨论】:

【参考方案1】:

您只需调用一次DataLoader 构造函数,然后将生成的 DataLoader 实例导出为常量。即使在每个请求上调用您的上下文函数,它也会使用导入的值,该值始终是相同的 DataLoader 实例。更改您的导出,使其成为一个函数:

export const createQuestionLoader = () => new dataloader((ids: number[]) => batchQuestions(ids));

然后你可以导入它并调用context里面的函数:

import  createQuestionLoader  from '...'

const generateContext = (req: Express.Request, res: Express.Response) => (
  QuestionLoader: createQuestionLoader(),
  res,
  req
);

【讨论】:

这行得通,谢谢。是否可以将 QuestionLoader 重构为 generateLoaders 而不会丢失每个上下文中的新实例?我还有其他几个未显示的加载程序,上下文文件最终会变得非常大。 是的,重点是导出一个创建loader实例的函数,而不是导出一个loader实例本身。如果你想在 generateLoaders 这样的另一个函数中调用该函数,那很好。 这导致我的生产服务器出现问题,但在本地工作。在生产中,数据加载器似乎没有初始化(或及时初始化) @A.com 请使用完整的代码示例打开一个新问题。 @DanielRearden 完全是我的错......我在 graphql 服务器上的上下文对象周围有奇怪的逻辑

以上是关于跨上下文创建的数据加载器缓存(graphQl ApolloServer)的主要内容,如果未能解决你的问题,请参考以下文章

用于解析器 GraphQL 瑜伽的 TypeScript 类型(在上下文中使用 prisma2)

GraphQL 解析器参数(根、参数、上下文)的错误顺序

如何在 GraphQL 解析器中添加用于缓存的 redis 客户端

***或查看器类型内的 GraphQL 查看器上下文查询?

测试graphql解析器时如何制作虚拟上下文?

GraphQL 订阅字段无法访问解析器的上下文