Add a cache on /metadata (#5189)
In this PR I'm introducing a simple custom graphql-yoga plugin to create a caching mechanism specific to our metadata. The cache key is made of : workspace id + workspace cache version, with this the cache is automatically invalidated each time a change is made on the workspace metadata.
This commit is contained in:
@ -0,0 +1,38 @@
|
|||||||
|
import { Plugin } from 'graphql-yoga';
|
||||||
|
|
||||||
|
export function useCachedMetadata(): Plugin {
|
||||||
|
const cache = new Map<string, any>();
|
||||||
|
|
||||||
|
const computeCacheKey = (serverContext: any) => {
|
||||||
|
const workspaceId = serverContext.req.workspace?.id ?? 'anonymous';
|
||||||
|
const cacheVersion = serverContext.req.cacheVersion ?? '0';
|
||||||
|
|
||||||
|
return `${workspaceId}:${cacheVersion}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
onRequest: ({ endResponse, serverContext }) => {
|
||||||
|
const cacheKey = computeCacheKey(serverContext);
|
||||||
|
const foundInCache = cache.has(cacheKey);
|
||||||
|
|
||||||
|
if (foundInCache) {
|
||||||
|
const cachedResponse = cache.get(cacheKey);
|
||||||
|
|
||||||
|
const earlyResponse = Response.json(cachedResponse);
|
||||||
|
|
||||||
|
return endResponse(earlyResponse);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onResponse: async ({ response, serverContext }) => {
|
||||||
|
const cacheKey = computeCacheKey(serverContext);
|
||||||
|
|
||||||
|
const foundInCache = cache.has(cacheKey);
|
||||||
|
|
||||||
|
if (!foundInCache) {
|
||||||
|
const responseBody = await response.json();
|
||||||
|
|
||||||
|
cache.set(cacheKey, responseBody);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@ import { useThrottler } from 'src/engine/api/graphql/graphql-config/hooks/use-th
|
|||||||
import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphql-api.module';
|
import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphql-api.module';
|
||||||
import { renderApolloPlayground } from 'src/engine/utils/render-apollo-playground.util';
|
import { renderApolloPlayground } from 'src/engine/utils/render-apollo-playground.util';
|
||||||
import { DataloaderService } from 'src/engine/dataloaders/dataloader.service';
|
import { DataloaderService } from 'src/engine/dataloaders/dataloader.service';
|
||||||
|
import { useCachedMetadata } from 'src/engine/api/graphql/graphql-config/hooks/use-cached-metadata';
|
||||||
|
|
||||||
export const metadataModuleFactory = async (
|
export const metadataModuleFactory = async (
|
||||||
environmentService: EnvironmentService,
|
environmentService: EnvironmentService,
|
||||||
@ -32,6 +33,7 @@ export const metadataModuleFactory = async (
|
|||||||
useExceptionHandler({
|
useExceptionHandler({
|
||||||
exceptionHandlerService,
|
exceptionHandlerService,
|
||||||
}),
|
}),
|
||||||
|
useCachedMetadata(),
|
||||||
],
|
],
|
||||||
path: '/metadata',
|
path: '/metadata',
|
||||||
context: () => ({
|
context: () => ({
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
|
||||||
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
|
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
|
||||||
import { WorkspaceSchemaStorageService } from 'src/engine/api/graphql/workspace-schema-storage/workspace-schema-storage.service';
|
import { WorkspaceSchemaStorageService } from 'src/engine/api/graphql/workspace-schema-storage/workspace-schema-storage.service';
|
||||||
|
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ObjectMetadataModule, WorkspaceCacheVersionModule],
|
imports: [ObjectMetadataModule, WorkspaceCacheVersionModule],
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import { LoggerDriverType } from 'src/engine/integrations/logger/interfaces';
|
|||||||
import { IsStrictlyLowerThan } from 'src/engine/integrations/environment/decorators/is-strictly-lower-than.decorator';
|
import { IsStrictlyLowerThan } from 'src/engine/integrations/environment/decorators/is-strictly-lower-than.decorator';
|
||||||
import { CaptchaDriverType } from 'src/engine/integrations/captcha/interfaces';
|
import { CaptchaDriverType } from 'src/engine/integrations/captcha/interfaces';
|
||||||
import { MessageQueueDriverType } from 'src/engine/integrations/message-queue/interfaces';
|
import { MessageQueueDriverType } from 'src/engine/integrations/message-queue/interfaces';
|
||||||
|
import { CacheStorageType } from 'src/engine/integrations/cache-storage/types/cache-storage-type.enum';
|
||||||
|
|
||||||
import { IsDuration } from './decorators/is-duration.decorator';
|
import { IsDuration } from './decorators/is-duration.decorator';
|
||||||
import { AwsRegion } from './interfaces/aws-region.interface';
|
import { AwsRegion } from './interfaces/aws-region.interface';
|
||||||
@ -369,7 +370,7 @@ export class EnvironmentVariables {
|
|||||||
@CastToPositiveNumber()
|
@CastToPositiveNumber()
|
||||||
API_RATE_LIMITING_LIMIT = 500;
|
API_RATE_LIMITING_LIMIT = 500;
|
||||||
|
|
||||||
CACHE_STORAGE_TYPE = 'memory';
|
CACHE_STORAGE_TYPE: CacheStorageType = CacheStorageType.Memory;
|
||||||
|
|
||||||
@CastToPositiveNumber()
|
@CastToPositiveNumber()
|
||||||
CACHE_STORAGE_TTL: number = 3600 * 24 * 7;
|
CACHE_STORAGE_TTL: number = 3600 * 24 * 7;
|
||||||
|
|||||||
Reference in New Issue
Block a user