import { type Cluster, Redis, type ClusterNode, type ClusterOptions } from "ioredis"; import { defaultReconnectOnError } from "@internal/redis"; import { logger } from "./services/logger.server"; export type RedisWithClusterOptions = { host?: string; port?: number; username?: string; password?: string; tlsDisabled?: boolean; clusterMode?: boolean; clusterOptions?: Omit; keyPrefix?: string; /** Cap retries for a command before it rejects; `null` means unlimited (default: ioredis's default of 20). */ maxRetriesPerRequest?: number | null; }; export type RedisClient = Redis | Cluster; export function createRedisClient( connectionName: string, options: RedisWithClusterOptions ): Redis | Cluster { let redis: Redis | Cluster; if (options.clusterMode) { const nodes: ClusterNode[] = [ { host: options.host, port: options.port, }, ]; logger.debug("Creating a redis cluster client", { connectionName, host: options.host, port: options.port, }); redis = new Redis.Cluster(nodes, { ...options.clusterOptions, redisOptions: { connectionName, keyPrefix: options.keyPrefix, username: options.username, password: options.password, enableAutoPipelining: true, reconnectOnError: defaultReconnectOnError, ...(options.maxRetriesPerRequest !== undefined ? { maxRetriesPerRequest: options.maxRetriesPerRequest } : {}), ...(options.tlsDisabled ? { checkServerIdentity: () => { // disable TLS verification return undefined; }, } : { tls: {} }), }, dnsLookup: (address, callback) => callback(null, address), slotsRefreshTimeout: 10000, }); } else { logger.debug("Creating a redis client", { connectionName, host: options.host, port: options.port, }); redis = new Redis({ connectionName, host: options.host, port: options.port, username: options.username, password: options.password, enableAutoPipelining: true, keyPrefix: options.keyPrefix, reconnectOnError: defaultReconnectOnError, ...(options.maxRetriesPerRequest !== undefined ? { maxRetriesPerRequest: options.maxRetriesPerRequest } : {}), ...(options.tlsDisabled ? {} : { tls: {} }), }); } redis.on("error", (error) => { logger.error("Redis client error", { connectionName, error }); }); return redis; }