|
@@ -1,8 +1,11 @@
|
|
package com.alibaba.otter.canal.server;
|
|
package com.alibaba.otter.canal.server;
|
|
|
|
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
@@ -18,17 +21,19 @@ import com.alibaba.otter.canal.spi.CanalMQProducer;
|
|
|
|
|
|
public class CanalMQStarter {
|
|
public class CanalMQStarter {
|
|
|
|
|
|
- private static final Logger logger = LoggerFactory.getLogger(CanalMQStarter.class);
|
|
|
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(CanalMQStarter.class);
|
|
|
|
|
|
- private volatile boolean running = false;
|
|
|
|
|
|
+ private volatile boolean running = false;
|
|
|
|
|
|
- private ExecutorService executorService;
|
|
|
|
|
|
+ private ExecutorService executorService;
|
|
|
|
|
|
- private CanalMQProducer canalMQProducer;
|
|
|
|
|
|
+ private CanalMQProducer canalMQProducer;
|
|
|
|
|
|
- private MQProperties properties;
|
|
|
|
|
|
+ private MQProperties properties;
|
|
|
|
|
|
- private CanalServerWithEmbedded canalServer;
|
|
|
|
|
|
+ private CanalServerWithEmbedded canalServer;
|
|
|
|
+
|
|
|
|
+ private Map<String, CanalMQRunnable> canalMQWorks = new ConcurrentHashMap<>();
|
|
|
|
|
|
public CanalMQStarter(CanalMQProducer canalMQProducer){
|
|
public CanalMQStarter(CanalMQProducer canalMQProducer){
|
|
this.canalMQProducer = canalMQProducer;
|
|
this.canalMQProducer = canalMQProducer;
|
|
@@ -57,20 +62,9 @@ public class CanalMQStarter {
|
|
executorService = Executors.newFixedThreadPool(canalServer.getCanalInstances().size());
|
|
executorService = Executors.newFixedThreadPool(canalServer.getCanalInstances().size());
|
|
logger.info("## start the MQ workers.");
|
|
logger.info("## start the MQ workers.");
|
|
for (final CanalInstance canalInstance : canalServer.getCanalInstances().values()) {
|
|
for (final CanalInstance canalInstance : canalServer.getCanalInstances().values()) {
|
|
- executorService.execute(new Runnable() {
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void run() {
|
|
|
|
- MQProperties.CanalDestination destination = new MQProperties.CanalDestination();
|
|
|
|
- destination.setCanalDestination(canalInstance.getDestination());
|
|
|
|
- CanalMQConfig mqConfig = canalInstance.getMqConfig();
|
|
|
|
- destination.setTopic(mqConfig.getTopic());
|
|
|
|
- destination.setPartition(mqConfig.getPartition());
|
|
|
|
- destination.setPartitionsNum(mqConfig.getPartitionsNum());
|
|
|
|
- destination.setPartitionHash(mqConfig.getPartitionHashProperties());
|
|
|
|
- worker(destination);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ CanalMQRunnable canalMQRunnable = new CanalMQRunnable(canalInstance);
|
|
|
|
+ canalMQWorks.put(canalInstance.getDestination(), canalMQRunnable);
|
|
|
|
+ executorService.execute(canalMQRunnable);
|
|
}
|
|
}
|
|
|
|
|
|
running = true;
|
|
running = true;
|
|
@@ -78,7 +72,16 @@ public class CanalMQStarter {
|
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
|
|
|
|
|
public void run() {
|
|
public void run() {
|
|
- stop();
|
|
|
|
|
|
+ try {
|
|
|
|
+ logger.info("## stop the MQ workers");
|
|
|
|
+ running = false;
|
|
|
|
+ executorService.shutdown();
|
|
|
|
+ canalMQProducer.stop();
|
|
|
|
+ } catch (Throwable e) {
|
|
|
|
+ logger.warn("##something goes wrong when stopping MQ workers:", e);
|
|
|
|
+ } finally {
|
|
|
|
+ logger.info("## canal MQ is down.");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
});
|
|
});
|
|
@@ -89,29 +92,33 @@ public class CanalMQStarter {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public synchronized void stop() {
|
|
|
|
- if (!running) {
|
|
|
|
- return;
|
|
|
|
|
|
+ public synchronized void startDestination(String destination) {
|
|
|
|
+ CanalInstance canalInstance = canalServer.getCanalInstances().get(destination);
|
|
|
|
+ if (canalInstance != null) {
|
|
|
|
+ stopDestination(destination);
|
|
|
|
+ CanalMQRunnable canalMQRunnable = new CanalMQRunnable(canalInstance);
|
|
|
|
+ canalMQWorks.put(canalInstance.getDestination(), canalMQRunnable);
|
|
|
|
+ executorService.execute(canalMQRunnable);
|
|
|
|
+ logger.info("## Start the MQ work of destination:" + destination);
|
|
}
|
|
}
|
|
- try {
|
|
|
|
- logger.info("## stop the MQ workers");
|
|
|
|
- running = false;
|
|
|
|
- executorService.shutdown();
|
|
|
|
- canalMQProducer.stop();
|
|
|
|
- } catch (Throwable e) {
|
|
|
|
- logger.warn("##something goes wrong when stopping MQ workers:", e);
|
|
|
|
- } finally {
|
|
|
|
- logger.info("## canal MQ is down.");
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public synchronized void stopDestination(String destination) {
|
|
|
|
+ CanalMQRunnable canalMQRunable = canalMQWorks.get(destination);
|
|
|
|
+ if (canalMQRunable != null) {
|
|
|
|
+ canalMQRunable.stop();
|
|
|
|
+ canalMQWorks.remove(destination);
|
|
|
|
+ logger.info("## Stop the MQ work of destination:" + destination);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private void worker(MQProperties.CanalDestination destination) {
|
|
|
|
- while (!running)
|
|
|
|
|
|
+ private void worker(MQProperties.CanalDestination destination, AtomicBoolean destinationRunning) {
|
|
|
|
+ while (!running || !destinationRunning.get())
|
|
;
|
|
;
|
|
logger.info("## start the MQ producer: {}.", destination.getCanalDestination());
|
|
logger.info("## start the MQ producer: {}.", destination.getCanalDestination());
|
|
|
|
|
|
final ClientIdentity clientIdentity = new ClientIdentity(destination.getCanalDestination(), (short) 1001, "");
|
|
final ClientIdentity clientIdentity = new ClientIdentity(destination.getCanalDestination(), (short) 1001, "");
|
|
- while (running) {
|
|
|
|
|
|
+ while (running && destinationRunning.get()) {
|
|
try {
|
|
try {
|
|
if (!canalServer.getCanalInstances().containsKey(clientIdentity.getDestination())) {
|
|
if (!canalServer.getCanalInstances().containsKey(clientIdentity.getDestination())) {
|
|
try {
|
|
try {
|
|
@@ -126,7 +133,7 @@ public class CanalMQStarter {
|
|
|
|
|
|
Long getTimeout = properties.getCanalGetTimeout();
|
|
Long getTimeout = properties.getCanalGetTimeout();
|
|
int getBatchSize = properties.getCanalBatchSize();
|
|
int getBatchSize = properties.getCanalBatchSize();
|
|
- while (running) {
|
|
|
|
|
|
+ while (running && destinationRunning.get()) {
|
|
Message message;
|
|
Message message;
|
|
if (getTimeout != null && getTimeout > 0) {
|
|
if (getTimeout != null && getTimeout > 0) {
|
|
message = canalServer
|
|
message = canalServer
|
|
@@ -168,4 +175,31 @@ public class CanalMQStarter {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ private class CanalMQRunnable implements Runnable {
|
|
|
|
+
|
|
|
|
+ private CanalInstance canalInstance;
|
|
|
|
+
|
|
|
|
+ public CanalMQRunnable(CanalInstance canalInstance){
|
|
|
|
+ this.canalInstance = canalInstance;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private AtomicBoolean running = new AtomicBoolean(true);
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void run() {
|
|
|
|
+ MQProperties.CanalDestination destination = new MQProperties.CanalDestination();
|
|
|
|
+ destination.setCanalDestination(canalInstance.getDestination());
|
|
|
|
+ CanalMQConfig mqConfig = canalInstance.getMqConfig();
|
|
|
|
+ destination.setTopic(mqConfig.getTopic());
|
|
|
|
+ destination.setPartition(mqConfig.getPartition());
|
|
|
|
+ destination.setPartitionsNum(mqConfig.getPartitionsNum());
|
|
|
|
+ destination.setPartitionHash(mqConfig.getPartitionHashProperties());
|
|
|
|
+ worker(destination, running);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void stop() {
|
|
|
|
+ running.set(false);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|