@Override public void releaseLock(final String lock, final String holder) { Assert.notNull(lock, "Pre-condition violated: lock != null."); Assert.notNull(holder, "Pre-condition violated: holder != null."); // KEYS[1]: key // ARGV[1]: value DefaultRedisScript<Void> s = new DefaultRedisScript<>( "local lock = redis.call('get', KEYS[1]); " + "if (lock == ARGV[1]) then " + // We own the lock -> We may release it by deleting the lock. "redis.call('del', KEYS[1]); " + "end;"); redis.execute(s, keys(key(LOCK, lock)), value(holder)); }
@Override public boolean tryLock(final String lock, final String holder, final int timeout, final TimeUnit unit) { Assert.notNull(lock, "Pre-condition violated: lock != null."); Assert.notNull(holder, "Pre-condition violated: holder != null."); Assert.isTrue(timeout > 0, "Pre-condition violated: timeout > 0."); Assert.notNull(unit, "Pre-condition violated: unit != null."); long timeoutMillis = unit.toMillis(timeout); Assert.isTrue(timeoutMillis >= 100, "Pre-condition violated: timeoutMillis >= 100."); // KEYS[1]: key // ARGV[1]: timeout // ARGV[2]: value DefaultRedisScript<Boolean> s = new DefaultRedisScript<>( "local lock = redis.call('get', KEYS[1]); " + "if (lock == ARGV[2]) then " + // We own the lock -> Refresh expiration. "redis.call('pexpire', KEYS[1], ARGV[1]); " + "return true; " + "end; " + "if (lock) then " + // Someone else owns the lock -> Abort. "return false; " + "end; " + // No one owns the lock -> Create lock with expiration. "redis.call('psetex', KEYS[1], ARGV[1], ARGV[2]); " + "return true;", Boolean.class); return redis.execute(s, keys(key(LOCK, lock)), value(timeoutMillis), value(holder)); }
@Bean @SuppressWarnings("unchecked") public RedisScript redisRequestRateLimiterScript() { DefaultRedisScript redisScript = new DefaultRedisScript<>(); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("META-INF/scripts/request_rate_limiter.lua"))); redisScript.setResultType(List.class); return redisScript; }
private <T> RedisScript<T> getRedisScript(String script, Class<T> resultType) { return new DefaultRedisScript<>(script, resultType); }