@@ -18,11 +18,38 @@ const fs = require('fs');
1818// Set up environment
1919require ( 'dotenv' ) . config ( { path : path . join ( __dirname , '..' , '.env' ) } ) ;
2020
21- const { USE_REDIS , REDIS_URI , REDIS_KEY_PREFIX } = process . env ;
21+ const {
22+ USE_REDIS ,
23+ REDIS_URI ,
24+ REDIS_USERNAME ,
25+ REDIS_PASSWORD ,
26+ REDIS_CA ,
27+ REDIS_KEY_PREFIX ,
28+ USE_REDIS_CLUSTER ,
29+ REDIS_USE_ALTERNATIVE_DNS_LOOKUP ,
30+ } = process . env ;
2231
2332// Simple utility function
2433const isEnabled = ( value ) => value === 'true' || value === true ;
2534
35+ // Helper function to read Redis CA certificate
36+ const getRedisCA = ( ) => {
37+ if ( ! REDIS_CA ) {
38+ return null ;
39+ }
40+ try {
41+ if ( fs . existsSync ( REDIS_CA ) ) {
42+ return fs . readFileSync ( REDIS_CA , 'utf8' ) ;
43+ } else {
44+ console . warn ( `⚠️ Redis CA certificate file not found: ${ REDIS_CA } ` ) ;
45+ return null ;
46+ }
47+ } catch ( error ) {
48+ console . error ( `❌ Failed to read Redis CA certificate file '${ REDIS_CA } ':` , error . message ) ;
49+ return null ;
50+ }
51+ } ;
52+
2653async function showHelp ( ) {
2754 console . log ( `
2855LibreChat Cache Flush Utility
@@ -67,21 +94,67 @@ async function flushRedisCache(dryRun = false, verbose = false) {
6794 console . log ( ` Prefix: ${ REDIS_KEY_PREFIX || 'None' } ` ) ;
6895 }
6996
70- // Create Redis client directly
71- const Redis = require ( 'ioredis' ) ;
97+ // Create Redis client using same pattern as main app
98+ const IoRedis = require ( 'ioredis' ) ;
7299 let redis ;
73100
74- // Handle cluster vs single Redis
75- if ( process . env . USE_REDIS_CLUSTER === 'true' ) {
76- const hosts = REDIS_URI . split ( ',' ) . map ( ( uri ) => {
77- const [ host , port ] = uri . split ( ':' ) ;
78- return { host, port : parseInt ( port ) || 6379 } ;
79- } ) ;
80- redis = new Redis . Cluster ( hosts ) ;
101+ // Parse credentials from URI or use environment variables (same as redisClients.ts)
102+ const urls = ( REDIS_URI || '' ) . split ( ',' ) . map ( ( uri ) => new URL ( uri ) ) ;
103+ const username = urls [ 0 ] ?. username || REDIS_USERNAME ;
104+ const password = urls [ 0 ] ?. password || REDIS_PASSWORD ;
105+ const ca = getRedisCA ( ) ;
106+
107+ // Redis options (matching redisClients.ts configuration)
108+ const redisOptions = {
109+ username : username ,
110+ password : password ,
111+ tls : ca ? { ca } : undefined ,
112+ connectTimeout : 10000 ,
113+ maxRetriesPerRequest : 3 ,
114+ enableOfflineQueue : true ,
115+ lazyConnect : false ,
116+ } ;
117+
118+ // Handle cluster vs single Redis (same logic as redisClients.ts)
119+ const useCluster = urls . length > 1 || isEnabled ( USE_REDIS_CLUSTER ) ;
120+
121+ if ( useCluster ) {
122+ const clusterOptions = {
123+ redisOptions,
124+ enableOfflineQueue : true ,
125+ } ;
126+
127+ // Add DNS lookup for AWS ElastiCache if needed (same as redisClients.ts)
128+ if ( isEnabled ( REDIS_USE_ALTERNATIVE_DNS_LOOKUP ) ) {
129+ clusterOptions . dnsLookup = ( address , callback ) => callback ( null , address ) ;
130+ }
131+
132+ redis = new IoRedis . Cluster (
133+ urls . map ( ( url ) => ( { host : url . hostname , port : parseInt ( url . port , 10 ) || 6379 } ) ) ,
134+ clusterOptions ,
135+ ) ;
81136 } else {
82- redis = new Redis ( REDIS_URI ) ;
137+ // @ts -ignore - ioredis default export is constructable despite linter warning
138+ redis = new IoRedis ( REDIS_URI , redisOptions ) ;
83139 }
84140
141+ // Wait for connection
142+ await new Promise ( ( resolve , reject ) => {
143+ const timeout = setTimeout ( ( ) => {
144+ reject ( new Error ( 'Connection timeout' ) ) ;
145+ } , 10000 ) ;
146+
147+ redis . once ( 'ready' , ( ) => {
148+ clearTimeout ( timeout ) ;
149+ resolve ( undefined ) ;
150+ } ) ;
151+
152+ redis . once ( 'error' , ( err ) => {
153+ clearTimeout ( timeout ) ;
154+ reject ( err ) ;
155+ } ) ;
156+ } ) ;
157+
85158 if ( dryRun ) {
86159 console . log ( '🔍 [DRY RUN] Would flush Redis cache' ) ;
87160 try {
@@ -105,7 +178,7 @@ async function flushRedisCache(dryRun = false, verbose = false) {
105178 try {
106179 const keys = await redis . keys ( '*' ) ;
107180 keyCount = keys . length ;
108- } catch ( error ) {
181+ } catch ( _error ) {
109182 // Continue with flush even if we can't count keys
110183 }
111184
@@ -209,7 +282,7 @@ async function main() {
209282 }
210283
211284 let success = true ;
212- const isRedisEnabled = isEnabled ( USE_REDIS ) && REDIS_URI ;
285+ const isRedisEnabled = isEnabled ( USE_REDIS ) || ( REDIS_URI != null && REDIS_URI !== '' ) ;
213286
214287 // Flush the appropriate cache type
215288 if ( isRedisEnabled ) {
0 commit comments