@@ -103,6 +103,7 @@ function RedisClient (options) {
103103 this . old_state = null ;
104104 this . send_anyway = false ;
105105 this . pipeline = 0 ;
106+ this . times_connected = 0 ;
106107 this . options = options ;
107108 // Init parser
108109 this . reply_parser = new Parser ( {
@@ -145,14 +146,15 @@ RedisClient.prototype.create_stream = function () {
145146 if ( this . options . connect_timeout ) {
146147 this . stream . setTimeout ( this . connect_timeout , function ( ) {
147148 self . retry_totaltime = self . connect_timeout ;
148- self . connection_gone ( 'timeout' ) ;
149+ self . connection_gone ( 'timeout' , new Error ( 'Redis connection gone from timeout event' ) ) ;
149150 } ) ;
150151 }
151152
152153 /* 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' ;
154155 this . stream . once ( connect_event , function ( ) {
155- this . removeAllListeners ( "timeout" ) ;
156+ this . removeAllListeners ( 'timeout' ) ;
157+ self . times_connected ++ ;
156158 self . on_connect ( ) ;
157159 } ) ;
158160
@@ -166,17 +168,18 @@ RedisClient.prototype.create_stream = function () {
166168 self . on_error ( err ) ;
167169 } ) ;
168170
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 */
170172 this . stream . on ( 'clientError' , function ( err ) {
173+ debug ( 'clientError occured' ) ;
171174 self . on_error ( err ) ;
172175 } ) ;
173176
174177 this . stream . once ( 'close' , function ( ) {
175- self . connection_gone ( 'close' ) ;
178+ self . connection_gone ( 'close' , new Error ( 'Stream connection closed' ) ) ;
176179 } ) ;
177180
178181 this . stream . once ( 'end' , function ( ) {
179- self . connection_gone ( 'end' ) ;
182+ self . connection_gone ( 'end' , new Error ( 'Stream connection ended' ) ) ;
180183 } ) ;
181184
182185 this . stream . on ( 'drain' , function ( ) {
@@ -268,10 +271,14 @@ RedisClient.prototype.on_error = function (err) {
268271
269272 this . connected = false ;
270273 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+ }
272279 // 'error' events get turned into exceptions if they aren't listened for. If the user handled this error
273280 // then we should try to reconnect.
274- this . connection_gone ( 'error' ) ;
281+ this . connection_gone ( 'error' , err ) ;
275282} ;
276283
277284RedisClient . prototype . on_connect = function ( ) {
@@ -417,12 +424,15 @@ RedisClient.prototype.send_offline_queue = function () {
417424 this . offline_queue = new Queue ( ) ;
418425} ;
419426
420- var retry_connection = function ( self ) {
427+ var retry_connection = function ( self , error ) {
421428 debug ( 'Retrying connection...' ) ;
422429
423430 self . emit ( 'reconnecting' , {
424431 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
426436 } ) ;
427437
428438 self . retry_totaltime += self . retry_delay ;
@@ -432,8 +442,7 @@ var retry_connection = function (self) {
432442 self . retry_timer = null ;
433443} ;
434444
435- RedisClient . prototype . connection_gone = function ( why ) {
436- var error ;
445+ RedisClient . prototype . connection_gone = function ( why , error ) {
437446 // If a retry is already in progress, just let that happen
438447 if ( this . retry_timer ) {
439448 return ;
@@ -469,6 +478,25 @@ RedisClient.prototype.connection_gone = function (why) {
469478 return ;
470479 }
471480
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+
472500 if ( this . max_attempts !== 0 && this . attempts >= this . max_attempts || this . retry_totaltime >= this . connect_timeout ) {
473501 var message = this . retry_totaltime >= this . connect_timeout ?
474502 'connection timeout exceeded.' :
@@ -502,7 +530,7 @@ RedisClient.prototype.connection_gone = function (why) {
502530
503531 debug ( 'Retry connection in ' + this . retry_delay + ' ms' ) ;
504532
505- this . retry_timer = setTimeout ( retry_connection , this . retry_delay , this ) ;
533+ this . retry_timer = setTimeout ( retry_connection , this . retry_delay , this , error ) ;
506534} ;
507535
508536RedisClient . prototype . return_error = function ( err ) {
0 commit comments