@@ -239,12 +239,12 @@ class Connection extends Component
239
239
240
240
/**
241
241
* @var string the hostname or ip address to use for connecting to the redis server. Defaults to 'localhost'.
242
- * If [[unixSocket]] is specified, hostname and port will be ignored.
242
+ * If [[unixSocket]] is specified, hostname and [[ port]] will be ignored.
243
243
*/
244
244
public $ hostname = 'localhost ' ;
245
245
/**
246
246
* @var integer the port to use for connecting to the redis server. Default port is 6379.
247
- * If [[unixSocket]] is specified, hostname and port will be ignored.
247
+ * If [[unixSocket]] is specified, [[ hostname]] and port will be ignored.
248
248
*/
249
249
public $ port = 6379 ;
250
250
/**
@@ -279,6 +279,13 @@ class Connection extends Component
279
279
* @since 2.0.5
280
280
*/
281
281
public $ socketClientFlags = STREAM_CLIENT_CONNECT ;
282
+ /**
283
+ * @var integer The number of times a command execution should be retried when a connection failure occurs.
284
+ * This is used in [[executeCommand()]] when a [[SocketException]] is thrown.
285
+ * Defaults to 0 meaning no retries on failure.
286
+ * @since 2.0.7
287
+ */
288
+ public $ retries = 0 ;
282
289
/**
283
290
* @var array List of available redis commands.
284
291
* @see http://redis.io/commands
@@ -555,7 +562,11 @@ public function close()
555
562
if ($ this ->_socket !== false ) {
556
563
$ connection = ($ this ->unixSocket ?: $ this ->hostname . ': ' . $ this ->port ) . ', database= ' . $ this ->database ;
557
564
\Yii::trace ('Closing DB connection: ' . $ connection , __METHOD__ );
558
- $ this ->executeCommand ('QUIT ' );
565
+ try {
566
+ $ this ->executeCommand ('QUIT ' );
567
+ } catch (SocketException $ e ) {
568
+ // ignore errors when quitting a closed connection
569
+ }
559
570
stream_socket_shutdown ($ this ->_socket , STREAM_SHUT_RDWR );
560
571
$ this ->_socket = false ;
561
572
}
@@ -647,8 +658,38 @@ public function executeCommand($name, $params = [])
647
658
}
648
659
649
660
\Yii::trace ("Executing Redis Command: {$ name }" , __METHOD__ );
650
- fwrite ($ this ->_socket , $ command );
661
+ if ($ this ->retries > 0 ) {
662
+ $ tries = $ this ->retries ;
663
+ while ($ tries -- > 0 ) {
664
+ try {
665
+ return $ this ->sendCommandInternal ($ command , $ params );
666
+ } catch (SocketException $ e ) {
667
+ \Yii::error ($ e , __METHOD__ );
668
+ // backup retries, fail on commands that fail inside here
669
+ $ retries = $ this ->retries ;
670
+ $ this ->retries = 0 ;
671
+ $ this ->close ();
672
+ $ this ->open ();
673
+ $ this ->retries = $ retries ;
674
+ }
675
+ }
676
+ }
677
+ return $ this ->sendCommandInternal ($ command , $ params );
678
+ }
651
679
680
+ /**
681
+ * Sends RAW command string to the server.
682
+ * @throws SocketException on connection error.
683
+ */
684
+ private function sendCommandInternal ($ command , $ params )
685
+ {
686
+ $ written = @fwrite ($ this ->_socket , $ command );
687
+ if ($ written === false ) {
688
+ throw new SocketException ("Failed to write to socket. \nRedis command was: " . $ command );
689
+ }
690
+ if ($ written !== ($ len = mb_strlen ($ command , '8bit ' ))) {
691
+ throw new SocketException ("Failed to write to socket. $ written of $ len bytes written. \nRedis command was: " . $ command );
692
+ }
652
693
return $ this ->parseResponse (implode (' ' , $ params ));
653
694
}
654
695
@@ -660,7 +701,7 @@ public function executeCommand($name, $params = [])
660
701
private function parseResponse ($ command )
661
702
{
662
703
if (($ line = fgets ($ this ->_socket )) === false ) {
663
- throw new Exception ("Failed to read from socket. \nRedis command was: " . $ command );
704
+ throw new SocketException ("Failed to read from socket. \nRedis command was: " . $ command );
664
705
}
665
706
$ type = $ line [0 ];
666
707
$ line = mb_substr ($ line , 1 , -2 , '8bit ' );
@@ -684,7 +725,7 @@ private function parseResponse($command)
684
725
$ data = '' ;
685
726
while ($ length > 0 ) {
686
727
if (($ block = fread ($ this ->_socket , $ length )) === false ) {
687
- throw new Exception ("Failed to read from socket. \nRedis command was: " . $ command );
728
+ throw new SocketException ("Failed to read from socket. \nRedis command was: " . $ command );
688
729
}
689
730
$ data .= $ block ;
690
731
$ length -= mb_strlen ($ block , '8bit ' );
0 commit comments