@@ -164,16 +164,21 @@ export class RedisConnectionFactory {
164
164
options : IRedisConnectionOptions ,
165
165
) : Promise < Redis > {
166
166
let tnl ;
167
+ let connection : Redis ;
167
168
168
169
try {
169
170
const config = await this . getRedisOptions ( clientMetadata , database , options ) ;
171
+ // cover cases when we are connecting to sentinel using standalone client to discover master groups
172
+ const dbIndex = config . db > 0 && ! database . sentinelMaster ? config . db : 0 ;
170
173
171
174
if ( database . ssh ) {
172
175
tnl = await this . sshTunnelProvider . createTunnel ( database ) ;
173
176
}
174
177
175
178
return await new Promise ( ( resolve , reject ) => {
176
179
try {
180
+ let lastError : Error ;
181
+
177
182
if ( tnl ) {
178
183
tnl . on ( 'error' , ( error ) => {
179
184
reject ( error ) ;
@@ -187,31 +192,42 @@ export class RedisConnectionFactory {
187
192
config . port = tnl . serverAddress . port ;
188
193
}
189
194
190
- const connection = new Redis ( {
195
+ connection = new Redis ( {
191
196
...config ,
192
- // cover cases when we are connecting to sentinel as to standalone to discover master groups
193
- db : config . db > 0 && ! database . sentinelMaster ? config . db : 0 ,
197
+ db : 0 ,
194
198
} ) ;
195
199
connection . on ( 'error' , ( e ) : void => {
196
200
this . logger . error ( 'Failed connection to the redis database.' , e ) ;
197
- reject ( e ) ;
201
+ lastError = e ;
198
202
} ) ;
199
203
connection . on ( 'end' , ( ) : void => {
200
- this . logger . error ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ;
201
- reject ( new InternalServerErrorException ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ) ;
204
+ this . logger . error ( ERROR_MESSAGES . UNABLE_TO_ESTABLISH_CONNECTION , lastError ) ;
205
+ reject ( lastError || new InternalServerErrorException ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ) ;
202
206
} ) ;
203
207
connection . on ( 'ready' , ( ) : void => {
208
+ lastError = null ;
204
209
this . logger . log ( 'Successfully connected to the redis database' ) ;
205
- resolve ( connection ) ;
210
+
211
+ // manual switch to particular logical db
212
+ // since ioredis doesn't handle "select" command error during connection
213
+ if ( dbIndex > 0 ) {
214
+ connection . select ( dbIndex )
215
+ . then ( ( ) => resolve ( connection ) )
216
+ . catch ( reject ) ;
217
+ } else {
218
+ resolve ( connection ) ;
219
+ }
206
220
} ) ;
207
221
connection . on ( 'reconnecting' , ( ) : void => {
208
- this . logger . log ( 'Reconnecting to the redis database' ) ;
222
+ lastError = null ;
223
+ this . logger . log ( ERROR_MESSAGES . RECONNECTING_TO_DATABASE ) ;
209
224
} ) ;
210
225
} catch ( e ) {
211
226
reject ( e ) ;
212
227
}
213
228
} ) as Redis ;
214
229
} catch ( e ) {
230
+ connection ?. disconnect ?.( ) ;
215
231
tnl ?. close ?.( ) ;
216
232
throw e ;
217
233
}
@@ -228,36 +244,63 @@ export class RedisConnectionFactory {
228
244
database : Database ,
229
245
options : IRedisConnectionOptions ,
230
246
) : Promise < Cluster > {
231
- const config = await this . getRedisClusterOptions ( clientMetadata , database , options ) ;
247
+ let connection : Cluster ;
232
248
233
- if ( database . ssh ) {
234
- throw new Error ( 'SSH is unsupported for cluster databases.' ) ;
235
- }
249
+ try {
250
+ const config = await this . getRedisClusterOptions ( clientMetadata , database , options ) ;
236
251
237
- return new Promise ( ( resolve , reject ) => {
238
- try {
239
- const cluster = new Cluster ( [ {
240
- host : database . host ,
241
- port : database . port ,
242
- } ] . concat ( database . nodes ) , {
243
- ...config ,
244
- } ) ;
245
- cluster . on ( 'error' , ( e ) : void => {
246
- this . logger . error ( 'Failed connection to the redis oss cluster' , e ) ;
247
- reject ( ! isEmpty ( e . lastNodeError ) ? e . lastNodeError : e ) ;
248
- } ) ;
249
- cluster . on ( 'end' , ( ) : void => {
250
- this . logger . error ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ;
251
- reject ( new InternalServerErrorException ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ) ;
252
- } ) ;
253
- cluster . on ( 'ready' , ( ) : void => {
254
- this . logger . log ( 'Successfully connected to the redis oss cluster.' ) ;
255
- resolve ( cluster ) ;
256
- } ) ;
257
- } catch ( e ) {
258
- reject ( e ) ;
252
+ if ( database . ssh ) {
253
+ throw new Error ( 'SSH is unsupported for cluster databases.' ) ;
259
254
}
260
- } ) ;
255
+
256
+ return await ( new Promise ( ( resolve , reject ) => {
257
+ try {
258
+ let lastError : Error ;
259
+
260
+ connection = new Cluster ( [ {
261
+ host : database . host ,
262
+ port : database . port ,
263
+ } ] . concat ( database . nodes ) , {
264
+ ...config ,
265
+ redisOptions : {
266
+ ...config . redisOptions ,
267
+ db : 0 ,
268
+ } ,
269
+ } ) ;
270
+ connection . on ( 'error' , ( e ) : void => {
271
+ this . logger . error ( 'Failed connection to the redis oss cluster' , e ) ;
272
+ lastError = ! isEmpty ( e . lastNodeError ) ? e . lastNodeError : e ;
273
+ } ) ;
274
+ connection . on ( 'end' , ( ) : void => {
275
+ this . logger . error ( ERROR_MESSAGES . UNABLE_TO_ESTABLISH_CONNECTION , lastError ) ;
276
+ reject ( lastError || new InternalServerErrorException ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ) ;
277
+ } ) ;
278
+ connection . on ( 'ready' , ( ) : void => {
279
+ lastError = null ;
280
+ this . logger . log ( 'Successfully connected to the redis oss cluster.' ) ;
281
+
282
+ // manual switch to particular logical db
283
+ // since ioredis doesn't handle "select" command error during connection
284
+ if ( config . redisOptions . db > 0 ) {
285
+ connection . select ( config . redisOptions . db )
286
+ . then ( ( ) => resolve ( connection ) )
287
+ . catch ( reject ) ;
288
+ } else {
289
+ resolve ( connection ) ;
290
+ }
291
+ } ) ;
292
+ connection . on ( 'reconnecting' , ( ) : void => {
293
+ lastError = null ;
294
+ this . logger . log ( ERROR_MESSAGES . RECONNECTING_TO_DATABASE ) ;
295
+ } ) ;
296
+ } catch ( e ) {
297
+ reject ( e ) ;
298
+ }
299
+ } ) ) ;
300
+ } catch ( e ) {
301
+ connection ?. disconnect ?.( ) ;
302
+ throw e ;
303
+ }
261
304
}
262
305
263
306
/**
@@ -271,27 +314,53 @@ export class RedisConnectionFactory {
271
314
database : Database ,
272
315
options : IRedisConnectionOptions ,
273
316
) : Promise < Redis > {
274
- const config = await this . getRedisSentinelOptions ( clientMetadata , database , options ) ;
317
+ let connection : Redis ;
275
318
276
- return new Promise ( ( resolve , reject ) => {
277
- try {
278
- const client = new Redis ( config ) ;
279
- client . on ( 'error' , ( e ) : void => {
280
- this . logger . error ( 'Failed connection to the redis oss sentinel' , e ) ;
319
+ try {
320
+ const config = await this . getRedisSentinelOptions ( clientMetadata , database , options ) ;
321
+
322
+ return await ( new Promise ( ( resolve , reject ) => {
323
+ try {
324
+ let lastError : Error ;
325
+
326
+ connection = new Redis ( {
327
+ ...config ,
328
+ db : 0 ,
329
+ } ) ;
330
+ connection . on ( 'error' , ( e ) : void => {
331
+ this . logger . error ( 'Failed connection to the redis oss sentinel' , e ) ;
332
+ lastError = e ;
333
+ } ) ;
334
+ connection . on ( 'end' , ( ) : void => {
335
+ this . logger . error ( ERROR_MESSAGES . UNABLE_TO_ESTABLISH_CONNECTION , lastError ) ;
336
+ reject ( lastError || new InternalServerErrorException ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ) ;
337
+ } ) ;
338
+ connection . on ( 'ready' , ( ) : void => {
339
+ lastError = null ;
340
+ this . logger . log ( 'Successfully connected to the redis oss sentinel.' ) ;
341
+
342
+ // manual switch to particular logical db
343
+ // since ioredis doesn't handle "select" command error during connection
344
+ if ( config . db > 0 ) {
345
+ connection . select ( config . db )
346
+ . then ( ( ) => resolve ( connection ) )
347
+ . catch ( reject ) ;
348
+ } else {
349
+ resolve ( connection ) ;
350
+ }
351
+ } ) ;
352
+ connection . on ( 'reconnecting' , ( ) : void => {
353
+ lastError = null ;
354
+ this . logger . log ( ERROR_MESSAGES . RECONNECTING_TO_DATABASE ) ;
355
+ } ) ;
356
+ } catch ( e ) {
281
357
reject ( e ) ;
282
- } ) ;
283
- client . on ( 'end' , ( ) : void => {
284
- this . logger . error ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ;
285
- reject ( new InternalServerErrorException ( ERROR_MESSAGES . SERVER_CLOSED_CONNECTION ) ) ;
286
- } ) ;
287
- client . on ( 'ready' , ( ) : void => {
288
- this . logger . log ( 'Successfully connected to the redis oss sentinel.' ) ;
289
- resolve ( client ) ;
290
- } ) ;
291
- } catch ( e ) {
292
- reject ( e ) ;
293
- }
294
- } ) ;
358
+ }
359
+ } ) ) ;
360
+ } catch ( e ) {
361
+ connection ?. disconnect ?.( ) ;
362
+ throw e ;
363
+ }
295
364
}
296
365
297
366
/**
0 commit comments