44import org .slf4j .Logger ;
55import org .slf4j .LoggerFactory ;
66import redis .clients .jedis .commands .ScriptingCommands ;
7+ import redis .clients .jedis .exceptions .JedisNoScriptException ;
78
89import java .io .IOException ;
910import java .util .*;
11+ import java .util .concurrent .ConcurrentHashMap ;
1012import java .util .stream .Collectors ;
1113
1214/**
1517public class RedisExtensions {
1618
1719 private static final Logger log = LoggerFactory .getLogger (RedisExtensions .class );
18- private enum SCRIPTS {
1920
20- executeArbitraryCommand ("/lua/executeArbitraryCommand.lua" ),
21- batchXADD ("/lua/batchXADD.lua" );
22-
23- private String path ;
24-
25- SCRIPTS (String path ) {
26- this .path = path ;
27- }
28-
29- String getPath () {
30- return this .path ;
31- }
32- }
3321 private final Gson gson ;
3422 private final ScriptingCommands client ;
35- private final Map <SCRIPTS , String > loadedScriptIds ;
23+ private final Map <Scripts , String > loadedScriptIds ;
3624
3725 public RedisExtensions (ScriptingCommands client ) throws IOException {
3826 this .gson = new Gson ();
3927 this .client = client ;
40- Map <SCRIPTS , String > scripts = new HashMap <>();
41- for (SCRIPTS scriptMeta : SCRIPTS .values ()) {
42- String lua = Utils .loadResource (scriptMeta .getPath ());
43- String sha = client .scriptLoad (lua );
44- log .debug ("Loaded script {} with sha marker {}" , sha );
45- scripts .put (scriptMeta , sha );
28+ Map <Scripts , String > scripts = new ConcurrentHashMap <>();
29+ for (Scripts scriptMeta : Scripts .values ()) {
30+ scripts .put (scriptMeta , loadScript (scriptMeta ));
31+ }
32+ this .loadedScriptIds = scripts ;
33+ }
34+
35+ public Object executeArbitraryCommand (String ...params ) {
36+ return executeArbitraryCommand (Arrays .asList (params ));
37+ }
38+
39+ private Object executeArbitraryCommand (List <String > params ) {
40+ return evalShaWithRetry (Scripts .executeArbitraryCommand , Collections .EMPTY_LIST , params );
41+ }
42+
43+ private String loadScript (Scripts scriptMeta ) throws IOException {
44+ String lua = Utils .loadResource (scriptMeta .getPath ());
45+ String sha = client .scriptLoad (lua );
46+ log .debug ("Loaded script {} with sha marker {}" , scriptMeta .getPath (), sha );
47+ return sha ;
48+ }
49+
50+ private Object evalShaWithRetry (Scripts script , List <String > keys , List <String > args ) {
51+ return evalShaWithRetry (script , keys , args , true );
52+ }
53+
54+ private Object evalShaWithRetry (Scripts script , List <String > keys , List <String > args , boolean firstAttempt ) {
55+ Object result = null ;
56+ String sha = loadedScriptIds .get (script );
57+ try {
58+ result = client .evalsha (sha , keys , args );
59+ } catch (JedisNoScriptException ex ) {
60+ if (firstAttempt ) {
61+ log .warn ("No script {} with sha marker {}. Trying to reload." , script .getPath (), sha );
62+ try {
63+ String newSha = loadScript (script );
64+ loadedScriptIds .put (script , newSha );
65+ result = evalShaWithRetry (script , keys , args , false );
66+ } catch (IOException ioex ) {
67+ throw ex ;
68+ }
69+ } else {
70+ throw ex ;
71+ }
4672 }
47- this . loadedScriptIds = Collections . unmodifiableMap ( scripts ) ;
73+ return result ;
4874 }
4975
5076 public List <StreamMessageId > batchXADD (String key , List <Map <String , String >> messages ) {
@@ -57,24 +83,14 @@ public List<StreamMessageId> batchXADD(String key, List<Map<String, String>> mes
5783 if (messages .stream ().flatMap (m -> m .values ().stream ()).anyMatch (v -> v == null )) {
5884 throw new IllegalArgumentException ("null values are disallowed" );
5985 }
60- String sha = loadedScriptIds .get (SCRIPTS .batchXADD );
6186 List <String > argv = messages .stream ()
6287 .map (m -> gson .toJson (m ))
6388 .collect (Collectors .toList ());
64- List <String > ids = (List <String >) client .evalsha (sha , Collections .singletonList (key ), argv );
89+ List <String > ids = (List <String >) evalShaWithRetry (Scripts .batchXADD ,
90+ Collections .singletonList (key ), argv );
6591 return ids .stream ().map (StreamMessageId ::from ).collect (Collectors .toList ());
6692 }
6793
68- public Object executeArbitraryCommand (String ...params ) {
69- String sha = loadedScriptIds .get (SCRIPTS .executeArbitraryCommand );
70- return client .evalsha (sha , 0 , params );
71- }
72-
73- public Object executeArbitraryCommand (List <String > params ) {
74- String sha = loadedScriptIds .get (SCRIPTS .executeArbitraryCommand );
75- return client .evalsha (sha , Collections .EMPTY_LIST , params );
76- }
77-
7894 public long XDEL (String key , List <StreamMessageId > ids ) {
7995 // TODO
8096 List <String > params = ids .stream ()
0 commit comments