Last active
December 4, 2023 04:46
-
-
Save royanon/9038b06cf67ee245c9ab5babf9e9a34b to your computer and use it in GitHub Desktop.
Sample to use apollo-server-plugin-response-cache for Strapi V4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Work on the following dependency | |
| // "@strapi/strapi": "4.5", | |
| // "@strapi/plugin-graphql": "4.5", | |
| // "apollo-server-cache-redis": "^3.3.0", | |
| // "apollo-server-core": "^3.3.0", | |
| // "apollo-server-plugin-response-cache": "^3.3.0", | |
| // file location: config/plugin.js | |
| const apolloServerPluginResponseCache = require('apollo-server-plugin-response-cache').default; | |
| const InMemoryLRUCache = require('@apollo/utils.keyvaluecache').InMemoryLRUCache; | |
| const ApolloServerPluginCacheControl = require('apollo-server-core').ApolloServerPluginCacheControl; | |
| const DEFAULT_MAX_AGE = parseInt(process.env.STRAPI_GRAPHQL_DEFAULT_MAX_AGE? process.env.STRAPI_GRAPHQL_DEFAULT_MAX_AGE : 3600); | |
| const MAX_AGE = parseInt(process.env.STRAPI_GRAPHQL_MAX_AGE? process.env.STRAPI_GRAPHQL_MAX_AGE : 60); | |
| async function sessionId(requestContext) { | |
| // sessionId: (requestContext) => (requestContext.request.http.headers.get('sessionId') || null), | |
| return null; | |
| } | |
| /** add logic if necessary */ | |
| async function shouldReadFromCache(requestContext) { | |
| return true; | |
| } | |
| /** add logic if necessary */ | |
| async function shouldWriteToCache(requestContext) { | |
| return true; | |
| } | |
| /** add logic if necessary */ | |
| async function extraCacheKeyData(requestContext) { | |
| } | |
| /** determine cache either redis or default inMemoryLRUCache */ | |
| function initCache() { | |
| // make sure only run when instance started, but not in build time | |
| if (process.env.REDIS_HOST) { | |
| const { RedisCache } = require('apollo-server-cache-redis'); | |
| return new RedisCache(process.env.REDIS_HOST); | |
| } else { | |
| return new InMemoryLRUCache({ | |
| // ~100MiB | |
| maxSize: Math.pow(2, 20) * 100, | |
| // 5 minutes (in milliseconds) | |
| ttl: 300_000, | |
| }); | |
| } | |
| return false; | |
| } | |
| /** referenced cache instance */ | |
| const graphqlCache = initCache(); | |
| module.exports = ({ env }) => ({ | |
| graphql: { | |
| enabled: true, | |
| config: { | |
| defaultLimit: 100, | |
| apolloServer: { | |
| // for debug purpose, we can use redis-stack to do tracking | |
| // cache: setRedisCacheIfEnvSet(), | |
| // keep simple to use InMemoryLRUCache if only one instance is used | |
| // data ttl folow the defaultMaxAge if not specify | |
| cache: graphqlCache, | |
| tracing: true, | |
| plugins: [ | |
| // cache behavior lower age override higher age | |
| ApolloServerPluginCacheControl({ defaultMaxAge: DEFAULT_MAX_AGE }), | |
| // sessionId will be used for Private scope. extra logic need to added if we need to handle login users query | |
| apolloServerPluginResponseCache({ | |
| shouldReadFromCache, | |
| shouldWriteToCache, | |
| extraCacheKeyData, | |
| sessionId, | |
| }), | |
| { | |
| /** | |
| * Plugin check request.variables.flush_cache and handle purge cache logic for redisCache or inMemoryLRUCache | |
| * Apollo plugin life cycle ref: https://www.apollographql.com/docs/apollo-server/integrations/plugins/ | |
| * request.variables.flush_cache short_cache|purge_all | |
| * @todo change lifecycle or otherwise, will cache itself after cache is cleared | |
| * */ | |
| async requestDidStart() { | |
| return { | |
| async willSendResponse(requestContext) { | |
| if(requestContext.request?.variables?.flush_cache === "short_cache"){ | |
| if (process.env.REDIS_HOST) { | |
| // remove keys with expiry lower than MAX_AGE | |
| graphqlCache.client.keys('*', (err, keys) => { | |
| keys.forEach(function (key, pos) { | |
| graphqlCache.client.get(key, function(err, result){ | |
| const cache_time = JSON.parse(result).cacheTime; | |
| if(Date.now() - cache_time < MAX_AGE * 1000){ | |
| graphqlCache.client.del(key, function(err, succeeded) { | |
| }); | |
| } | |
| }); | |
| }); | |
| }); | |
| } else { | |
| // remove keys with expiry lower than MAX_AGE | |
| let keys = graphqlCache.keys(); | |
| keys.forEach(key => { | |
| let value = graphqlCache.get(key); | |
| value.then(function(result) { | |
| const cache_time = JSON.parse(result).cacheTime; | |
| if(Date.now() - cache_time < MAX_AGE * 1000){ | |
| graphqlCache.delete(key); | |
| } | |
| }); | |
| }); | |
| } | |
| } else if(requestContext.request?.variables?.flush_cache === "purge_all") { | |
| if (process.env.REDIS_HOST) { | |
| // clear RedisCache | |
| graphqlCache.client.flushdb( function (err, succeeded) { | |
| // console.log(succeeded); | |
| }); | |
| } else { | |
| // clear inMemoryLRUCache | |
| graphqlCache.clear(); | |
| } | |
| } | |
| }, | |
| }; | |
| }, | |
| }, | |
| ] | |
| }, | |
| }, | |
| }, | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The library is now available in here
https://github.com/10Life/strapi-plugin-advanced-cache-manager