22
33namespace Monospice \LaravelRedisSentinel \Connections ;
44
5+ use Closure ;
56use Illuminate \Redis \Connections \PhpRedisConnection as LaravelPhpRedisConnection ;
67use Redis ;
78use RedisException ;
89
910/**
1011 * Executes Redis commands using the PhpRedis client.
1112 *
12- * This package extends Laravel's PhpRedisConnection class to work around issues
13- * experienced when using the PhpRedis client to send commands over "aggregate"
14- * connections (in this case, Sentinel connections).
13+ * This package extends Laravel's PhpRedisConnection class to wrap all command
14+ * methods with a retryOnFailure method.
1515 *
1616 * @category Package
1717 * @package Monospice\LaravelRedisSentinel
18- * @author @pdbreen, Cy Rossignol <cy@rossignols.me >
18+ * @author Jeffrey Zant <j.zant@slash2.nl >
1919 * @license See LICENSE file
2020 * @link https://github.com/monospice/laravel-redis-sentinel-drivers
2121 */
@@ -54,33 +54,137 @@ public function __construct($client, callable $connector = null, array $sentinel
5454 }
5555
5656 /**
57- * Execute commands in a transaction.
57+ * {@inheritdoc} in addition retry on client failure.
58+ *
59+ * @param mixed $cursor
60+ * @param array $options
61+ * @return mixed
62+ */
63+ public function scan ($ cursor , $ options = [])
64+ {
65+ return $ this ->retryOnFailure (function () use ($ cursor , $ options ) {
66+ return parent ::scan ($ cursor , $ options );
67+ });
68+ }
69+
70+ /**
71+ * {@inheritdoc} in addition retry on client failure.
72+ *
73+ * @param string $key
74+ * @param mixed $cursor
75+ * @param array $options
76+ * @return mixed
77+ */
78+ public function zscan ($ key , $ cursor , $ options = [])
79+ {
80+ return $ this ->retryOnFailure (function () use ($ key , $ cursor , $ options ) {
81+ parent ::zscan ($ key , $ cursor , $ options );
82+ });
83+ }
84+
85+ /**
86+ * {@inheritdoc} in addition retry on client failure.
87+ *
88+ * @param string $key
89+ * @param mixed $cursor
90+ * @param array $options
91+ * @return mixed
92+ */
93+ public function hscan ($ key , $ cursor , $ options = [])
94+ {
95+ return $ this ->retryOnFailure (function () use ($ key , $ cursor , $ options ) {
96+ parent ::hscan ($ key , $ cursor , $ options );
97+ });
98+ }
99+
100+ /**
101+ * {@inheritdoc} in addition retry on client failure.
102+ *
103+ * @param string $key
104+ * @param mixed $cursor
105+ * @param array $options
106+ * @return mixed
107+ */
108+ public function sscan ($ key , $ cursor , $ options = [])
109+ {
110+ return $ this ->retryOnFailure (function () use ($ key , $ cursor , $ options ) {
111+ parent ::sscan ($ key , $ cursor , $ options );
112+ });
113+ }
114+
115+ /**
116+ * {@inheritdoc} in addition retry on client failure.
117+ *
118+ * @param callable|null $callback
119+ * @return \Redis|array
120+ */
121+ public function pipeline (callable $ callback = null )
122+ {
123+ return $ this ->retryOnFailure (function () use ($ callback ) {
124+ return parent ::pipeline ($ callback );
125+ });
126+ }
127+
128+ /**
129+ * {@inheritdoc} in addition retry on client failure.
58130 *
59131 * @param callable|null $callback
60132 * @return \Redis|array
61133 */
62134 public function transaction (callable $ callback = null )
63135 {
64136 return $ this ->retryOnFailure (function () use ($ callback ) {
65- $ transaction = $ this ->client ()->multi ();
137+ return parent ::transaction ($ callback );
138+ });
139+ }
66140
67- return is_null ($ callback )
68- ? $ transaction
69- : tap ($ transaction , $ callback )->exec ();
141+ /**
142+ * {@inheritdoc} in addition retry on client failure.
143+ *
144+ * @param array|string $channels
145+ * @param \Closure $callback
146+ * @return void
147+ */
148+ public function subscribe ($ channels , Closure $ callback )
149+ {
150+ return $ this ->retryOnFailure (function () use ($ channels , $ callback ) {
151+ return parent ::subscribe ($ channels , $ callback );
70152 });
71153 }
154+
155+ /**
156+ * {@inheritdoc} in addition retry on client failure.
157+ *
158+ * @param array|string $channels
159+ * @param \Closure $callback
160+ * @return void
161+ */
162+ public function psubscribe ($ channels , Closure $ callback )
163+ {
164+ return $ this ->retryOnFailure (function () use ($ channels , $ callback ) {
165+ return parent ::psubscribe ($ channels , $ callback );
166+ });
167+ }
168+
169+ /**
170+ * {@inheritdoc} in addition retry on client failure.
171+ *
172+ * @param string $method
173+ * @param array $parameters
174+ * @return mixed
175+ */
176+ public function command ($ method , array $ parameters = [])
177+ {
178+ return $ this ->retryOnFailure (function () use ($ method , $ parameters ) {
179+ return parent ::command ($ method , $ parameters );
180+ });
181+ }
182+
72183 /**
73184 * Attempt to retry the provided operation when the client fails to connect
74185 * to a Redis server.
75186 *
76- * We adapt Predis' Sentinel connection failure handling logic here to
77- * reproduce the high-availability mode provided by the actual client. To
78- * work around "aggregate" connection limitations in Predis, this class
79- * provides methods that don't use the high-level Sentinel connection API
80- * of Predis directly, so it needs to handle connection failures itself.
81- *
82187 * @param callable $callback The operation to execute.
83- *
84188 * @return mixed The result of the first successful attempt.
85189 *
86190 * @throws RedisException After exhausting the allowed number of
@@ -98,7 +202,12 @@ protected function retryOnFailure(callable $callback)
98202
99203 usleep ($ this ->retryWait * 1000 );
100204
101- $ this ->client = $ this ->connector ();
205+ try {
206+ $ this ->client = $ this ->connector ();
207+ } catch (RedisException $ e ) {
208+ // Ignore the the creation of a new client gets an exception.
209+ // If this exception isn't caught the retry will stop.
210+ }
102211
103212 $ attempts ++;
104213 }
0 commit comments