mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
fixed #5270 , add CanalMQStarter stop latch
This commit is contained in:
@@ -1,5 +1,15 @@
|
|||||||
package com.alibaba.otter.canal.server;
|
package com.alibaba.otter.canal.server;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.connector.core.config.MQProperties;
|
import com.alibaba.otter.canal.connector.core.config.MQProperties;
|
||||||
import com.alibaba.otter.canal.connector.core.producer.MQDestination;
|
import com.alibaba.otter.canal.connector.core.producer.MQDestination;
|
||||||
import com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;
|
import com.alibaba.otter.canal.connector.core.spi.CanalMQProducer;
|
||||||
@@ -9,18 +19,6 @@ import com.alibaba.otter.canal.instance.core.CanalMQConfig;
|
|||||||
import com.alibaba.otter.canal.protocol.ClientIdentity;
|
import com.alibaba.otter.canal.protocol.ClientIdentity;
|
||||||
import com.alibaba.otter.canal.protocol.Message;
|
import com.alibaba.otter.canal.protocol.Message;
|
||||||
import com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;
|
import com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded;
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
public class CanalMQStarter {
|
public class CanalMQStarter {
|
||||||
|
|
||||||
@@ -107,28 +105,33 @@ public class CanalMQStarter {
|
|||||||
|
|
||||||
public synchronized void startDestination(String destination) {
|
public synchronized void startDestination(String destination) {
|
||||||
CanalInstance canalInstance = canalServer.getCanalInstances().get(destination);
|
CanalInstance canalInstance = canalServer.getCanalInstances().get(destination);
|
||||||
CanalMQRunnable canalMQRunable = canalMQWorks.get(destination);
|
if (canalInstance != null) {
|
||||||
//当zk出现session time out可能会导致instance出现多个消费者,从而出现乱序
|
CanalMQRunnable canalMQRunnable = canalMQWorks.get(destination);
|
||||||
//因此当抢占成功的实例已经启动CanalMQRunnable时就不需要stop然后start了
|
if (Objects.isNull(canalMQRunnable)) {
|
||||||
if (canalInstance != null && Objects.isNull(canalMQRunable)) {
|
canalMQRunnable = new CanalMQRunnable(destination);
|
||||||
stopDestination(destination);
|
canalMQWorks.put(canalInstance.getDestination(), canalMQRunnable);
|
||||||
CanalMQRunnable canalMQRunnable = new CanalMQRunnable(destination);
|
// 触发一下任务启动
|
||||||
canalMQWorks.put(canalInstance.getDestination(), canalMQRunnable);
|
Future future = executorService.submit(canalMQRunnable);
|
||||||
executorService.execute(canalMQRunnable);
|
canalMQRunnable.setFuture(future);
|
||||||
logger.info("## Start the MQ work of destination:" + destination);
|
logger.info("## Start the MQ work of destination:" + destination);
|
||||||
|
} else {
|
||||||
|
// 主段时间内的zk出现session time out,会默认优先当前节点抢占成功
|
||||||
|
// 如果没有出发过stop动作,这里可以忽略start的启动
|
||||||
|
logger.info("## Start the MQ work of destination:" + destination + " , ignore stop");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stopDestination(String destination) {
|
public synchronized void stopDestination(String destination) {
|
||||||
CanalMQRunnable canalMQRunable = canalMQWorks.get(destination);
|
CanalMQRunnable canalMQRunnable = canalMQWorks.get(destination);
|
||||||
if (canalMQRunable != null) {
|
if (canalMQRunnable != null) {
|
||||||
canalMQRunable.stop();
|
canalMQRunnable.stop(true);
|
||||||
canalMQWorks.remove(destination);
|
canalMQWorks.remove(destination);
|
||||||
logger.info("## Stop the MQ work of destination:" + destination);
|
logger.info("## Stop the MQ work of destination:" + destination);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void worker(String destination, AtomicBoolean destinationRunning) {
|
private void worker(String destination, AtomicBoolean destinationRunning, CountDownLatch latch) {
|
||||||
while (!running || !destinationRunning.get()) {
|
while (!running || !destinationRunning.get()) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
@@ -210,6 +213,9 @@ public class CanalMQStarter {
|
|||||||
logger.error("process error!", e);
|
logger.error("process error!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保一下关闭
|
||||||
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CanalMQRunnable implements Runnable {
|
private class CanalMQRunnable implements Runnable {
|
||||||
@@ -222,13 +228,31 @@ public class CanalMQStarter {
|
|||||||
|
|
||||||
private AtomicBoolean running = new AtomicBoolean(true);
|
private AtomicBoolean running = new AtomicBoolean(true);
|
||||||
|
|
||||||
|
private CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
private Future future;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
worker(destination, running);
|
worker(destination, running, latch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop(boolean wait) {
|
||||||
running.set(false);
|
running.set(false);
|
||||||
|
if (wait) {
|
||||||
|
try {
|
||||||
|
// 触发一下interrupt
|
||||||
|
future.cancel(true);
|
||||||
|
// 等待MQ发送线程的正常退出
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFuture(Future future) {
|
||||||
|
this.future = future;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user