简体   繁体   English

如何在 Apollo Server 中设置服务器端完整响应缓存

[英]How to setup server-side full response caching in Apollo Server

I am trying to setup a cache according to this guide for one expensive query that has a result that changes only once a day.我正在尝试根据本指南为一个昂贵的查询设置缓存, 查询的结果每天仅更改一次。 The query takes 7-8 seconds and most it is after the DB query, because the response returned from the resolver must be heavily processed.查询需要 7-8 秒,大部分时间是在数据库查询之后,因为从解析器返回的响应必须经过大量处理。

I am using apollo-server-express library and the change pluging is apollo-server-plugin-response-cache .我正在使用apollo-server-express库,更改插件是apollo-server-plugin-response-cache

This is what I have done:这就是我所做的:

server.js

const { ApolloServer } = require('apollo-server-express')
const responseCachePlugin = require('apollo-server-plugin-response-cache')

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: async ({ req }) => {
    // ...
  },
  plugins: [responseCachePlugin()]
resolvers.js

personDetails: async (root, args, ctx, info) => {
      info.cacheControl.setCacheHint({ maxAge: 600 })
      const persons = await Person.find({}).populate('details')

      // processing the data

      return processedData
}

I expect the resolver to run once and then after that the response should be returned from the cache almost instantly.我希望解析器运行一次,然后几乎立即从缓存中返回响应。 This doesn't work.这不起作用。 I am doing something wrong or I haven't understood how this should work.我做错了什么,或者我不明白这应该如何工作。

I tried to put cache hints also in the schema, but didn't get any better results.我试图将缓存提示也放在架构中,但没有得到更好的结果。

It should work.它应该工作。 Here is a working example:这是一个工作示例:

server.ts : server.ts

import { ApolloServer, gql } from 'apollo-server-express';
import express from 'express';
import responseCachePlugin from 'apollo-server-plugin-response-cache';

const typeDefs = gql`
  type Query {
    personDetails: String
  }
`;
const resolvers = {
  Query: {
    personDetails: async (root, args, ctx, info) => {
      console.log(`[${new Date().toLocaleTimeString()}] Query.personDetails`);
      info.cacheControl.setCacheHint({ maxAge: 10 });
      return 'This is person details';
    },
  },
};

const app = express();
const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [responseCachePlugin()],
});

apolloServer.applyMiddleware({ app });

const server = app.listen({ port: 4000 }, () => {
  console.log(`The server is running in http://localhost:4000${apolloServer.graphqlPath}`);
});

The request logs:请求日志:

The server is running in http://localhost:4000/graphql
[1:51:27 PM] Query.personDetails
[1:51:52 PM] Query.personDetails

The response header:响应头:

cache-control: max-age=10, public

The first graphql request send at [1:51:27 PM] .第一个 graphql 请求在[1:51:27 PM]发送。 In the next 10 seconds, all requests sent will hit the cache(defaults to an in-memory LRU cache), which means the graphql resolver personDetails will not execute.在接下来的 10 秒内,所有发送的请求都会命中缓存(默认为内存中的 LRU 缓存),这意味着 graphql 解析器personDetails将不会执行。 The graphql response will be read from the cache and sent to client-side. graphql 响应将从缓存中读取并发送到客户端。

After 10 seconds, I send another graphql request at [1:51:52 PM] . 10 秒后,我在[1:51:52 PM]发送了另一个 graphql 请求。 The cache is expired.缓存已过期。 So this request will not hit the in-memory cache.所以这个请求不会命中内存缓存。 The graphql resolver will execute and generate a new value. graphql 解析器将执行并生成一个新值。

source code: https://github.com/mrdulin/apollo-graphql-tutorial/tree/master/src/stackoverflow/57243105源代码: https : //github.com/mrdulin/apollo-graphql-tutorial/tree/master/src/stackoverflow/57243105

I understand that this is an old question but it might help someone solve server side caching issue in Apollo.我知道这是一个老问题,但它可能有助于解决 Apollo 中的服务器端缓存问题。

So as per my understanding the apollo-server-plugin-response-cache plugin only works if the response from the underlying REST API have control-cache header.因此,根据我的理解, apollo-server-plugin-response-cache插件仅在来自底层 REST API 的响应具有 control-cache 标头时才有效。 In case there is no cache-control header in your REST API it can be overriden in restDataSouce GET calls as below.如果您的 REST API 中没有缓存控制标头,它可以在 restDataSouce GET 调用中被覆盖,如下所示。

 return this.get(`uri_path`,"", {cacheOptions: { ttl: 1}});

After that continue using info.cacheControl at the resolvers as suggested in the example from the question snippets.之后,按照问题片段示例中的建议,继续在解析器中使用 info.cacheControl。 maxAge there will override the time mentioned in the cacheOptions. maxAge 将覆盖 cacheOptions 中提到的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM