tasks) {
+ return tasks.removeAsync(requestId);
+ }
+
}
diff --git a/redisson/src/main/java/org/redisson/api/ExecutorOptions.java b/redisson/src/main/java/org/redisson/api/ExecutorOptions.java
new file mode 100644
index 000000000..cc349afc1
--- /dev/null
+++ b/redisson/src/main/java/org/redisson/api/ExecutorOptions.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2018 Nikita Koksharov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.redisson.api;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Configuration for ExecutorService.
+ *
+ * @author Nikita Koksharov
+ *
+ */
+public class ExecutorOptions {
+
+ private long taskRetryInterval = 60000;
+
+ private ExecutorOptions() {
+ }
+
+ public static ExecutorOptions defaults() {
+ return new ExecutorOptions();
+ }
+
+ public long getTaskRetryInterval() {
+ return taskRetryInterval;
+ }
+
+ /**
+ * Defines task retry interval at the end of which task is executed again.
+ * ExecutorService worker re-schedule task execution retry every 5 seconds.
+ *
+ * Default is 1 minute
+ *
+ * @param timeout value
+ * @param unit value
+ * @return self instance
+ */
+ public ExecutorOptions taskRetryInterval(long timeout, TimeUnit unit) {
+ this.taskRetryInterval = unit.toMillis(timeout);
+ return this;
+ }
+
+}
diff --git a/redisson/src/main/java/org/redisson/api/RedissonClient.java b/redisson/src/main/java/org/redisson/api/RedissonClient.java
index 53eba5182..a084c47de 100755
--- a/redisson/src/main/java/org/redisson/api/RedissonClient.java
+++ b/redisson/src/main/java/org/redisson/api/RedissonClient.java
@@ -839,6 +839,15 @@ public interface RedissonClient {
*/
RScheduledExecutorService getExecutorService(String name);
+ /**
+ * Returns ScheduledExecutorService by name
+ *
+ * @param name - name of object
+ * @param options - options for executor
+ * @return ScheduledExecutorService object
+ */
+ RScheduledExecutorService getExecutorService(String name, ExecutorOptions options);
+
/**
* Returns ScheduledExecutorService by name
* using provided codec for task, response and request serialization
@@ -864,6 +873,17 @@ public interface RedissonClient {
* @since 2.8.2
*/
RScheduledExecutorService getExecutorService(String name, Codec codec);
+
+ /**
+ * Returns ScheduledExecutorService by name
+ * using provided codec for task, response and request serialization
+ *
+ * @param name - name of object
+ * @param codec - codec for task, response and request
+ * @param options - options for executor
+ * @return ScheduledExecutorService object
+ */
+ RScheduledExecutorService getExecutorService(String name, Codec codec, ExecutorOptions options);
/**
* Returns object for remote operations prefixed with the default name (redisson_remote_service)
diff --git a/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java b/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java
index 4ed2cba4d..20d1f28be 100644
--- a/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java
+++ b/redisson/src/main/java/org/redisson/cluster/ClusterConnectionManager.java
@@ -582,7 +582,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
for (Integer slot : removedSlots) {
MasterSlaveEntry entry = removeEntry(slot);
if (entry.getSlotRanges().isEmpty()) {
- entry.shutdownMasterAsync();
+ entry.shutdownAsync();
log.info("{} master and slaves for it removed", entry.getClient().getAddr());
}
}
diff --git a/redisson/src/main/java/org/redisson/codec/DefenceModule.java b/redisson/src/main/java/org/redisson/codec/DefenceModule.java
deleted file mode 100644
index 6c0e54a15..000000000
--- a/redisson/src/main/java/org/redisson/codec/DefenceModule.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Copyright 2018 Nikita Koksharov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.redisson.codec;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import com.fasterxml.jackson.databind.BeanDescription;
-import com.fasterxml.jackson.databind.DeserializationConfig;
-import com.fasterxml.jackson.databind.deser.ValueInstantiator;
-import com.fasterxml.jackson.databind.deser.ValueInstantiators.Base;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-
-/**
- * Fix for https://github.com/FasterXML/jackson-databind/issues/1599
- *
- * @author Nikita Koksharov
- *
- * TODO remove after update to latest version of Jackson
- *
- */
-public class DefenceModule extends SimpleModule {
-
- private static final long serialVersionUID = -429891510707420220L;
-
- public static class DefenceValueInstantiator extends Base {
-
- protected final static Set DEFAULT_NO_DESER_CLASS_NAMES;
- static {
- Set s = new HashSet();
- // Courtesy of [https://github.com/kantega/notsoserial]:
- // (and wrt [databind#1599]
- s.add("org.apache.commons.collections.functors.InvokerTransformer");
- s.add("org.apache.commons.collections.functors.InstantiateTransformer");
- s.add("org.apache.commons.collections4.functors.InvokerTransformer");
- s.add("org.apache.commons.collections4.functors.InstantiateTransformer");
- s.add("org.codehaus.groovy.runtime.ConvertedClosure");
- s.add("org.codehaus.groovy.runtime.MethodClosure");
- s.add("org.springframework.beans.factory.ObjectFactory");
- s.add("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
- DEFAULT_NO_DESER_CLASS_NAMES = Collections.unmodifiableSet(s);
- }
-
- @Override
- public ValueInstantiator findValueInstantiator(DeserializationConfig config, BeanDescription beanDesc,
- ValueInstantiator defaultInstantiator) {
- if (DEFAULT_NO_DESER_CLASS_NAMES.contains(beanDesc.getClassInfo().getRawType().getName())) {
- throw new IllegalArgumentException("Illegal type " + beanDesc.getClassInfo().getRawType().getName() + " to deserialize: prevented for security reasons");
- }
-
- return super.findValueInstantiator(config, beanDesc, defaultInstantiator);
- }
-
- }
-
- @Override
- public void setupModule(SetupContext context) {
- context.addValueInstantiators(new DefenceValueInstantiator());
- }
-
-}
diff --git a/redisson/src/main/java/org/redisson/codec/JsonJacksonCodec.java b/redisson/src/main/java/org/redisson/codec/JsonJacksonCodec.java
index cb00e6472..f8e5145f3 100755
--- a/redisson/src/main/java/org/redisson/codec/JsonJacksonCodec.java
+++ b/redisson/src/main/java/org/redisson/codec/JsonJacksonCodec.java
@@ -153,8 +153,6 @@ public class JsonJacksonCodec extends BaseCodec {
}
protected void init(ObjectMapper objectMapper) {
- objectMapper.registerModule(new DefenceModule());
-
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.setVisibility(objectMapper.getSerializationConfig()
.getDefaultVisibilityChecker()
diff --git a/redisson/src/main/java/org/redisson/connection/ConnectionManager.java b/redisson/src/main/java/org/redisson/connection/ConnectionManager.java
index 4de8b004d..21e5e47fc 100644
--- a/redisson/src/main/java/org/redisson/connection/ConnectionManager.java
+++ b/redisson/src/main/java/org/redisson/connection/ConnectionManager.java
@@ -67,8 +67,6 @@ public interface ConnectionManager {
IdleConnectionWatcher getConnectionWatcher();
- void shutdownAsync(RedisClient client);
-
int calcSlot(String key);
MasterSlaveServersConfig getConfig();
diff --git a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java
index 622744c9a..3c6c1965f 100644
--- a/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java
+++ b/redisson/src/main/java/org/redisson/connection/MasterSlaveConnectionManager.java
@@ -46,11 +46,11 @@ import org.redisson.config.BaseMasterSlaveServersConfig;
import org.redisson.config.Config;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.TransportMode;
+import org.redisson.misc.CountableListener;
import org.redisson.misc.InfinitySemaphoreLatch;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import org.redisson.misc.URIBuilder;
-import org.redisson.pubsub.AsyncSemaphore;
import org.redisson.pubsub.PublishSubscribeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -435,11 +435,6 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
return client;
}
- @Override
- public void shutdownAsync(RedisClient client) {
- client.shutdownAsync();
- }
-
@Override
public RedisClient createClient(NodeType type, URI address, int timeout, int commandTimeout, String sslHostname) {
RedisClientConfig redisConfig = createRedisConfig(type, address, timeout, commandTimeout, sslHostname);
@@ -633,16 +628,6 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
dnsMonitor.stop();
}
- timer.stop();
-
- shutdownLatch.close();
- shutdownPromise.trySuccess(true);
- shutdownLatch.awaitUninterruptibly();
-
- for (MasterSlaveEntry entry : getEntrySet()) {
- entry.shutdown();
- }
-
if (cfg.getExecutor() == null) {
executor.shutdown();
try {
@@ -651,7 +636,20 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
Thread.currentThread().interrupt();
}
}
+
+ timer.stop();
+
+ shutdownLatch.close();
+ shutdownPromise.trySuccess(true);
+ shutdownLatch.awaitUninterruptibly();
+
+ RPromise result = new RedissonPromise();
+ CountableListener listener = new CountableListener(result, null, getEntrySet().size());
+ for (MasterSlaveEntry entry : getEntrySet()) {
+ entry.shutdownAsync().addListener(listener);
+ }
+ result.awaitUninterruptibly(timeout, unit);
resolverGroup.close();
if (cfg.getEventLoopGroup() == null) {
diff --git a/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java b/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java
index 304294bec..c3ddcff21 100644
--- a/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java
+++ b/redisson/src/main/java/org/redisson/connection/MasterSlaveEntry.java
@@ -139,25 +139,28 @@ public class MasterSlaveEntry {
return;
}
- masterEntry = new ClientConnectionsEntry(
- client,
- config.getMasterConnectionMinimumIdleSize(),
- config.getMasterConnectionPoolSize(),
- config.getSubscriptionConnectionMinimumIdleSize(),
- config.getSubscriptionConnectionPoolSize(),
- connectionManager,
- NodeType.MASTER);
-
- CountableListener listener = new CountableListener(result, client);
- RFuture writeFuture = writeConnectionPool.add(masterEntry);
- listener.incCounter();
- writeFuture.addListener(listener);
-
- if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
- RFuture pubSubFuture = pubSubConnectionPool.add(masterEntry);
- listener.incCounter();
- pubSubFuture.addListener(listener);
- }
+ masterEntry = new ClientConnectionsEntry(
+ client,
+ config.getMasterConnectionMinimumIdleSize(),
+ config.getMasterConnectionPoolSize(),
+ config.getSubscriptionConnectionMinimumIdleSize(),
+ config.getSubscriptionConnectionPoolSize(),
+ connectionManager,
+ NodeType.MASTER);
+
+ int counter = 1;
+ if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
+ counter++;
+ }
+
+ CountableListener listener = new CountableListener(result, client, counter);
+ RFuture writeFuture = writeConnectionPool.add(masterEntry);
+ writeFuture.addListener(listener);
+
+ if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
+ RFuture pubSubFuture = pubSubConnectionPool.add(masterEntry);
+ pubSubFuture.addListener(listener);
+ }
}
});
@@ -465,19 +468,22 @@ public class MasterSlaveEntry {
&& slaveBalancer.getAvailableClients() > 1) {
slaveDown(newMasterClient.getAddr(), FreezeReason.SYSTEM);
}
- connectionManager.shutdownAsync(oldMaster.getClient());
+ oldMaster.getClient().shutdownAsync();
log.info("master {} has changed to {}", oldMaster.getClient().getAddr(), masterEntry.getClient().getAddr());
}
});
}
- public void shutdownMasterAsync() {
+ public RFuture shutdownAsync() {
if (!active.compareAndSet(true, false)) {
- return;
+ return RedissonPromise.newSucceededFuture(null);
}
- connectionManager.shutdownAsync(masterEntry.getClient());
- slaveBalancer.shutdownAsync();
+ RPromise result = new RedissonPromise();
+ CountableListener listener = new CountableListener(result, null, 2);
+ masterEntry.getClient().shutdownAsync().addListener(listener);
+ slaveBalancer.shutdownAsync().addListener(listener);
+ return result;
}
public RFuture connectionWriteOp(RedisCommand> command) {
@@ -526,15 +532,6 @@ public class MasterSlaveEntry {
slaveBalancer.returnConnection(connection);
}
- public void shutdown() {
- if (!active.compareAndSet(true, false)) {
- return;
- }
-
- masterEntry.getClient().shutdown();
- slaveBalancer.shutdown();
- }
-
public void addSlotRange(Integer range) {
slots.add(range);
}
diff --git a/redisson/src/main/java/org/redisson/connection/balancer/LoadBalancerManager.java b/redisson/src/main/java/org/redisson/connection/balancer/LoadBalancerManager.java
index af5f51597..a83b7cd99 100644
--- a/redisson/src/main/java/org/redisson/connection/balancer/LoadBalancerManager.java
+++ b/redisson/src/main/java/org/redisson/connection/balancer/LoadBalancerManager.java
@@ -83,19 +83,17 @@ public class LoadBalancerManager {
public RFuture add(final ClientConnectionsEntry entry) {
RPromise result = new RedissonPromise();
- CountableListener listener = new CountableListener(result, null) {
+ CountableListener listener = new CountableListener(result, null, 2) {
@Override
protected void onSuccess(Void value) {
- client2Entry.put(entry.getClient(), entry);
- }
+ client2Entry.put(entry.getClient(), entry);
+ }
};
RFuture slaveFuture = slaveConnectionPool.add(entry);
- listener.incCounter();
slaveFuture.addListener(listener);
RFuture pubSubFuture = pubSubConnectionPool.add(entry);
- listener.incCounter();
pubSubFuture.addListener(listener);
return result;
}
@@ -249,16 +247,16 @@ public class LoadBalancerManager {
slaveConnectionPool.returnConnection(entry, connection);
}
- public void shutdown() {
- for (ClientConnectionsEntry entry : client2Entry.values()) {
- entry.getClient().shutdown();
+ public RFuture shutdownAsync() {
+ if (client2Entry.values().isEmpty()) {
+ return RedissonPromise.newSucceededFuture(null);
}
- }
-
- public void shutdownAsync() {
+ RPromise result = new RedissonPromise();
+ CountableListener listener = new CountableListener(result, null, client2Entry.values().size());
for (ClientConnectionsEntry entry : client2Entry.values()) {
- connectionManager.shutdownAsync(entry.getClient());
+ entry.getClient().shutdownAsync().addListener(listener);
}
+ return result;
}
}
diff --git a/redisson/src/main/java/org/redisson/executor/RedissonExecutorRemoteService.java b/redisson/src/main/java/org/redisson/executor/RedissonExecutorRemoteService.java
new file mode 100644
index 000000000..f3d709f65
--- /dev/null
+++ b/redisson/src/main/java/org/redisson/executor/RedissonExecutorRemoteService.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2018 Nikita Koksharov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.redisson.executor;
+
+import java.util.concurrent.ConcurrentMap;
+
+import org.redisson.RedissonRemoteService;
+import org.redisson.api.RFuture;
+import org.redisson.api.RMap;
+import org.redisson.api.RedissonClient;
+import org.redisson.client.codec.Codec;
+import org.redisson.command.CommandExecutor;
+import org.redisson.remote.RemoteServiceRequest;
+import org.redisson.remote.ResponseEntry;
+
+/**
+ *
+ * @author Nikita Koksharov
+ *
+ */
+public class RedissonExecutorRemoteService extends RedissonRemoteService {
+
+ public RedissonExecutorRemoteService(Codec codec, RedissonClient redisson, String name,
+ CommandExecutor commandExecutor, String executorId, ConcurrentMap responses) {
+ super(codec, redisson, name, commandExecutor, executorId, responses);
+ }
+
+ @Override
+ protected RFuture getTask(String requestId, RMap tasks) {
+ return tasks.getAsync(requestId);
+ }
+
+}
diff --git a/redisson/src/main/java/org/redisson/executor/ScheduledTasksService.java b/redisson/src/main/java/org/redisson/executor/ScheduledTasksService.java
index f1a7c55ad..e6184a87c 100644
--- a/redisson/src/main/java/org/redisson/executor/ScheduledTasksService.java
+++ b/redisson/src/main/java/org/redisson/executor/ScheduledTasksService.java
@@ -23,12 +23,15 @@ import org.redisson.api.RFuture;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec;
+import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandExecutor;
import org.redisson.remote.RemoteServiceRequest;
import org.redisson.remote.RequestId;
import org.redisson.remote.ResponseEntry;
+import io.netty.util.internal.PlatformDependent;
+
/**
*
* @author Nikita Koksharov
@@ -37,8 +40,6 @@ import org.redisson.remote.ResponseEntry;
public class ScheduledTasksService extends TasksService {
private RequestId requestId;
- private String schedulerQueueName;
- private String schedulerChannelName;
public ScheduledTasksService(Codec codec, RedissonClient redisson, String name, CommandExecutor commandExecutor, String redissonId, ConcurrentMap responses) {
super(codec, redisson, name, commandExecutor, redissonId, responses);
@@ -48,14 +49,6 @@ public class ScheduledTasksService extends TasksService {
this.requestId = requestId;
}
- public void setSchedulerChannelName(String schedulerChannelName) {
- this.schedulerChannelName = schedulerChannelName;
- }
-
- public void setSchedulerQueueName(String scheduledQueueName) {
- this.schedulerQueueName = scheduledQueueName;
- }
-
@Override
protected RFuture addAsync(String requestQueueName, RemoteServiceRequest request) {
int requestIndex = 0;
@@ -72,29 +65,19 @@ public class ScheduledTasksService extends TasksService {
request.getArgs()[requestIndex] = request.getId();
Long startTime = (Long)request.getArgs()[3];
- if (requestId != null) {
- return commandExecutor.evalWriteAsync(name, LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
- // check if executor service not in shutdown state and previous task exists
- "if redis.call('exists', KEYS[2]) == 0 and redis.call('hexists', KEYS[5], ARGV[2]) == 1 then "
- + "redis.call('zadd', KEYS[3], ARGV[1], ARGV[2]);"
- + "redis.call('hset', KEYS[5], ARGV[2], ARGV[3]);"
- + "redis.call('incr', KEYS[1]);"
- // if new task added to queue head then publish its startTime
- // to all scheduler workers
- + "local v = redis.call('zrange', KEYS[3], 0, 0); "
- + "if v[1] == ARGV[2] then "
- + "redis.call('publish', KEYS[4], ARGV[1]); "
- + "end "
- + "return 1;"
- + "end;"
- + "return 0;",
- Arrays.