@@ -29,6 +29,8 @@ class RedisStore implements SharedLockStoreInterface
2929{
3030 use ExpiringStoreTrait;
3131
32+ private const NO_SCRIPT_ERROR_MESSAGE = 'NOSCRIPT No matching script. Please use EVAL. ' ;
33+
3234 private bool $ supportTime ;
3335
3436 /**
@@ -226,11 +228,32 @@ public function exists(Key $key): bool
226228
227229 private function evaluate (string $ script , string $ resource , array $ args ): mixed
228230 {
231+ $ scriptSha = sha1 ($ script );
232+
229233 if ($ this ->redis instanceof \Redis || $ this ->redis instanceof Relay || $ this ->redis instanceof \RedisCluster) {
230234 $ this ->redis ->clearLastError ();
231- $ result = $ this ->redis ->eval ($ script , array_merge ([$ resource ], $ args ), 1 );
232- if (null !== $ err = $ this ->redis ->getLastError ()) {
233- throw new LockStorageException ($ err );
235+
236+ $ result = $ this ->redis ->evalSha ($ scriptSha , array_merge ([$ resource ], $ args ), 1 );
237+ if (self ::NO_SCRIPT_ERROR_MESSAGE === $ err = $ this ->redis ->getLastError ()) {
238+ $ this ->redis ->clearLastError ();
239+
240+ if ($ this ->redis instanceof \RedisCluster) {
241+ foreach ($ this ->redis ->_masters () as $ master ) {
242+ $ this ->redis ->script ($ master , 'LOAD ' , $ script );
243+ }
244+ } else {
245+ $ this ->redis ->script ('LOAD ' , $ script );
246+ }
247+
248+ if (null !== $ err = $ this ->redis ->getLastError ()) {
249+ throw new LockStorageException ($ err );
250+ }
251+
252+ $ result = $ this ->redis ->evalSha ($ scriptSha , array_merge ([$ resource ], $ args ), 1 );
253+
254+ if (null !== $ err = $ this ->redis ->getLastError ()) {
255+ throw new LockStorageException ($ err );
256+ }
234257 }
235258
236259 return $ result ;
@@ -239,9 +262,21 @@ private function evaluate(string $script, string $resource, array $args): mixed
239262 if ($ this ->redis instanceof \RedisArray) {
240263 $ client = $ this ->redis ->_instance ($ this ->redis ->_target ($ resource ));
241264 $ client ->clearLastError ();
242- $ result = $ client ->eval ($ script , array_merge ([$ resource ], $ args ), 1 );
243- if (null !== $ err = $ client ->getLastError ()) {
244- throw new LockStorageException ($ err );
265+ $ result = $ client ->evalSha ($ scriptSha , array_merge ([$ resource ], $ args ), 1 );
266+ if (self ::NO_SCRIPT_ERROR_MESSAGE === $ err = $ client ->getLastError ()) {
267+ $ client ->clearLastError ();
268+
269+ $ client ->script ('LOAD ' , $ script );
270+
271+ if (null !== $ err = $ client ->getLastError ()) {
272+ throw new LockStorageException ($ err );
273+ }
274+
275+ $ result = $ client ->evalSha ($ scriptSha , array_merge ([$ resource ], $ args ), 1 );
276+
277+ if (null !== $ err = $ client ->getLastError ()) {
278+ throw new LockStorageException ($ err );
279+ }
245280 }
246281
247282 return $ result ;
@@ -250,7 +285,22 @@ private function evaluate(string $script, string $resource, array $args): mixed
250285 \assert ($ this ->redis instanceof \Predis \ClientInterface);
251286
252287 try {
253- return $ this ->redis ->eval (...array_merge ([$ script , 1 , $ resource ], $ args ));
288+ return $ this ->redis ->evalSha ($ scriptSha , 1 , $ resource , ...$ args );
289+ } catch (ServerException $ e ) {
290+ // Fallthrough only if we need to load the script
291+ if (self ::NO_SCRIPT_ERROR_MESSAGE !== $ e ->getMessage ()) {
292+ throw new LockStorageException ($ e ->getMessage (), $ e ->getCode (), $ e );
293+ }
294+ }
295+
296+ try {
297+ $ this ->redis ->script ('LOAD ' , $ script );
298+ } catch (ServerException $ e ) {
299+ throw new LockStorageException ($ e ->getMessage (), $ e ->getCode (), $ e );
300+ }
301+
302+ try {
303+ return $ this ->redis ->evalSha ($ scriptSha , 1 , $ resource , ...$ args );
254304 } catch (ServerException $ e ) {
255305 throw new LockStorageException ($ e ->getMessage (), $ e ->getCode (), $ e );
256306 }
0 commit comments