
com.tencent.polaris.discovery.client.flow.WatchFlow Maven / Gradle / Ivy
/*
* Tencent is pleased to support the open source community by making Polaris available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.polaris.discovery.client.flow;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.api.listener.ServiceListener;
import com.tencent.polaris.api.plugin.compose.Extensions;
import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener;
import com.tencent.polaris.api.pojo.RegistryCacheValue;
import com.tencent.polaris.api.pojo.ServiceChangeEvent;
import com.tencent.polaris.api.pojo.ServiceEventKey;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.InstancesResponse;
import com.tencent.polaris.api.rpc.WatchServiceResponse;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.client.pojo.ServiceInstancesByProto;
import com.tencent.polaris.client.util.NamedThreadFactory;
import com.tencent.polaris.client.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
/**
* @author liaochuntao
*/
public class WatchFlow {
private static final Logger LOG = LoggerFactory.getLogger(SyncFlow.class);
private Extensions extensions;
private SyncFlow syncFlow;
private DispatchExecutor executor;
private final AtomicBoolean initialize = new AtomicBoolean(false);
private static final Map> watchers = new ConcurrentHashMap<>();
public void init(Extensions extensions, SyncFlow syncFlow) {
this.extensions = extensions;
this.syncFlow = syncFlow;
}
/**
* 监听服务下的实例变化
*
* @return WatchServiceResponse
*/
public WatchServiceResponse commonWatchService(CommonWatchServiceRequest request) throws PolarisException {
if (request.isWatch()) {
return watchService(request);
} else {
return unWatchService(request);
}
}
private void initFlow() {
if (initialize.compareAndSet(false, true)) {
extensions.getLocalRegistry().registerResourceListener(new InstanceChangeListener());
executor = new DispatchExecutor(extensions.getConfiguration().getConsumer().getSubscribe()
.getCallbackConcurrency());
}
}
private WatchServiceResponse watchService(CommonWatchServiceRequest request) throws PolarisException {
initFlow();
ServiceKey serviceKey = request.getSvcEventKey().getServiceKey();
InstancesResponse response = syncFlow.commonSyncGetAllInstances(request.getAllRequest());
watchers.computeIfAbsent(request.getSvcEventKey().getServiceKey(),
key -> Collections.synchronizedSet(new HashSet<>()));
boolean result = watchers.get(serviceKey).addAll(request.getWatchServiceRequest().getListeners());
return new WatchServiceResponse(response, result);
}
private WatchServiceResponse unWatchService(CommonWatchServiceRequest request) {
boolean result = true;
Set listeners = watchers.get(request.getSvcEventKey().getServiceKey());
if (CollectionUtils.isNotEmpty(listeners)) {
result = listeners.removeAll(request.getWatchServiceRequest().getListeners());
}
return new WatchServiceResponse(null, result);
}
/**
* 监听实例变化的Listener
*/
private class InstanceChangeListener extends AbstractResourceEventListener {
private final BiConsumer consumer = (event, listener) -> {
WatchFlow.this.executor.execute(event.getServiceKey(), () -> {
listener.onEvent(event);
});
};
@Override
public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue,
RegistryCacheValue newValue) {
if (newValue.getEventType() != ServiceEventKey.EventType.INSTANCE) {
return;
}
if (oldValue instanceof ServiceInstancesByProto && newValue instanceof ServiceInstancesByProto) {
LOG.debug("receive service={} change event", svcEventKey);
ServiceInstancesByProto oldIns = (ServiceInstancesByProto) oldValue;
ServiceInstancesByProto newIns = (ServiceInstancesByProto) newValue;
ServiceChangeEvent event = ServiceChangeEvent.Builder()
.serviceKey(svcEventKey.getServiceKey())
.addInstances(Utils.checkAddInstances(oldIns, newIns))
.updateInstances(Utils.checkUpdateInstances(oldIns, newIns))
.deleteInstances(Utils.checkDeleteInstances(oldIns, newIns))
.build();
Set listeners = watchers.getOrDefault(svcEventKey.getServiceKey(), Collections.emptySet());
listeners.forEach(serviceListener -> consumer.accept(event, serviceListener));
}
}
}
/**
* 由于使用移步处理ServiceChangeEvent,为了保证同一个Service下的Event按事件发生顺序通知给Listener,需要保证同一个Service
* 的Event是由同一个Thread进行处理
*/
private static class DispatchExecutor {
private final Executor[] executors;
public DispatchExecutor(int nThread) {
if (nThread < 1) {
nThread = 1;
}
this.executors = new Executor[nThread];
for (int i = 0; i < nThread; i++) {
this.executors[i] = Executors.newFixedThreadPool(1,
new NamedThreadFactory("service-watch-dispatch" + i));
}
}
public void execute(ServiceKey serviceKey, Runnable command) {
int code = serviceKey.hashCode();
Executor executor = executors[code % executors.length];
executor.execute(command);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy