@@ -103,6 +103,7 @@ function RedisClient (options) {
103
103
this . old_state = null ;
104
104
this . send_anyway = false ;
105
105
this . pipeline = 0 ;
106
+ this . times_connected = 0 ;
106
107
this . options = options ;
107
108
// Init parser
108
109
this . reply_parser = new Parser ( {
@@ -145,14 +146,15 @@ RedisClient.prototype.create_stream = function () {
145
146
if ( this . options . connect_timeout ) {
146
147
this . stream . setTimeout ( this . connect_timeout , function ( ) {
147
148
self . retry_totaltime = self . connect_timeout ;
148
- self . connection_gone ( 'timeout' ) ;
149
+ self . connection_gone ( 'timeout' , new Error ( 'Redis connection gone from timeout event' ) ) ;
149
150
} ) ;
150
151
}
151
152
152
153
/* istanbul ignore next: travis does not work with stunnel atm. Therefor the tls tests are skipped on travis */
153
- var connect_event = this . options . tls ? " secureConnect" : " connect" ;
154
+ var connect_event = this . options . tls ? ' secureConnect' : ' connect' ;
154
155
this . stream . once ( connect_event , function ( ) {
155
- this . removeAllListeners ( "timeout" ) ;
156
+ this . removeAllListeners ( 'timeout' ) ;
157
+ self . times_connected ++ ;
156
158
self . on_connect ( ) ;
157
159
} ) ;
158
160
@@ -166,17 +168,18 @@ RedisClient.prototype.create_stream = function () {
166
168
self . on_error ( err ) ;
167
169
} ) ;
168
170
169
- /* istanbul ignore next: travis does not work with stunnel atm. Therefor the tls tests are skipped on travis */
171
+ /* istanbul ignore next: difficult to test and not important as long as we keep this listener */
170
172
this . stream . on ( 'clientError' , function ( err ) {
173
+ debug ( 'clientError occured' ) ;
171
174
self . on_error ( err ) ;
172
175
} ) ;
173
176
174
177
this . stream . once ( 'close' , function ( ) {
175
- self . connection_gone ( 'close' ) ;
178
+ self . connection_gone ( 'close' , new Error ( 'Stream connection closed' ) ) ;
176
179
} ) ;
177
180
178
181
this . stream . once ( 'end' , function ( ) {
179
- self . connection_gone ( 'end' ) ;
182
+ self . connection_gone ( 'end' , new Error ( 'Stream connection ended' ) ) ;
180
183
} ) ;
181
184
182
185
this . stream . on ( 'drain' , function ( ) {
@@ -268,10 +271,14 @@ RedisClient.prototype.on_error = function (err) {
268
271
269
272
this . connected = false ;
270
273
this . ready = false ;
271
- this . emit ( 'error' , err ) ;
274
+
275
+ // Only emit the error if the retry_stategy option is not set
276
+ if ( ! this . options . retry_strategy ) {
277
+ this . emit ( 'error' , err ) ;
278
+ }
272
279
// 'error' events get turned into exceptions if they aren't listened for. If the user handled this error
273
280
// then we should try to reconnect.
274
- this . connection_gone ( 'error' ) ;
281
+ this . connection_gone ( 'error' , err ) ;
275
282
} ;
276
283
277
284
RedisClient . prototype . on_connect = function ( ) {
@@ -417,12 +424,15 @@ RedisClient.prototype.send_offline_queue = function () {
417
424
this . offline_queue = new Queue ( ) ;
418
425
} ;
419
426
420
- var retry_connection = function ( self ) {
427
+ var retry_connection = function ( self , error ) {
421
428
debug ( 'Retrying connection...' ) ;
422
429
423
430
self . emit ( 'reconnecting' , {
424
431
delay : self . retry_delay ,
425
- attempt : self . attempts
432
+ attempt : self . attempts ,
433
+ error : error ,
434
+ times_connected : self . times_connected ,
435
+ total_retry_time : self . retry_totaltime
426
436
} ) ;
427
437
428
438
self . retry_totaltime += self . retry_delay ;
@@ -432,8 +442,7 @@ var retry_connection = function (self) {
432
442
self . retry_timer = null ;
433
443
} ;
434
444
435
- RedisClient . prototype . connection_gone = function ( why ) {
436
- var error ;
445
+ RedisClient . prototype . connection_gone = function ( why , error ) {
437
446
// If a retry is already in progress, just let that happen
438
447
if ( this . retry_timer ) {
439
448
return ;
@@ -469,6 +478,25 @@ RedisClient.prototype.connection_gone = function (why) {
469
478
return ;
470
479
}
471
480
481
+ if ( typeof this . options . retry_strategy === 'function' ) {
482
+ this . retry_delay = this . options . retry_strategy ( {
483
+ attempt : this . attempts ,
484
+ error : error ,
485
+ total_retry_time : this . retry_totaltime ,
486
+ times_connected : this . times_connected
487
+ } ) ;
488
+ if ( typeof this . retry_delay !== 'number' ) {
489
+ // Pass individual error through
490
+ if ( this . retry_delay instanceof Error ) {
491
+ error = this . retry_delay ;
492
+ }
493
+ this . flush_and_error ( error ) ;
494
+ this . emit ( 'error' , error ) ;
495
+ this . end ( false ) ;
496
+ return ;
497
+ }
498
+ }
499
+
472
500
if ( this . max_attempts !== 0 && this . attempts >= this . max_attempts || this . retry_totaltime >= this . connect_timeout ) {
473
501
var message = this . retry_totaltime >= this . connect_timeout ?
474
502
'connection timeout exceeded.' :
@@ -502,7 +530,7 @@ RedisClient.prototype.connection_gone = function (why) {
502
530
503
531
debug ( 'Retry connection in ' + this . retry_delay + ' ms' ) ;
504
532
505
- this . retry_timer = setTimeout ( retry_connection , this . retry_delay , this ) ;
533
+ this . retry_timer = setTimeout ( retry_connection , this . retry_delay , this , error ) ;
506
534
} ;
507
535
508
536
RedisClient . prototype . return_error = function ( err ) {
0 commit comments