@@ -5,6 +5,7 @@ var tls = require('tls');
55var util = require ( 'util' ) ;
66var utils = require ( './lib/utils' ) ;
77var Queue = require ( 'double-ended-queue' ) ;
8+ var CommandError = require ( './lib/customError' ) ;
89var Command = require ( './lib/command' ) . Command ;
910var OfflineCommand = require ( './lib/command' ) . OfflineCommand ;
1011var EventEmitter = require ( 'events' ) ;
@@ -264,11 +265,11 @@ RedisClient.prototype.create_stream = function () {
264265 } ) ;
265266
266267 this . stream . once ( 'close' , function ( hadError ) {
267- self . connection_gone ( 'close' , new Error ( 'Stream connection closed' + ( hadError ? ' because of a transmission error' : '' ) ) ) ;
268+ self . connection_gone ( 'close' , hadError ? new Error ( 'Stream connection closed with a transmission error' ) : null ) ;
268269 } ) ;
269270
270271 this . stream . once ( 'end' , function ( ) {
271- self . connection_gone ( 'end' , new Error ( 'Stream connection ended' ) ) ;
272+ self . connection_gone ( 'end' , null ) ;
272273 } ) ;
273274
274275 this . stream . on ( 'drain' , function ( ) {
@@ -320,16 +321,29 @@ RedisClient.prototype.warn = function (msg) {
320321
321322// Flush provided queues, erroring any items with a callback first
322323RedisClient . prototype . flush_and_error = function ( error , queue_names ) {
324+ var callbacks_not_called = [ ] ;
323325 queue_names = queue_names || [ 'offline_queue' , 'command_queue' ] ;
324326 for ( var i = 0 ; i < queue_names . length ; i ++ ) {
325327 for ( var command_obj = this [ queue_names [ i ] ] . shift ( ) ; command_obj ; command_obj = this [ queue_names [ i ] ] . shift ( ) ) {
328+ var err = new CommandError ( error ) ;
329+ err . command = command_obj . command . toUpperCase ( ) ;
330+ if ( command_obj . args . length ) {
331+ err . args = command_obj . args ;
332+ }
326333 if ( typeof command_obj . callback === 'function' ) {
327- error . command = command_obj . command . toUpperCase ( ) ;
328- command_obj . callback ( error ) ;
334+ command_obj . callback ( err ) ;
335+ } else {
336+ callbacks_not_called . push ( err ) ;
329337 }
330338 }
331339 this [ queue_names [ i ] ] = new Queue ( ) ;
332340 }
341+ // Mutate the original error that will be emitted
342+ // This is fine, as we don't manipulate any user errors
343+ if ( callbacks_not_called . length !== 0 ) {
344+ error . errors = callbacks_not_called ;
345+ }
346+ return callbacks_not_called . length === 0 ;
333347} ;
334348
335349RedisClient . prototype . on_error = function ( err ) {
@@ -546,8 +560,10 @@ RedisClient.prototype.connection_gone = function (why, error) {
546560
547561 // If this is a requested shutdown, then don't retry
548562 if ( this . closing ) {
549- debug ( 'Connection ended from quit command, not retrying.' ) ;
550- this . flush_and_error ( new Error ( 'Redis connection gone from ' + why + ' event.' ) ) ;
563+ debug ( 'Connection ended by quit / end command, not retrying.' ) ;
564+ error = new Error ( 'Stream connection ended and running command aborted. It might have been processed.' ) ;
565+ error . code = 'NR_OFFLINE' ;
566+ this . flush_and_error ( error ) ;
551567 return ;
552568 }
553569
@@ -567,10 +583,18 @@ RedisClient.prototype.connection_gone = function (why, error) {
567583 if ( typeof this . retry_delay !== 'number' ) {
568584 // Pass individual error through
569585 if ( this . retry_delay instanceof Error ) {
570- error = this . retry_delay ;
586+ error = new CommandError ( this . retry_delay ) ;
587+ }
588+ // Attention: there might be the case where there's no error!
589+ if ( ! error ) {
590+ error = new Error ( 'Stream connection ended and running command aborted. It might have been processed.' ) ;
591+ error . code = 'NR_OFFLINE' ;
592+ }
593+ // Only emit an error in case that a running command had no callback
594+ if ( ! this . flush_and_error ( error ) ) {
595+ error . message = 'Stream connection ended and all running commands aborted. They might have been processed.' ;
596+ this . emit ( 'error' , error ) ;
571597 }
572- this . flush_and_error ( error ) ;
573- this . emit ( 'error' , error ) ;
574598 this . end ( false ) ;
575599 return ;
576600 }
@@ -595,11 +619,11 @@ RedisClient.prototype.connection_gone = function (why, error) {
595619 } else if ( this . command_queue . length !== 0 ) {
596620 error = new Error ( 'Redis connection lost and command aborted in uncertain state. It might have been processed.' ) ;
597621 error . code = 'UNCERTAIN_STATE' ;
598- this . flush_and_error ( error , [ 'command_queue' ] ) ;
599- error . message = 'Redis connection lost and commands aborted in uncertain state. They might have been processed.' ;
600- // TODO: Reconsider emitting this always, as each running command is handled anyway
601- // This should likely be removed in v.3. This is different to the broken connection as we'll reconnect here
602- this . emit ( 'error' , error ) ;
622+ if ( ! this . flush_and_error ( error , [ 'command_queue' ] ) ) {
623+ // Only emit if not all commands had a callback that already handled the error
624+ error . message = 'Redis connection lost and commands aborted in uncertain state. They might have been processed.' ;
625+ this . emit ( 'error' , error ) ;
626+ }
603627 }
604628
605629 if ( this . retry_max_delay !== null && this . retry_delay > this . retry_max_delay ) {
@@ -618,6 +642,9 @@ RedisClient.prototype.return_error = function (err) {
618642 var command_obj = this . command_queue . shift ( ) ;
619643 if ( command_obj && command_obj . command && command_obj . command . toUpperCase ) {
620644 err . command = command_obj . command . toUpperCase ( ) ;
645+ if ( command_obj . args . length ) {
646+ err . args = command_obj . args ;
647+ }
621648 }
622649
623650 var match = err . message . match ( utils . err_code ) ;
@@ -786,6 +813,9 @@ function handle_offline_command (self, command_obj) {
786813 }
787814 err = new Error ( command + " can't be processed. " + msg ) ;
788815 err . command = command ;
816+ if ( command_obj . args . length ) {
817+ err . args = command_obj . args ;
818+ }
789819 err . code = 'NR_OFFLINE' ;
790820 utils . reply_in_order ( self , callback , err ) ;
791821 } else {
0 commit comments