From b9ba4e8f8c7ca1d7a57dac2e38fef4808df707c3 Mon Sep 17 00:00:00 2001 From: Weiko Date: Fri, 26 Apr 2024 18:15:22 +0200 Subject: [PATCH 1/5] Add redis to useMetadataCache yoga plugin --- .../hooks/use-cached-metadata.ts | 21 +++++++++---------- .../graphql/metadata-graphql-api.module.ts | 10 ++++++++- .../api/graphql/metadata.module-factory.ts | 7 ++++++- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts index b89af80dc863..b62422531583 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts @@ -1,8 +1,9 @@ import { Plugin } from 'graphql-yoga'; -export function useCachedMetadata(): Plugin { - const cache = new Map(); - +export function useCachedMetadata( + cacheGetter: (key: string) => any, + cacheSetter: (key: string, value: any) => void, +): Plugin { const computeCacheKey = (serverContext: any) => { const workspaceId = serverContext.req.workspace?.id ?? 'anonymous'; const cacheVersion = serverContext.req.cacheVersion ?? '0'; @@ -11,13 +12,11 @@ export function useCachedMetadata(): Plugin { }; return { - onRequest: ({ endResponse, serverContext }) => { + onRequest: async ({ endResponse, serverContext }) => { const cacheKey = computeCacheKey(serverContext); - const foundInCache = cache.has(cacheKey); - - if (foundInCache) { - const cachedResponse = cache.get(cacheKey); + const cachedResponse = await cacheGetter(cacheKey); + if (cachedResponse) { const earlyResponse = Response.json(cachedResponse); return endResponse(earlyResponse); @@ -26,12 +25,12 @@ export function useCachedMetadata(): Plugin { onResponse: async ({ response, serverContext }) => { const cacheKey = computeCacheKey(serverContext); - const foundInCache = cache.has(cacheKey); + const cachedResponse = await cacheGetter(cacheKey); - if (!foundInCache) { + if (!cachedResponse) { const responseBody = await response.json(); - cache.set(cacheKey, responseBody); + cacheSetter(cacheKey, responseBody); } }, }; diff --git a/packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts b/packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts index cc305f99cff6..cc41b6e742ff 100644 --- a/packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts +++ b/packages/twenty-server/src/engine/api/graphql/metadata-graphql-api.module.ts @@ -12,6 +12,8 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; import { DataloaderModule } from 'src/engine/dataloaders/dataloader.module'; import { DataloaderService } from 'src/engine/dataloaders/dataloader.service'; +import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum'; +import { CacheStorageModule } from 'src/engine/integrations/cache-storage/cache-storage.module'; @Module({ imports: [ @@ -19,11 +21,17 @@ import { DataloaderService } from 'src/engine/dataloaders/dataloader.service'; driver: YogaDriver, useFactory: metadataModuleFactory, imports: [GraphQLConfigModule, DataloaderModule], - inject: [EnvironmentService, ExceptionHandlerService, DataloaderService], + inject: [ + EnvironmentService, + ExceptionHandlerService, + DataloaderService, + CacheStorageNamespace.WorkspaceSchema, + ], }), MetadataEngineModule, WorkspaceMigrationRunnerModule, WorkspaceMigrationModule, + CacheStorageModule, ], }) export class MetadataGraphQLApiModule {} diff --git a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts index a124086a7704..3f39fe1f7fb4 100644 --- a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts @@ -9,11 +9,13 @@ import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphq import { renderApolloPlayground } from 'src/engine/utils/render-apollo-playground.util'; import { DataloaderService } from 'src/engine/dataloaders/dataloader.service'; import { useCachedMetadata } from 'src/engine/api/graphql/graphql-config/hooks/use-cached-metadata'; +import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; export const metadataModuleFactory = async ( environmentService: EnvironmentService, exceptionHandlerService: ExceptionHandlerService, dataloaderService: DataloaderService, + workspaceSchemaCacheStorage: CacheStorageService, ): Promise => { const config: YogaDriverConfig = { autoSchemaFile: true, @@ -33,7 +35,10 @@ export const metadataModuleFactory = async ( useExceptionHandler({ exceptionHandlerService, }), - useCachedMetadata(), + useCachedMetadata( + workspaceSchemaCacheStorage.get.bind(workspaceSchemaCacheStorage), + workspaceSchemaCacheStorage.set.bind(workspaceSchemaCacheStorage), + ), ], path: '/metadata', context: () => ({ From 6fab4d99facfdc6cadc63473d26d99f53cfa5b50 Mon Sep 17 00:00:00 2001 From: Weiko Date: Fri, 26 Apr 2024 18:54:43 +0200 Subject: [PATCH 2/5] fix mutations --- .../graphql/graphql-config/hooks/use-cached-metadata.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts index b62422531583..a272dcebfa16 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts @@ -11,8 +11,15 @@ export function useCachedMetadata( return `${workspaceId}:${cacheVersion}`; }; + const operationName = (serverContext: any) => + serverContext?.req?.body?.operationName; + return { onRequest: async ({ endResponse, serverContext }) => { + if (operationName(serverContext) !== 'ObjectMetadataItems') { + return; + } + const cacheKey = computeCacheKey(serverContext); const cachedResponse = await cacheGetter(cacheKey); From e0a2dcf79b5ef6cd5bb4f5c8d179933c9b98ee60 Mon Sep 17 00:00:00 2001 From: Weiko Date: Fri, 26 Apr 2024 18:57:58 +0200 Subject: [PATCH 3/5] improve signature --- .../api/graphql/graphql-config/hooks/use-cached-metadata.ts | 3 ++- .../src/engine/api/graphql/metadata.module-factory.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts index a272dcebfa16..76151096f5a5 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts @@ -3,6 +3,7 @@ import { Plugin } from 'graphql-yoga'; export function useCachedMetadata( cacheGetter: (key: string) => any, cacheSetter: (key: string, value: any) => void, + operationsToCache: string[], ): Plugin { const computeCacheKey = (serverContext: any) => { const workspaceId = serverContext.req.workspace?.id ?? 'anonymous'; @@ -16,7 +17,7 @@ export function useCachedMetadata( return { onRequest: async ({ endResponse, serverContext }) => { - if (operationName(serverContext) !== 'ObjectMetadataItems') { + if (!operationsToCache.includes(operationName(serverContext))) { return; } diff --git a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts index 3f39fe1f7fb4..d07af25492f4 100644 --- a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts @@ -38,6 +38,7 @@ export const metadataModuleFactory = async ( useCachedMetadata( workspaceSchemaCacheStorage.get.bind(workspaceSchemaCacheStorage), workspaceSchemaCacheStorage.set.bind(workspaceSchemaCacheStorage), + ['ObjectMetadataItems'], ), ], path: '/metadata', From 45662b1d1149077f93ce35e7cd2acefa54383c5e Mon Sep 17 00:00:00 2001 From: Weiko Date: Fri, 26 Apr 2024 19:04:08 +0200 Subject: [PATCH 4/5] improve signature --- .../hooks/use-cached-metadata.ts | 20 ++++++++++--------- .../api/graphql/metadata.module-factory.ts | 14 ++++++++----- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts index 76151096f5a5..972317432f0e 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts @@ -1,10 +1,12 @@ import { Plugin } from 'graphql-yoga'; -export function useCachedMetadata( - cacheGetter: (key: string) => any, - cacheSetter: (key: string, value: any) => void, - operationsToCache: string[], -): Plugin { +export type CacheMetadataPluginConfig = { + cacheGetter: (key: string) => any; + cacheSetter: (key: string, value: any) => void; + operationsToCache: string[]; +}; + +export function useCachedMetadata(config: CacheMetadataPluginConfig): Plugin { const computeCacheKey = (serverContext: any) => { const workspaceId = serverContext.req.workspace?.id ?? 'anonymous'; const cacheVersion = serverContext.req.cacheVersion ?? '0'; @@ -17,12 +19,12 @@ export function useCachedMetadata( return { onRequest: async ({ endResponse, serverContext }) => { - if (!operationsToCache.includes(operationName(serverContext))) { + if (!config.operationsToCache.includes(operationName(serverContext))) { return; } const cacheKey = computeCacheKey(serverContext); - const cachedResponse = await cacheGetter(cacheKey); + const cachedResponse = await config.cacheGetter(cacheKey); if (cachedResponse) { const earlyResponse = Response.json(cachedResponse); @@ -33,12 +35,12 @@ export function useCachedMetadata( onResponse: async ({ response, serverContext }) => { const cacheKey = computeCacheKey(serverContext); - const cachedResponse = await cacheGetter(cacheKey); + const cachedResponse = await config.cacheGetter(cacheKey); if (!cachedResponse) { const responseBody = await response.json(); - cacheSetter(cacheKey, responseBody); + config.cacheSetter(cacheKey, responseBody); } }, }; diff --git a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts index d07af25492f4..5c28d63f3947 100644 --- a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts @@ -35,11 +35,15 @@ export const metadataModuleFactory = async ( useExceptionHandler({ exceptionHandlerService, }), - useCachedMetadata( - workspaceSchemaCacheStorage.get.bind(workspaceSchemaCacheStorage), - workspaceSchemaCacheStorage.set.bind(workspaceSchemaCacheStorage), - ['ObjectMetadataItems'], - ), + useCachedMetadata({ + cacheGetter: workspaceSchemaCacheStorage.get.bind( + workspaceSchemaCacheStorage, + ), + cacheSetter: workspaceSchemaCacheStorage.set.bind( + workspaceSchemaCacheStorage, + ), + operationsToCache: ['ObjectMetadataItems'], + }), ], path: '/metadata', context: () => ({ From 13f84ce10ddc62a07906680580200b292f1e691f Mon Sep 17 00:00:00 2001 From: Weiko Date: Fri, 26 Apr 2024 19:15:00 +0200 Subject: [PATCH 5/5] rename to getOperationName --- .../graphql/graphql-config/hooks/use-cached-metadata.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts index 972317432f0e..5aa40c7284f1 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-config/hooks/use-cached-metadata.ts @@ -14,12 +14,12 @@ export function useCachedMetadata(config: CacheMetadataPluginConfig): Plugin { return `${workspaceId}:${cacheVersion}`; }; - const operationName = (serverContext: any) => + const getOperationName = (serverContext: any) => serverContext?.req?.body?.operationName; return { onRequest: async ({ endResponse, serverContext }) => { - if (!config.operationsToCache.includes(operationName(serverContext))) { + if (!config.operationsToCache.includes(getOperationName(serverContext))) { return; } @@ -33,6 +33,10 @@ export function useCachedMetadata(config: CacheMetadataPluginConfig): Plugin { } }, onResponse: async ({ response, serverContext }) => { + if (!config.operationsToCache.includes(getOperationName(serverContext))) { + return; + } + const cacheKey = computeCacheKey(serverContext); const cachedResponse = await config.cacheGetter(cacheKey);