diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index 31a93e3ebb..531ee768c9 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -301,7 +301,7 @@ public static enum Keyword implements Rawable { DELETE, LIBRARYNAME, WITHCODE, DESCRIPTION, GETKEYS, GETKEYSANDFLAGS, DOCS, FILTERBY, DUMP, MODULE, ACLCAT, PATTERN, DOCTOR, LATEST, HISTORY, USAGE, SAMPLES, PURGE, STATS, LOADEX, CONFIG, ARGS, RANK, NOW, VERSION, ADDR, SKIPME, USER, LADDR, - CHANNELS, NUMPAT, NUMSUB, SHARDCHANNELS, SHARDNUMSUB, NOVALUES; + CHANNELS, NUMPAT, NUMSUB, SHARDCHANNELS, SHARDNUMSUB, NOVALUES, MAXAGE; private final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/commands/ClientCommands.java b/src/main/java/redis/clients/jedis/commands/ClientCommands.java index edcfbd602e..75bda24a30 100644 --- a/src/main/java/redis/clients/jedis/commands/ClientCommands.java +++ b/src/main/java/redis/clients/jedis/commands/ClientCommands.java @@ -30,10 +30,10 @@ public interface ClientCommands { String clientKill(String ip, int port); /** - * Close a given client connection. + * Close client connections based on certain selection parameters. * - * @param params Connection info will be closed - * @return Close success return OK + * @param params Parameters defining what client connections to close. + * @return The number of client connections that were closed. */ long clientKill(ClientKillParams params); diff --git a/src/main/java/redis/clients/jedis/params/ClientKillParams.java b/src/main/java/redis/clients/jedis/params/ClientKillParams.java index 12c65be882..0082ef3340 100644 --- a/src/main/java/redis/clients/jedis/params/ClientKillParams.java +++ b/src/main/java/redis/clients/jedis/params/ClientKillParams.java @@ -67,6 +67,16 @@ public ClientKillParams laddr(String ip, int port) { return addParam(Keyword.LADDR, ip + ':' + port); } + /** + * Kill clients older than {@code maxAge} seconds. + * + * @param maxAge Clients older than this number of seconds will be killed. + * @return The {@code ClientKillParams} instance, for call chaining. + */ + public ClientKillParams maxAge(long maxAge) { + return addParam(Keyword.MAXAGE, maxAge); + } + @Override public void addParams(CommandArguments args) { params.forEach(kv -> args.add(kv.getKey()).add(kv.getValue())); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java index 8c3f35db49..cf7760dbf4 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java @@ -222,10 +222,10 @@ public void killAddrIpPort() { @Test public void killUser() { - Jedis client2 = new Jedis(hnp.getHost(), hnp.getPort(), 500); client.aclSetUser("test_kill", "on", "+acl", ">password1"); - try { + try (Jedis client2 = new Jedis(hnp.getHost(), hnp.getPort(), 500)) { client2.auth("test_kill", "password1"); + assertEquals(1, jedis.clientKill(new ClientKillParams().user("test_kill"))); assertDisconnected(client2); } finally { @@ -233,6 +233,27 @@ public void killUser() { } } + @Test + public void killMaxAge() throws InterruptedException { + long maxAge = 2; + + // sleep twice the maxAge, to be sure + Thread.sleep(maxAge * 2 * 1000); + + try (Jedis client2 = new Jedis(hnp.getHost(), hnp.getPort(), 500)) { + client2.auth("foobared"); + + long killedClients = jedis.clientKill(new ClientKillParams().maxAge(maxAge)); + + // The reality is that some tests leak clients, so we can't assert + // on the exact number of killed clients. + assertTrue(killedClients > 0); + + assertDisconnected(client); + assertConnected(client2); + } + } + @Test public void clientInfo() { String info = client.clientInfo(); @@ -267,6 +288,10 @@ private void assertDisconnected(Jedis j) { } } + private void assertConnected(Jedis j) { + assertEquals("PONG", j.ping()); + } + private String findInClientList() { for (String clientInfo : jedis.clientList().split("\n")) { if (pattern.matcher(clientInfo).find()) {