From 6a4afb2cc4311d46fee60c9b197680ff82850428 Mon Sep 17 00:00:00 2001 From: Fabrizio Ruggeri Date: Wed, 2 Apr 2025 19:55:57 +0200 Subject: [PATCH 1/3] Set redis cache in seconds Redis cache for response-cache should follow the same ttl meaning of the related plugin, so ttl should be in seconds --- .../response-cache-redis/src/redis-cache.ts | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/plugins/response-cache-redis/src/redis-cache.ts b/packages/plugins/response-cache-redis/src/redis-cache.ts index 3b8f111778..1cb1970495 100644 --- a/packages/plugins/response-cache-redis/src/redis-cache.ts +++ b/packages/plugins/response-cache-redis/src/redis-cache.ts @@ -1,8 +1,11 @@ -import Redis from 'ioredis'; -import type { Cache } from '@envelop/response-cache'; -import { handleMaybePromise } from '@whatwg-node/promise-helpers'; - -export type BuildRedisEntityId = (typename: string, id: number | string) => string; +import Redis from "ioredis"; +import type { Cache } from "@envelop/response-cache"; +import { handleMaybePromise } from "@whatwg-node/promise-helpers"; + +export type BuildRedisEntityId = ( + typename: string, + id: number | string +) => string; export type BuildRedisOperationResultCacheKey = (responseId: string) => string; export type RedisCacheParameter = { @@ -26,30 +29,34 @@ export type RedisCacheParameter = { export const createRedisCache = (params: RedisCacheParameter): Cache => { const store = params.redis; - const buildRedisEntityId = params?.buildRedisEntityId ?? defaultBuildRedisEntityId; + const buildRedisEntityId = + params?.buildRedisEntityId ?? defaultBuildRedisEntityId; const buildRedisOperationResultCacheKey = - params?.buildRedisOperationResultCacheKey ?? defaultBuildRedisOperationResultCacheKey; + params?.buildRedisOperationResultCacheKey ?? + defaultBuildRedisOperationResultCacheKey; - async function buildEntityInvalidationsKeys(entity: string): Promise { + async function buildEntityInvalidationsKeys( + entity: string + ): Promise { const keysToInvalidate: string[] = [entity]; // find the responseIds for the entity const responseIds = await store.smembers(entity); // and add each response to be invalidated since they contained the entity data - responseIds.forEach(responseId => { + responseIds.forEach((responseId) => { keysToInvalidate.push(responseId); keysToInvalidate.push(buildRedisOperationResultCacheKey(responseId)); }); // if invalidating an entity like Comment, then also invalidate Comment:1, Comment:2, etc - if (!entity.includes(':')) { + if (!entity.includes(":")) { const entityKeys = await store.keys(`${entity}:*`); for (const entityKey of entityKeys) { // and invalidate any responses in each of those entity keys const entityResponseIds = await store.smembers(entityKey); // if invalidating an entity check for associated operations containing that entity // and invalidate each response since they contained the entity data - entityResponseIds.forEach(responseId => { + entityResponseIds.forEach((responseId) => { keysToInvalidate.push(responseId); keysToInvalidate.push(buildRedisOperationResultCacheKey(responseId)); }); @@ -70,7 +77,7 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { pipeline.set(responseId, JSON.stringify(result)); } else { // set the ttl in milliseconds - pipeline.set(responseId, JSON.stringify(result), 'PX', ttl); + pipeline.set(responseId, JSON.stringify(result), "EX", ttl); } const responseKey = buildRedisOperationResultCacheKey(responseId); @@ -95,7 +102,7 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { get(responseId) { return handleMaybePromise( () => store.get(responseId), - (result: any) => (result ? JSON.parse(result) : undefined), + (result: any) => (result ? JSON.parse(result) : undefined) ); }, async invalidate(entitiesToRemove) { @@ -104,8 +111,8 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { for (const { typename, id } of entitiesToRemove) { invalidationKeys.push( await buildEntityInvalidationsKeys( - id != null ? buildRedisEntityId(typename, id) : typename, - ), + id != null ? buildRedisEntityId(typename, id) : typename + ) ); } @@ -117,6 +124,7 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { }; }; -export const defaultBuildRedisEntityId: BuildRedisEntityId = (typename, id) => `${typename}:${id}`; +export const defaultBuildRedisEntityId: BuildRedisEntityId = (typename, id) => + `${typename}:${id}`; export const defaultBuildRedisOperationResultCacheKey: BuildRedisOperationResultCacheKey = - responseId => `operations:${responseId}`; + (responseId) => `operations:${responseId}`; From c1b15962534d82706a30bc450ce8c5d5afe47fe3 Mon Sep 17 00:00:00 2001 From: Fabrizio Ruggeri Date: Wed, 14 May 2025 10:53:21 +0200 Subject: [PATCH 2/3] Remove badly formatted code --- .../response-cache-redis/src/redis-cache.ts | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/packages/plugins/response-cache-redis/src/redis-cache.ts b/packages/plugins/response-cache-redis/src/redis-cache.ts index 1cb1970495..487390033c 100644 --- a/packages/plugins/response-cache-redis/src/redis-cache.ts +++ b/packages/plugins/response-cache-redis/src/redis-cache.ts @@ -1,11 +1,8 @@ -import Redis from "ioredis"; -import type { Cache } from "@envelop/response-cache"; -import { handleMaybePromise } from "@whatwg-node/promise-helpers"; - -export type BuildRedisEntityId = ( - typename: string, - id: number | string -) => string; +import Redis from 'ioredis'; +import type { Cache } from '@envelop/response-cache'; +import { handleMaybePromise } from '@whatwg-node/promise-helpers'; + +export type BuildRedisEntityId = (typename: string, id: number | string) => string; export type BuildRedisOperationResultCacheKey = (responseId: string) => string; export type RedisCacheParameter = { @@ -29,34 +26,30 @@ export type RedisCacheParameter = { export const createRedisCache = (params: RedisCacheParameter): Cache => { const store = params.redis; - const buildRedisEntityId = - params?.buildRedisEntityId ?? defaultBuildRedisEntityId; + const buildRedisEntityId = params?.buildRedisEntityId ?? defaultBuildRedisEntityId; const buildRedisOperationResultCacheKey = - params?.buildRedisOperationResultCacheKey ?? - defaultBuildRedisOperationResultCacheKey; + params?.buildRedisOperationResultCacheKey ?? defaultBuildRedisOperationResultCacheKey; - async function buildEntityInvalidationsKeys( - entity: string - ): Promise { + async function buildEntityInvalidationsKeys(entity: string): Promise { const keysToInvalidate: string[] = [entity]; // find the responseIds for the entity const responseIds = await store.smembers(entity); // and add each response to be invalidated since they contained the entity data - responseIds.forEach((responseId) => { + responseIds.forEach(responseId => { keysToInvalidate.push(responseId); keysToInvalidate.push(buildRedisOperationResultCacheKey(responseId)); }); // if invalidating an entity like Comment, then also invalidate Comment:1, Comment:2, etc - if (!entity.includes(":")) { + if (!entity.includes(':')) { const entityKeys = await store.keys(`${entity}:*`); for (const entityKey of entityKeys) { // and invalidate any responses in each of those entity keys const entityResponseIds = await store.smembers(entityKey); // if invalidating an entity check for associated operations containing that entity // and invalidate each response since they contained the entity data - entityResponseIds.forEach((responseId) => { + entityResponseIds.forEach(responseId => { keysToInvalidate.push(responseId); keysToInvalidate.push(buildRedisOperationResultCacheKey(responseId)); }); @@ -77,7 +70,7 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { pipeline.set(responseId, JSON.stringify(result)); } else { // set the ttl in milliseconds - pipeline.set(responseId, JSON.stringify(result), "EX", ttl); + pipeline.set(responseId, JSON.stringify(result), 'EX', ttl); } const responseKey = buildRedisOperationResultCacheKey(responseId); @@ -102,7 +95,7 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { get(responseId) { return handleMaybePromise( () => store.get(responseId), - (result: any) => (result ? JSON.parse(result) : undefined) + (result: any) => (result ? JSON.parse(result) : undefined), ); }, async invalidate(entitiesToRemove) { @@ -111,8 +104,8 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { for (const { typename, id } of entitiesToRemove) { invalidationKeys.push( await buildEntityInvalidationsKeys( - id != null ? buildRedisEntityId(typename, id) : typename - ) + id != null ? buildRedisEntityId(typename, id) : typename, + ), ); } @@ -124,7 +117,6 @@ export const createRedisCache = (params: RedisCacheParameter): Cache => { }; }; -export const defaultBuildRedisEntityId: BuildRedisEntityId = (typename, id) => - `${typename}:${id}`; +export const defaultBuildRedisEntityId: BuildRedisEntityId = (typename, id) => `${typename}:${id}`; export const defaultBuildRedisOperationResultCacheKey: BuildRedisOperationResultCacheKey = - (responseId) => `operations:${responseId}`; + responseId => `operations:${responseId}`; From 0e5aa95b43371fa24285d2c207b49a421d5c28a0 Mon Sep 17 00:00:00 2001 From: Fabrizio Ruggeri Date: Thu, 15 May 2025 13:12:18 +0200 Subject: [PATCH 3/3] Updated tests --- .../test/response-redis-cache.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/plugins/response-cache-redis/test/response-redis-cache.spec.ts b/packages/plugins/response-cache-redis/test/response-redis-cache.spec.ts index 59fbaad47e..53f8b96725 100644 --- a/packages/plugins/response-cache-redis/test/response-redis-cache.spec.ts +++ b/packages/plugins/response-cache-redis/test/response-redis-cache.spec.ts @@ -797,8 +797,8 @@ describeIf(versionInfo.major >= 16)('useResponseCache with Redis cache', () => { // so queried just once expect(spy).toHaveBeenCalledTimes(1); - // let's travel in time beyond the ttl of 100 - jest.advanceTimersByTime(150); + // let's travel in time beyond the ttl of 100 seconds + jest.advanceTimersByTime(150_000); // since the cache has expired, now when we query await testInstance.execute(query); @@ -1083,8 +1083,8 @@ describeIf(versionInfo.major >= 16)('useResponseCache with Redis cache', () => { await testInstance.execute(query); expect(spy).toHaveBeenCalledTimes(1); - // wait so User expires - jest.advanceTimersByTime(201); + // wait so User expires, beyond 200 seconds + jest.advanceTimersByTime(201_000); await testInstance.execute(query); // now we've queried twice @@ -1174,8 +1174,8 @@ describeIf(versionInfo.major >= 16)('useResponseCache with Redis cache', () => { await testInstance.execute(query); expect(spy).toHaveBeenCalledTimes(1); - // wait so User expires - jest.advanceTimersByTime(201); + // wait so User expires beyond 200 seconds + jest.advanceTimersByTime(201_000); await testInstance.execute(query); // now we've queried twice