@trieb.work/nextjs-turbo-redis-cache
Version:
Next.js redis cache handler
153 lines (149 loc) • 5.69 kB
TypeScript
import { RedisClientOptions } from 'redis';
type CacheEntry = {
value: unknown;
lastModified: number;
tags: string[];
};
type CreateRedisStringsHandlerOptions = {
/** Redis redisUrl to use.
* @default process.env.REDIS_URL? process.env.REDIS_URL : process.env.REDISHOST
? `redis://${process.env.REDISHOST}:${process.env.REDISPORT}`
: 'redis://localhost:6379'
*/
redisUrl?: string;
/** Redis database number to use. Uses DB 0 for production, DB 1 otherwise
* @default process.env.VERCEL_ENV === 'production' ? 0 : 1
*/
database?: number;
/** Prefix added to all Redis keys
* @default process.env.VERCEL_URL || 'UNDEFINED_URL_'
*/
keyPrefix?: string;
/** Timeout in milliseconds for time critical Redis operations (during cache get, which blocks site rendering).
* If redis get is not fulfilled within this time, the cache handler will return null so site rendering will
* not be blocked further and site can fallback to re-render/re-fetch the content.
* @default 500
*/
getTimeoutMs?: number;
/** Number of entries to query in one batch during full sync of shared tags hash map
* @default 250
*/
revalidateTagQuerySize?: number;
/** Key used to store shared tags hash map in Redis
* @default '__sharedTags__'
*/
sharedTagsKey?: string;
/** Average interval in milliseconds between tag map full re-syncs
* @default 3600000 (1 hour)
*/
avgResyncIntervalMs?: number;
/** Enable deduplication of Redis get requests via internal in-memory cache
* @default true
*/
redisGetDeduplication?: boolean;
/** Time in milliseconds to cache Redis get results in memory. Set this to 0 to disable in-memory caching completely
* @default 10000
*/
inMemoryCachingTime?: number;
/** Default stale age in seconds for cached items
* @default 1209600 (14 days)
*/
defaultStaleAge?: number;
/** Function to calculate expire age (redis TTL value) from stale age
* @default Production: staleAge * 2, Other: staleAge * 1.2
*/
estimateExpireAge?: (staleAge: number) => number;
/** Kill container on Redis client error if error threshold is reached
* @default 0 (0 means no error threshold)
*/
killContainerOnErrorThreshold?: number;
/** Additional Redis client socket options
* @example { tls: true, rejectUnauthorized: false }
*/
socketOptions?: RedisClientOptions['socket'];
/** Additional Redis client options to be passed directly to createClient
* @example { username: 'user', password: 'pass' }
*/
clientOptions?: Omit<RedisClientOptions, 'url' | 'database' | 'socket'>;
};
declare class RedisStringsHandler {
private client;
private sharedTagsMap;
private revalidatedTagsMap;
private inMemoryDeduplicationCache;
private getTimeoutMs;
private redisGet;
private redisDeduplicationHandler;
private deduplicatedRedisGet;
private keyPrefix;
private redisGetDeduplication;
private inMemoryCachingTime;
private defaultStaleAge;
private estimateExpireAge;
private killContainerOnErrorThreshold;
constructor({ redisUrl, database, keyPrefix, sharedTagsKey, getTimeoutMs, revalidateTagQuerySize, avgResyncIntervalMs, redisGetDeduplication, inMemoryCachingTime, defaultStaleAge, estimateExpireAge, killContainerOnErrorThreshold, socketOptions, clientOptions, }: CreateRedisStringsHandlerOptions);
resetRequestCache(): void;
private clientReadyCalls;
private assertClientIsReady;
get(key: string, ctx: {
kind: 'APP_ROUTE' | 'APP_PAGE';
isRoutePPREnabled: boolean;
isFallback: boolean;
} | {
kind: 'FETCH';
revalidate: number;
fetchUrl: string;
fetchIdx: number;
tags: string[];
softTags: string[];
isFallback: boolean;
}): Promise<CacheEntry | null>;
set(key: string, data: {
kind: 'APP_PAGE';
status: number;
headers: {
'x-nextjs-stale-time': string;
'x-next-cache-tags': string;
};
html: string;
rscData: Buffer;
segmentData: unknown;
postboned: unknown;
} | {
kind: 'APP_ROUTE';
status: number;
headers: {
'cache-control'?: string;
'x-nextjs-stale-time': string;
'x-next-cache-tags': string;
};
body: Buffer;
} | {
kind: 'FETCH';
data: {
headers: Record<string, string>;
body: string;
status: number;
url: string;
};
revalidate: number | false;
}, ctx: {
isRoutePPREnabled: boolean;
isFallback: boolean;
tags?: string[];
revalidate?: number | false;
cacheControl?: {
revalidate: 5;
expire: undefined;
};
}): Promise<void>;
revalidateTag(tagOrTags: string | string[], ...rest: any[]): Promise<void>;
}
declare class CachedHandler {
constructor(options: CreateRedisStringsHandlerOptions);
get(...args: Parameters<RedisStringsHandler['get']>): ReturnType<RedisStringsHandler['get']>;
set(...args: Parameters<RedisStringsHandler['set']>): ReturnType<RedisStringsHandler['set']>;
revalidateTag(...args: Parameters<RedisStringsHandler['revalidateTag']>): ReturnType<RedisStringsHandler['revalidateTag']>;
resetRequestCache(...args: Parameters<RedisStringsHandler['resetRequestCache']>): ReturnType<RedisStringsHandler['resetRequestCache']>;
}
export { RedisStringsHandler, CachedHandler as default };