From 4be6f3efbb3d2a4fc902719769cd29250d521ede Mon Sep 17 00:00:00 2001 From: Chionanthus <33491015+Chionanthus@users.noreply.github.com> Date: Thu, 19 Oct 2023 22:32:02 -0500 Subject: [PATCH] [ISSUE #10380] Support for fuzzy watch capability for Nacos registration center. (#11200) * add nacos fuzzy watch in client side * add fuzzy watch request handler, client operation and watch event * add fuzzy watch index manager support, add service change event in nacos naming module * add nacos server side notify fuzzy watch logic * add nacos naming fuzzy watch example * fix format * Optimizing Abstract Classes * alter class name and fix bug * remove redundant file import by repeat merge * fix bug --- .../alibaba/nacos/api/common/Constants.java | 10 +- .../nacos/api/naming/NamingService.java | 32 +-- ...a => AbstractFuzzyWatchEventListener.java} | 4 +- ...hListener.java => FuzzyWatchListener.java} | 6 +- ...yEvent.java => FuzzyWatchNotifyEvent.java} | 8 +- .../nacos/api/naming/pojo/Service.java | 6 + .../naming/remote/NamingRemoteConstants.java | 4 +- ...a => AbstractFuzzyWatchNotifyRequest.java} | 19 +- ...ava => FuzzyWatchNotifyChangeRequest.java} | 10 +- ....java => FuzzyWatchNotifyInitRequest.java} | 29 ++- ...iceRequest.java => FuzzyWatchRequest.java} | 8 +- ...eResponse.java => FuzzyWatchResponse.java} | 16 +- ...e.java => NotifyFuzzyWatcherResponse.java} | 4 +- .../nacos/api/naming/utils/NamingUtils.java | 18 +- .../com.alibaba.nacos.api.remote.Payload | 10 +- .../client/naming/NacosNamingService.java | 49 ++-- ....java => FuzzyWatchServiceListHolder.java} | 58 ++--- ...yEvent.java => FuzzyWatchNotifyEvent.java} | 14 +- ...ifier.java => ServicesChangeNotifier.java} | 64 +++--- .../naming/remote/NamingClientProxy.java | 6 +- .../remote/NamingClientProxyDelegate.java | 24 +- .../remote/gprc/NamingGrpcClientProxy.java | 45 ++-- .../remote/gprc/NamingPushRequestHandler.java | 20 +- .../gprc/redo/NamingGrpcRedoService.java | 71 +++--- .../remote/gprc/redo/RedoScheduledTask.java | 20 +- ...edoData.java => FuzzyWatcherRedoData.java} | 10 +- .../remote/http/NamingHttpClientProxy.java | 6 +- .../nacos-client/reflect-config.json | 27 ++- .../remote/NamingClientProxyDelegateTest.java | 66 +++--- .../gprc/NamingGrpcClientProxyTest.java | 10 +- .../gprc/NamingPushRequestHandlerTest.java | 6 +- .../nacos/example/FuzzyWatchExample.java | 115 ++++++++++ .../naming/core/v2/client/AbstractClient.java | 31 +++ .../nacos/naming/core/v2/client/Client.java | 31 +++ .../v2/event/client/ClientOperationEvent.java | 39 ++++ .../core/v2/event/service/ServiceEvent.java | 53 ++++- .../v2/index/ClientServiceIndexesManager.java | 131 ++++++++++- .../metadata/InstanceMetadataProcessor.java | 3 +- .../v2/service/ClientOperationService.java | 24 ++ .../service/ClientOperationServiceProxy.java | 10 + .../EphemeralClientOperationServiceImpl.java | 27 +++ .../PersistentClientOperationServiceImpl.java | 10 + .../heartbeat/ClientBeatProcessorV2.java | 3 +- .../heartbeat/UnhealthyInstanceChecker.java | 2 +- .../v2/NamingSubscriberServiceV2Impl.java | 38 ++++ .../naming/push/v2/executor/PushExecutor.java | 21 ++ .../v2/executor/PushExecutorDelegate.java | 15 ++ .../push/v2/executor/PushExecutorRpcImpl.java | 13 ++ .../push/v2/executor/PushExecutorUdpImpl.java | 12 + .../push/v2/task/FuzzyWatchInitDelayTask.java | 91 ++++++++ .../v2/task/FuzzyWatchInitExecuteTask.java | 209 ++++++++++++++++++ .../task/FuzzyWatchNotifyChangeDelayTask.java | 90 ++++++++ .../FuzzyWatchNotifyChangeExecuteTask.java | 145 ++++++++++++ .../task/FuzzyWatchPushDelayTaskEngine.java | 120 ++++++++++ .../rpc/handler/FuzzyWatchRequestHandler.java | 63 ++++++ .../ClientServiceIndexesManagerTest.java | 2 +- .../v2/NamingSubscriberServiceV2ImplTest.java | 3 +- .../push/v2/task/FixturePushExecutor.java | 17 ++ 58 files changed, 1665 insertions(+), 333 deletions(-) rename api/src/main/java/com/alibaba/nacos/api/naming/listener/{AbstractWatchEventListener.java => AbstractFuzzyWatchEventListener.java} (84%) rename api/src/main/java/com/alibaba/nacos/api/naming/listener/{WatchListener.java => FuzzyWatchListener.java} (87%) rename api/src/main/java/com/alibaba/nacos/api/naming/listener/{WatchNotifyEvent.java => FuzzyWatchNotifyEvent.java} (86%) rename api/src/main/java/com/alibaba/nacos/api/naming/remote/request/{AbstractWatchNotifyRequest.java => AbstractFuzzyWatchNotifyRequest.java} (74%) rename api/src/main/java/com/alibaba/nacos/api/naming/remote/request/{WatchNotifyChangeRequest.java => FuzzyWatchNotifyChangeRequest.java} (78%) rename api/src/main/java/com/alibaba/nacos/api/naming/remote/request/{WatchNotifyInitRequest.java => FuzzyWatchNotifyInitRequest.java} (50%) rename api/src/main/java/com/alibaba/nacos/api/naming/remote/request/{WatchServiceRequest.java => FuzzyWatchRequest.java} (79%) rename api/src/main/java/com/alibaba/nacos/api/naming/remote/response/{WatchServiceResponse.java => FuzzyWatchResponse.java} (74%) rename api/src/main/java/com/alibaba/nacos/api/naming/remote/response/{NotifyWatcherResponse.java => NotifyFuzzyWatcherResponse.java} (88%) rename client/src/main/java/com/alibaba/nacos/client/naming/cache/{WatchServiceListHolder.java => FuzzyWatchServiceListHolder.java} (63%) rename client/src/main/java/com/alibaba/nacos/client/naming/event/{WatchNotifyEvent.java => FuzzyWatchNotifyEvent.java} (72%) rename client/src/main/java/com/alibaba/nacos/client/naming/event/{WatchServiceChangeNotifier.java => ServicesChangeNotifier.java} (59%) rename client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/data/{WatcherRedoData.java => FuzzyWatcherRedoData.java} (68%) create mode 100644 example/src/main/java/com/alibaba/nacos/example/FuzzyWatchExample.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitDelayTask.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitExecuteTask.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeDelayTask.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeExecuteTask.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchPushDelayTaskEngine.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/remote/rpc/handler/FuzzyWatchRequestHandler.java diff --git a/api/src/main/java/com/alibaba/nacos/api/common/Constants.java b/api/src/main/java/com/alibaba/nacos/api/common/Constants.java index 87e424ee9d6..017bbb7dccd 100644 --- a/api/src/main/java/com/alibaba/nacos/api/common/Constants.java +++ b/api/src/main/java/com/alibaba/nacos/api/common/Constants.java @@ -241,10 +241,10 @@ public static class Naming { } /** - * The constants in Watch Pattern Match Rule directory. + * The constants in fuzzy watch pattern match rule directory. */ - public static class WatchMatchRule { - + public static class FuzzyWatchMatchRule { + public static final String MATCH_ALL = "MATCH_ALL"; public static final String MATCH_PREFIX = "MATCH_PREFIX"; @@ -252,9 +252,9 @@ public static class WatchMatchRule { } /** - * The constants in Watch Notify Event directory. + * The constants in fuzzy watch event type directory. */ - public static class WatchEventType { + public static class ServiceChangedType { public static final String ADD_SERVICE = "ADD_SERVICE"; diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/NamingService.java b/api/src/main/java/com/alibaba/nacos/api/naming/NamingService.java index fe1f6b266f2..fba95bb6e16 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/NamingService.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/NamingService.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.api.naming; import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.api.naming.listener.AbstractWatchEventListener; +import com.alibaba.nacos.api.naming.listener.AbstractFuzzyWatchEventListener; import com.alibaba.nacos.api.naming.listener.EventListener; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ListView; @@ -534,44 +534,44 @@ void unsubscribe(String serviceName, String groupName, List clusters, Ev throws NacosException; /** - * Watch a range of services by match rule to receive notify events of matched services alteration. + * Watch a range of services by rule to receive notify events of matched services alteration. * - * @param fixedGroupName fixed group name for watch + * @param fixedGroupName fixed group name for fuzzy watch * @param listener event listener * @throws NacosException nacos exception */ - void fuzzyWatch(String fixedGroupName, AbstractWatchEventListener listener) throws NacosException; + void fuzzyWatch(String fixedGroupName, AbstractFuzzyWatchEventListener listener) throws NacosException; /** - * Watch a range of services by match rule to receive notify events of matched services alteration. + * Watch a range of services by rule to receive notify events of matched services alteration. * - * @param serviceNamePattern service name pattern for watch - * @param fixedGroupName fixed group name for watch + * @param serviceNamePattern service name pattern for fuzzy watch + * @param fixedGroupName fixed group name for fuzzy watch * @param listener event listener * @throws NacosException nacos exception */ void fuzzyWatch(String serviceNamePattern, String fixedGroupName, - AbstractWatchEventListener listener) throws NacosException; + AbstractFuzzyWatchEventListener listener) throws NacosException; /** - * Cancel watch event listener of a pattern. + * Cancel fuzzy watch, and remove event listener of a pattern. * - * @param fixedGroupName fixed group name for watch + * @param fixedGroupName fixed group name for fuzzy watch * @param listener event listener * @throws NacosException nacos exception */ - void cancelFuzzyWatch(String fixedGroupName, AbstractWatchEventListener listener) throws NacosException; + void cancelFuzzyWatch(String fixedGroupName, AbstractFuzzyWatchEventListener listener) throws NacosException; /** - * Cancel watch event listener of a pattern. + * Cancel fuzzy watch, and remove event listener of a pattern. * - * @param serviceNamePattern service name pattern for watch - * @param fixedGroupName fixed group name for watch + * @param serviceNamePattern service name pattern for fuzzy watch + * @param fixedGroupName fixed group name for fuzzy watch * @param listener event listener * @throws NacosException nacos exception */ - void cancelFuzzyWatch(String serviceNamePattern, String fixedGroupName, AbstractWatchEventListener listener) throws NacosException; - + void cancelFuzzyWatch(String serviceNamePattern, String fixedGroupName, AbstractFuzzyWatchEventListener listener) throws NacosException; + /** * Get all service names from server. * diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/listener/AbstractWatchEventListener.java b/api/src/main/java/com/alibaba/nacos/api/naming/listener/AbstractFuzzyWatchEventListener.java similarity index 84% rename from api/src/main/java/com/alibaba/nacos/api/naming/listener/AbstractWatchEventListener.java rename to api/src/main/java/com/alibaba/nacos/api/naming/listener/AbstractFuzzyWatchEventListener.java index 1b36de6a2d0..e4c23dbe43b 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/listener/AbstractWatchEventListener.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/listener/AbstractFuzzyWatchEventListener.java @@ -19,11 +19,11 @@ import java.util.concurrent.Executor; /** - * Abstract watch event listener, to support handle event by user custom executor. + * Abstract fuzzy watch event listener, to support handle event by user custom executor. * * @author tanyongquan */ -public abstract class AbstractWatchEventListener implements WatchListener { +public abstract class AbstractFuzzyWatchEventListener implements FuzzyWatchListener { String uuid; diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/listener/WatchListener.java b/api/src/main/java/com/alibaba/nacos/api/naming/listener/FuzzyWatchListener.java similarity index 87% rename from api/src/main/java/com/alibaba/nacos/api/naming/listener/WatchListener.java rename to api/src/main/java/com/alibaba/nacos/api/naming/listener/FuzzyWatchListener.java index fcf384ddcca..ffd2090a799 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/listener/WatchListener.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/listener/FuzzyWatchListener.java @@ -17,16 +17,16 @@ package com.alibaba.nacos.api.naming.listener; /** - * Watch Listener. + * Fuzzy Watch Listener. * * @author tanyongquan */ -public interface WatchListener { +public interface FuzzyWatchListener { /** * callback event. * * @param event event */ - void onEvent(WatchNotifyEvent event); + void onEvent(FuzzyWatchNotifyEvent event); } diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/listener/WatchNotifyEvent.java b/api/src/main/java/com/alibaba/nacos/api/naming/listener/FuzzyWatchNotifyEvent.java similarity index 86% rename from api/src/main/java/com/alibaba/nacos/api/naming/listener/WatchNotifyEvent.java rename to api/src/main/java/com/alibaba/nacos/api/naming/listener/FuzzyWatchNotifyEvent.java index 65b9e79bd31..29f07309389 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/listener/WatchNotifyEvent.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/listener/FuzzyWatchNotifyEvent.java @@ -19,20 +19,20 @@ import com.alibaba.nacos.api.naming.pojo.Service; /** - * Watch Notify Event. + * Fuzzy Watch Notify Event. * * @author tanyongquan */ -public class WatchNotifyEvent implements Event { +public class FuzzyWatchNotifyEvent implements Event { private Service service; private String changeType; - public WatchNotifyEvent() { + public FuzzyWatchNotifyEvent() { } - public WatchNotifyEvent(Service service, String changeType) { + public FuzzyWatchNotifyEvent(Service service, String changeType) { this.service = service; this.changeType = changeType; } diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/pojo/Service.java b/api/src/main/java/com/alibaba/nacos/api/naming/pojo/Service.java index 0e9bfa166be..3c800dd0bda 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/pojo/Service.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/pojo/Service.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.api.naming.pojo; +import com.alibaba.nacos.api.naming.utils.NamingUtils; + import java.io.Serializable; import java.util.HashMap; import java.util.Map; @@ -101,6 +103,10 @@ public void setGroupName(String groupName) { this.groupName = groupName; } + public String getGroupedServiceName() { + return NamingUtils.getGroupedName(name, groupName); + } + public Map getMetadata() { return metadata; } diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/remote/NamingRemoteConstants.java b/api/src/main/java/com/alibaba/nacos/api/naming/remote/NamingRemoteConstants.java index 6d5e4b91b02..36ee9f64034 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/remote/NamingRemoteConstants.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/remote/NamingRemoteConstants.java @@ -30,9 +30,9 @@ public class NamingRemoteConstants { public static final String DE_REGISTER_INSTANCE = "deregisterInstance"; - public static final String WATCH_SERVICE = "watchService"; + public static final String FUZZY_WATCH_SERVICE = "fuzzyWatchService"; - public static final String CANCEL_WATCH_SERVICE = "cancelWatchService"; + public static final String CANCEL_FUZZY_WATCH_SERVICE = "cancelFuzzyWatchService"; public static final String QUERY_SERVICE = "queryService"; diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/AbstractWatchNotifyRequest.java b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/AbstractFuzzyWatchNotifyRequest.java similarity index 74% rename from api/src/main/java/com/alibaba/nacos/api/naming/remote/request/AbstractWatchNotifyRequest.java rename to api/src/main/java/com/alibaba/nacos/api/naming/remote/request/AbstractFuzzyWatchNotifyRequest.java index edc21ca707c..b1678a8001d 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/AbstractWatchNotifyRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/AbstractFuzzyWatchNotifyRequest.java @@ -21,23 +21,20 @@ import static com.alibaba.nacos.api.common.Constants.Naming.NAMING_MODULE; /** - * Abstract watch notify request, including basic watch notify information. + * Abstract fuzzy watch notify request, including basic fuzzy watch notify information. * * @author tanyongquan */ -public abstract class AbstractWatchNotifyRequest extends ServerRequest { +public abstract class AbstractFuzzyWatchNotifyRequest extends ServerRequest { private String namespace; - private String pattern; - private String serviceChangedType; - public AbstractWatchNotifyRequest(){ + public AbstractFuzzyWatchNotifyRequest(){ } - public AbstractWatchNotifyRequest(String namespace, String pattern, String serviceChangedType) { + public AbstractFuzzyWatchNotifyRequest(String namespace, String serviceChangedType) { this.namespace = namespace; - this.pattern = pattern; this.serviceChangedType = serviceChangedType; } @@ -57,14 +54,6 @@ public void setServiceChangedType(String serviceChangedType) { this.serviceChangedType = serviceChangedType; } - public String getPattern() { - return pattern; - } - - public void setPattern(String pattern) { - this.pattern = pattern; - } - @Override public String getModule() { return NAMING_MODULE; diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchNotifyChangeRequest.java b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchNotifyChangeRequest.java similarity index 78% rename from api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchNotifyChangeRequest.java rename to api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchNotifyChangeRequest.java index 88730bccaac..bf31ecb58cd 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchNotifyChangeRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchNotifyChangeRequest.java @@ -17,22 +17,22 @@ package com.alibaba.nacos.api.naming.remote.request; /** - * Nacos watch notify service change request, use it when one of the services changes. + * Nacos fuzzy watch notify service change request, use it when one of the services changes. * * @author tanyongquan */ -public class WatchNotifyChangeRequest extends AbstractWatchNotifyRequest { +public class FuzzyWatchNotifyChangeRequest extends AbstractFuzzyWatchNotifyRequest { String serviceName; String groupName; - public WatchNotifyChangeRequest() { + public FuzzyWatchNotifyChangeRequest() { } - public WatchNotifyChangeRequest(String namespace, String serviceName, + public FuzzyWatchNotifyChangeRequest(String namespace, String serviceName, String groupName, String serviceChangedType) { - super(namespace, "", serviceChangedType); + super(namespace, serviceChangedType); this.serviceName = serviceName; this.groupName = groupName; } diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchNotifyInitRequest.java b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchNotifyInitRequest.java similarity index 50% rename from api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchNotifyInitRequest.java rename to api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchNotifyInitRequest.java index 7889c2113e2..0983df802d7 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchNotifyInitRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchNotifyInitRequest.java @@ -22,28 +22,39 @@ import java.util.HashSet; /** - * Nacos watch initial notify request, use it when init a watch request, push service by batch. + * Nacos fuzzy watch initial notify request, use it when init a watch request, push service by batch. * * @author tanyongquan */ -public class WatchNotifyInitRequest extends AbstractWatchNotifyRequest { +public class FuzzyWatchNotifyInitRequest extends AbstractFuzzyWatchNotifyRequest { + + private String pattern; private Collection servicesName; - public WatchNotifyInitRequest() { + public FuzzyWatchNotifyInitRequest() { } - private WatchNotifyInitRequest(String namespace, String pattern, String serviceChangedType, Collection servicesName) { - super(namespace, pattern, serviceChangedType); + private FuzzyWatchNotifyInitRequest(String namespace, String pattern, String serviceChangedType, Collection servicesName) { + super(namespace, serviceChangedType); this.servicesName = servicesName; + this.pattern = pattern; + } + + public static FuzzyWatchNotifyInitRequest buildInitRequest(String namespace, String pattern, Collection servicesName) { + return new FuzzyWatchNotifyInitRequest(namespace, pattern, Constants.ServiceChangedType.WATCH_INITIAL_MATCH, servicesName); + } + + public static FuzzyWatchNotifyInitRequest buildInitFinishRequest(String namespace, String pattern) { + return new FuzzyWatchNotifyInitRequest(namespace, pattern, Constants.ServiceChangedType.FINISH_WATCH_INIT, new HashSet<>(1)); } - public static WatchNotifyInitRequest buildInitRequest(String namespace, String pattern, Collection servicesName) { - return new WatchNotifyInitRequest(namespace, pattern, Constants.WatchEventType.WATCH_INITIAL_MATCH, servicesName); + public String getPattern() { + return pattern; } - public static WatchNotifyInitRequest buildInitFinishRequest(String namespace, String pattern) { - return new WatchNotifyInitRequest(namespace, pattern, Constants.WatchEventType.FINISH_WATCH_INIT, new HashSet<>(1)); + public void setPattern(String pattern) { + this.pattern = pattern; } public Collection getServicesName() { diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchServiceRequest.java b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchRequest.java similarity index 79% rename from api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchServiceRequest.java rename to api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchRequest.java index ac7b00018f1..dd5015abd8b 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/WatchServiceRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/remote/request/FuzzyWatchRequest.java @@ -17,18 +17,18 @@ package com.alibaba.nacos.api.naming.remote.request; /** - * Nacos naming watch service request. + * Nacos naming fuzzy watch service request. * * @author tanyongquan */ -public class WatchServiceRequest extends AbstractNamingRequest { +public class FuzzyWatchRequest extends AbstractNamingRequest { private String type; - public WatchServiceRequest() { + public FuzzyWatchRequest() { } - public WatchServiceRequest(String namespace, String serviceNamePattern, String groupNamePattern, String type) { + public FuzzyWatchRequest(String namespace, String serviceNamePattern, String groupNamePattern, String type) { super(namespace, serviceNamePattern, groupNamePattern); this.type = type; } diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/WatchServiceResponse.java b/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/FuzzyWatchResponse.java similarity index 74% rename from api/src/main/java/com/alibaba/nacos/api/naming/remote/response/WatchServiceResponse.java rename to api/src/main/java/com/alibaba/nacos/api/naming/remote/response/FuzzyWatchResponse.java index ecf487e23fe..6abbad6ba54 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/WatchServiceResponse.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/FuzzyWatchResponse.java @@ -20,23 +20,23 @@ import com.alibaba.nacos.api.remote.response.ResponseCode; /** - * Nacos naming watch service response. + * Nacos naming fuzzy watch service response. * * @author tanyongquan */ -public class WatchServiceResponse extends Response { +public class FuzzyWatchResponse extends Response { private String type; - public WatchServiceResponse(){ + public FuzzyWatchResponse(){ } - public WatchServiceResponse(String type) { + public FuzzyWatchResponse(String type) { this.type = type; } - public static WatchServiceResponse buildSuccessResponse(String type) { - return new WatchServiceResponse(type); + public static FuzzyWatchResponse buildSuccessResponse(String type) { + return new FuzzyWatchResponse(type); } /** @@ -45,8 +45,8 @@ public static WatchServiceResponse buildSuccessResponse(String type) { * @param message error message * @return fail response */ - public static WatchServiceResponse buildFailResponse(String message) { - WatchServiceResponse result = new WatchServiceResponse(); + public static FuzzyWatchResponse buildFailResponse(String message) { + FuzzyWatchResponse result = new FuzzyWatchResponse(); result.setErrorInfo(ResponseCode.FAIL.getCode(), message); return result; } diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/NotifyWatcherResponse.java b/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/NotifyFuzzyWatcherResponse.java similarity index 88% rename from api/src/main/java/com/alibaba/nacos/api/naming/remote/response/NotifyWatcherResponse.java rename to api/src/main/java/com/alibaba/nacos/api/naming/remote/response/NotifyFuzzyWatcherResponse.java index 6ff93354da5..ac9d55298db 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/NotifyWatcherResponse.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/remote/response/NotifyFuzzyWatcherResponse.java @@ -19,10 +19,10 @@ import com.alibaba.nacos.api.remote.response.Response; /** - * Response for notify watcher. + * Response for notify fuzzy watcher. * * @author tanyongquan */ -public class NotifyWatcherResponse extends Response { +public class NotifyFuzzyWatcherResponse extends Response { } diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java index cb53846d22a..b29b9639918 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/naming/utils/NamingUtils.java @@ -208,7 +208,7 @@ public static String getPatternRemovedNamespace(String completedPattern) { } /** - * Get the Pattern subscribed to under this NamespaceId. + * Get the pattern watched under given namespace id. * @param namespaceId name space id * @param completedPattern a set of all watch pattern(with namespace id) * @return filtered pattern set @@ -228,16 +228,16 @@ public static Set filterPatternWithNamespace(String namespaceId, Set clust } @Override - public void fuzzyWatch(String fixedGroupName, AbstractWatchEventListener listener) throws NacosException { + public void fuzzyWatch(String fixedGroupName, AbstractFuzzyWatchEventListener listener) throws NacosException { // pattern e.g. DEFAULT_GROUP@@MATCH_ALL - doFuzzyWatch(Constants.WatchMatchRule.MATCH_ALL, fixedGroupName, listener); + doFuzzyWatch(Constants.FuzzyWatchMatchRule.MATCH_ALL, fixedGroupName, listener); } @Override public void fuzzyWatch(String serviceNamePattern, String fixedGroupName, - AbstractWatchEventListener listener) throws NacosException { + AbstractFuzzyWatchEventListener listener) throws NacosException { // only support prefix match right now // pattern e.g. DEFAULT_GROUP@@nacos.test##MATCH_PREFIX - String serviceNamePrefixPattern = NamingUtils.getGroupedPattern(serviceNamePattern, Constants.WatchMatchRule.MATCH_PREFIX); + String serviceNamePrefixPattern = NamingUtils.getGroupedPattern(serviceNamePattern, Constants.FuzzyWatchMatchRule.MATCH_PREFIX); doFuzzyWatch(serviceNamePrefixPattern, fixedGroupName, listener); } private void doFuzzyWatch(String serviceNamePattern, String groupNamePattern, - AbstractWatchEventListener listener) throws NacosException { + AbstractFuzzyWatchEventListener listener) throws NacosException { if (null == listener) { return; } String uuid = UUID.randomUUID().toString(); listener.setUuid(uuid); - watchServiceChangeNotifier.registerWatchListener(serviceNamePattern, groupNamePattern, listener); + servicesChangeNotifier.registerFuzzyWatchListener(serviceNamePattern, groupNamePattern, listener); clientProxy.fuzzyWatch(serviceNamePattern, groupNamePattern, uuid); } @Override - public void cancelFuzzyWatch(String fixedGroupName, AbstractWatchEventListener listener) throws NacosException { - doCancelFuzzyWatch(Constants.WatchMatchRule.MATCH_ALL, fixedGroupName, listener); + public void cancelFuzzyWatch(String fixedGroupName, AbstractFuzzyWatchEventListener listener) throws NacosException { + doCancelFuzzyWatch(Constants.FuzzyWatchMatchRule.MATCH_ALL, fixedGroupName, listener); } @Override - public void cancelFuzzyWatch(String serviceNamePattern, String fixedGroupName, AbstractWatchEventListener listener) throws NacosException { - String serviceNamePrefixPattern = NamingUtils.getGroupedPattern(serviceNamePattern, Constants.WatchMatchRule.MATCH_PREFIX); + public void cancelFuzzyWatch(String serviceNamePattern, String fixedGroupName, AbstractFuzzyWatchEventListener listener) throws NacosException { + String serviceNamePrefixPattern = NamingUtils.getGroupedPattern(serviceNamePattern, Constants.FuzzyWatchMatchRule.MATCH_PREFIX); doCancelFuzzyWatch(serviceNamePrefixPattern, fixedGroupName, listener); } - private void doCancelFuzzyWatch(String serviceNamePattern, String groupNamePattern, AbstractWatchEventListener listener) throws NacosException { + private void doCancelFuzzyWatch(String serviceNamePattern, String groupNamePattern, + AbstractFuzzyWatchEventListener listener) throws NacosException { if (null == listener) { return; } - watchServiceChangeNotifier.deregisterWatchListener(serviceNamePattern, groupNamePattern, listener); - if (!watchServiceChangeNotifier.isWatched(serviceNamePattern, groupNamePattern)) { + servicesChangeNotifier.deregisterFuzzyWatchListener(serviceNamePattern, groupNamePattern, listener); + if (!servicesChangeNotifier.isWatched(serviceNamePattern, groupNamePattern)) { clientProxy.cancelFuzzyWatch(serviceNamePattern, groupNamePattern); } } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/cache/WatchServiceListHolder.java b/client/src/main/java/com/alibaba/nacos/client/naming/cache/FuzzyWatchServiceListHolder.java similarity index 63% rename from client/src/main/java/com/alibaba/nacos/client/naming/cache/WatchServiceListHolder.java rename to client/src/main/java/com/alibaba/nacos/client/naming/cache/FuzzyWatchServiceListHolder.java index 293849cabce..dfd0e2bd240 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/cache/WatchServiceListHolder.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/cache/FuzzyWatchServiceListHolder.java @@ -18,12 +18,12 @@ import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.naming.pojo.Service; -import com.alibaba.nacos.api.naming.remote.request.AbstractWatchNotifyRequest; -import com.alibaba.nacos.api.naming.remote.request.WatchNotifyChangeRequest; -import com.alibaba.nacos.api.naming.remote.request.WatchNotifyInitRequest; +import com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest; +import com.alibaba.nacos.api.naming.remote.request.FuzzyWatchNotifyChangeRequest; +import com.alibaba.nacos.api.naming.remote.request.FuzzyWatchNotifyInitRequest; import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.client.env.NacosClientProperties; -import com.alibaba.nacos.client.naming.event.WatchNotifyEvent; +import com.alibaba.nacos.client.naming.event.FuzzyWatchNotifyEvent; import com.alibaba.nacos.client.naming.utils.CollectionUtils; import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.utils.ConcurrentHashSet; @@ -34,11 +34,11 @@ import java.util.concurrent.ConcurrentHashMap; /** - * Naming client watch service list holder. + * Naming client fuzzy watch service list holder. * * @author tanyongquan */ -public class WatchServiceListHolder { +public class FuzzyWatchServiceListHolder { private String notifierEventScope; @@ -47,54 +47,55 @@ public class WatchServiceListHolder { */ private Map> patternMatchMap = new ConcurrentHashMap<>(); - public WatchServiceListHolder(String notifierEventScope, NacosClientProperties properties) { + public FuzzyWatchServiceListHolder(String notifierEventScope, NacosClientProperties properties) { this.notifierEventScope = notifierEventScope; } /** - * Publish service change event notify by watch. + * Publish service change event notify from nacos server about fuzzy watch. * * @param request watch notify request from Nacos server */ - public void processServiceChange(AbstractWatchNotifyRequest request) { - if (request instanceof WatchNotifyInitRequest) { - WatchNotifyInitRequest watchNotifyInitRequest = (WatchNotifyInitRequest) request; - Set cacheService = patternMatchMap.computeIfAbsent(request.getPattern(), keyInner -> new ConcurrentHashSet<>()); + public void processFuzzyWatchNotify(AbstractFuzzyWatchNotifyRequest request) { + if (request instanceof FuzzyWatchNotifyInitRequest) { + FuzzyWatchNotifyInitRequest watchNotifyInitRequest = (FuzzyWatchNotifyInitRequest) request; + Set matchedServiceSet = patternMatchMap.computeIfAbsent(watchNotifyInitRequest.getPattern(), + keyInner -> new ConcurrentHashSet<>()); Collection servicesName = watchNotifyInitRequest.getServicesName(); for (String groupedName : servicesName) { Service service = new Service(NamingUtils.getServiceName(groupedName), NamingUtils.getGroupName(groupedName)); // may have a 'change event' sent to client before 'init event' - if (cacheService.add(service)) { - NotifyCenter.publishEvent(WatchNotifyEvent.buildNotifyPatternAllListenersEvent(notifierEventScope, - service, request.getPattern(), Constants.WatchEventType.ADD_SERVICE)); + if (matchedServiceSet.add(service)) { + NotifyCenter.publishEvent(FuzzyWatchNotifyEvent.buildNotifyPatternAllListenersEvent(notifierEventScope, + service, watchNotifyInitRequest.getPattern(), Constants.ServiceChangedType.ADD_SERVICE)); } } - } else if (request instanceof WatchNotifyChangeRequest) { - WatchNotifyChangeRequest notifyChangeRequest = (WatchNotifyChangeRequest) request; + } else if (request instanceof FuzzyWatchNotifyChangeRequest) { + FuzzyWatchNotifyChangeRequest notifyChangeRequest = (FuzzyWatchNotifyChangeRequest) request; Collection matchedPattern = NamingUtils.getServiceMatchedPatterns(notifyChangeRequest.getServiceName(), notifyChangeRequest.getGroupName(), patternMatchMap.keySet()); Service service = new Service(notifyChangeRequest.getServiceName(), notifyChangeRequest.getGroupName()); String serviceChangeType = request.getServiceChangedType(); switch (serviceChangeType) { - case Constants.WatchEventType.ADD_SERVICE: - case Constants.WatchEventType.INSTANCE_CHANGED: + case Constants.ServiceChangedType.ADD_SERVICE: + case Constants.ServiceChangedType.INSTANCE_CHANGED: for (String pattern : matchedPattern) { Set matchedServiceSet = patternMatchMap.get(pattern); if (matchedServiceSet != null && matchedServiceSet.add(service)) { NotifyCenter.publishEvent( - WatchNotifyEvent.buildNotifyPatternAllListenersEvent(notifierEventScope, - service, pattern, serviceChangeType)); + FuzzyWatchNotifyEvent.buildNotifyPatternAllListenersEvent(notifierEventScope, + service, pattern, Constants.ServiceChangedType.ADD_SERVICE)); } } break; - case Constants.WatchEventType.DELETE_SERVICE: + case Constants.ServiceChangedType.DELETE_SERVICE: for (String pattern : matchedPattern) { Set matchedServiceSet = patternMatchMap.get(pattern); if (matchedServiceSet != null && matchedServiceSet.remove(service)) { NotifyCenter.publishEvent( - WatchNotifyEvent.buildNotifyPatternAllListenersEvent(notifierEventScope, - service, pattern, serviceChangeType)); + FuzzyWatchNotifyEvent.buildNotifyPatternAllListenersEvent(notifierEventScope, + service, pattern, Constants.ServiceChangedType.DELETE_SERVICE)); } } break; @@ -105,21 +106,22 @@ public void processServiceChange(AbstractWatchNotifyRequest request) { } /** - * For a duplicate watch of a certain pattern, initiate an initialization event to the corresponding Listener. + * For a duplicate fuzzy watch of a certain pattern, initiate an initialization event to the corresponding Listener. * * @param serviceNamePattern service name pattern. * @param groupNamePattern group name pattern. * @param uuid The UUID that identifies the Listener. */ - public void duplicateWatchInit(String serviceNamePattern, String groupNamePattern, String uuid) { + public void duplicateFuzzyWatchInit(String serviceNamePattern, String groupNamePattern, String uuid) { String pattern = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); Collection cacheServices = patternMatchMap.get(pattern); if (cacheServices == null) { return; } for (Service service : cacheServices) { - NotifyCenter.publishEvent(WatchNotifyEvent.buildNotifyPatternSpecificListenerEvent(notifierEventScope, service, - pattern, uuid, Constants.WatchEventType.ADD_SERVICE)); + NotifyCenter.publishEvent( + FuzzyWatchNotifyEvent.buildNotifyPatternSpecificListenerEvent(notifierEventScope, service, + pattern, uuid, Constants.ServiceChangedType.ADD_SERVICE)); } } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/event/WatchNotifyEvent.java b/client/src/main/java/com/alibaba/nacos/client/naming/event/FuzzyWatchNotifyEvent.java similarity index 72% rename from client/src/main/java/com/alibaba/nacos/client/naming/event/WatchNotifyEvent.java rename to client/src/main/java/com/alibaba/nacos/client/naming/event/FuzzyWatchNotifyEvent.java index 7d738369678..4f39dc30645 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/event/WatchNotifyEvent.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/event/FuzzyWatchNotifyEvent.java @@ -24,7 +24,7 @@ * * @author tanyongquan */ -public class WatchNotifyEvent extends Event { +public class FuzzyWatchNotifyEvent extends Event { private final String eventScope; @@ -36,26 +36,26 @@ public class WatchNotifyEvent extends Event { private final String serviceChangedType; - private WatchNotifyEvent(String eventScope, Service changedService, String pattern, String uuid, String serviceChangedType) { + private FuzzyWatchNotifyEvent(String eventScope, Service changedService, String pattern, String uuid, String serviceChangedType) { this(eventScope, changedService, pattern, serviceChangedType); this.uuid = uuid; } - private WatchNotifyEvent(String eventScope, Service changedService, String pattern, String serviceChangedType) { + private FuzzyWatchNotifyEvent(String eventScope, Service changedService, String pattern, String serviceChangedType) { this.eventScope = eventScope; this.changedService = changedService; this.serviceChangedType = serviceChangedType; this.pattern = pattern; } - public static WatchNotifyEvent buildNotifyPatternSpecificListenerEvent(String eventScope, Service changedService, + public static FuzzyWatchNotifyEvent buildNotifyPatternSpecificListenerEvent(String eventScope, Service changedService, String pattern, String uuid, String serviceChangedType) { - return new WatchNotifyEvent(eventScope, changedService, pattern, uuid, serviceChangedType); + return new FuzzyWatchNotifyEvent(eventScope, changedService, pattern, uuid, serviceChangedType); } - public static WatchNotifyEvent buildNotifyPatternAllListenersEvent(String eventScope, Service changedService, + public static FuzzyWatchNotifyEvent buildNotifyPatternAllListenersEvent(String eventScope, Service changedService, String pattern, String serviceChangedType) { - return new WatchNotifyEvent(eventScope, changedService, pattern, serviceChangedType); + return new FuzzyWatchNotifyEvent(eventScope, changedService, pattern, serviceChangedType); } public Service getChangedService() { diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/event/WatchServiceChangeNotifier.java b/client/src/main/java/com/alibaba/nacos/client/naming/event/ServicesChangeNotifier.java similarity index 59% rename from client/src/main/java/com/alibaba/nacos/client/naming/event/WatchServiceChangeNotifier.java rename to client/src/main/java/com/alibaba/nacos/client/naming/event/ServicesChangeNotifier.java index e9e18415172..26bc5741387 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/event/WatchServiceChangeNotifier.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/event/ServicesChangeNotifier.java @@ -16,7 +16,7 @@ package com.alibaba.nacos.client.naming.event; -import com.alibaba.nacos.api.naming.listener.AbstractWatchEventListener; +import com.alibaba.nacos.api.naming.listener.AbstractFuzzyWatchEventListener; import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.notify.Event; @@ -32,55 +32,55 @@ import java.util.concurrent.ConcurrentHashMap; /** - * A watcher to notify watch event Listener callback. + * A watcher to notify service change event Listener callback. * * @author tanyongquan */ -public class WatchServiceChangeNotifier extends Subscriber { +public class ServicesChangeNotifier extends Subscriber { private final String eventScope; @JustForTest - public WatchServiceChangeNotifier() { + public ServicesChangeNotifier() { this.eventScope = UUID.randomUUID().toString(); } - public WatchServiceChangeNotifier(String eventScope) { + public ServicesChangeNotifier(String eventScope) { this.eventScope = eventScope; } /** - * pattern -> Set[Listener]. + * The content of map is {pattern -> Set[Listener]}. */ - private final Map> watchListenerMap = new ConcurrentHashMap<>(); + private final Map> fuzzyWatchListenerMap = new ConcurrentHashMap<>(); - /** register watch listener. - * This listener responds to changes of the services (not the instance). + /** register fuzzy watch listener. + * This listener responds to changes of the services (not the instance's change). * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern * @param listener custom listener */ - public void registerWatchListener(String serviceNamePattern, String groupNamePattern, AbstractWatchEventListener listener) { + public void registerFuzzyWatchListener(String serviceNamePattern, String groupNamePattern, AbstractFuzzyWatchEventListener listener) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - Set eventListeners = watchListenerMap.computeIfAbsent(key, keyInner -> new ConcurrentHashSet<>()); + Set eventListeners = fuzzyWatchListenerMap.computeIfAbsent(key, keyInner -> new ConcurrentHashSet<>()); eventListeners.add(listener); } - /** remove watch listener. + /** remove fuzzy watch listener. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern */ - public void deregisterWatchListener(String serviceNamePattern, String groupNamePattern, AbstractWatchEventListener listener) { + public void deregisterFuzzyWatchListener(String serviceNamePattern, String groupNamePattern, AbstractFuzzyWatchEventListener listener) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - ConcurrentHashSet eventListeners = watchListenerMap.get(key); + ConcurrentHashSet eventListeners = fuzzyWatchListenerMap.get(key); if (eventListeners == null) { return; } eventListeners.remove(listener); if (CollectionUtils.isEmpty(eventListeners)) { - watchListenerMap.remove(key); + fuzzyWatchListenerMap.remove(key); } } @@ -93,55 +93,55 @@ public void deregisterWatchListener(String serviceNamePattern, String groupNameP */ public boolean isWatched(String serviceNamePattern, String groupNamePattern) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - ConcurrentHashSet eventListeners = watchListenerMap.get(key); + ConcurrentHashSet eventListeners = fuzzyWatchListenerMap.get(key); return CollectionUtils.isNotEmpty(eventListeners); } /** - * receive watch notify (watch init or service change) from nacos server, notify all listener watch this pattern. + * receive fuzzy watch notify (fuzzy watch init or service change) from nacos server, notify all listener watch this pattern. * If the event contains a UUID, then the event is used to notify the specified Listener when there are - * multiple watches for a particular Pattern + * multiple watches for a particular pattern. * * @param event watch notify event */ @Override - public void onEvent(WatchNotifyEvent event) { + public void onEvent(FuzzyWatchNotifyEvent event) { String uuid = event.getUuid(); - Collection listeners = watchListenerMap.get(event.getPattern()); - final com.alibaba.nacos.api.naming.listener.WatchNotifyEvent watchNotifyEvent = transferToWatchNotifyEvent(event); - for (AbstractWatchEventListener each : listeners) { + Collection listeners = fuzzyWatchListenerMap.get(event.getPattern()); + final com.alibaba.nacos.api.naming.listener.FuzzyWatchNotifyEvent fuzzyWatchNotifyEvent = transferToWatchNotifyEvent(event); + for (AbstractFuzzyWatchEventListener each : listeners) { // notify all listener watch this pattern if (StringUtils.isEmpty(uuid)) { if (each.getExecutor() != null) { - each.getExecutor().execute(() -> each.onEvent(watchNotifyEvent)); + each.getExecutor().execute(() -> each.onEvent(fuzzyWatchNotifyEvent)); } else { - each.onEvent(watchNotifyEvent); + each.onEvent(fuzzyWatchNotifyEvent); } } else if (uuid.equals(each.getUuid())) { // notify specific listener by uuid, use in duplicate watch a same pattern if (each.getExecutor() != null) { - each.getExecutor().execute(() -> each.onEvent(watchNotifyEvent)); + each.getExecutor().execute(() -> each.onEvent(fuzzyWatchNotifyEvent)); } else { - each.onEvent(watchNotifyEvent); + each.onEvent(fuzzyWatchNotifyEvent); } return; } } } - private com.alibaba.nacos.api.naming.listener.WatchNotifyEvent transferToWatchNotifyEvent( - WatchNotifyEvent watchNotifyEvent) { - return new com.alibaba.nacos.api.naming.listener.WatchNotifyEvent(watchNotifyEvent.getChangedService(), - watchNotifyEvent.getServiceChangedType()); + private com.alibaba.nacos.api.naming.listener.FuzzyWatchNotifyEvent transferToWatchNotifyEvent( + FuzzyWatchNotifyEvent fuzzyWatchNotifyEvent) { + return new com.alibaba.nacos.api.naming.listener.FuzzyWatchNotifyEvent(fuzzyWatchNotifyEvent.getChangedService(), + fuzzyWatchNotifyEvent.getServiceChangedType()); } @Override public Class subscribeType() { - return WatchNotifyEvent.class; + return FuzzyWatchNotifyEvent.class; } @Override - public boolean scopeMatches(WatchNotifyEvent event) { + public boolean scopeMatches(FuzzyWatchNotifyEvent event) { return this.eventScope.equals(event.scope()); } } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxy.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxy.java index e6965a7af5c..145bbf49cbb 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxy.java @@ -183,11 +183,11 @@ ListView getServiceList(int pageNo, int pageSize, String groupName, Abst boolean isSubscribed(String serviceName, String groupName, String clusters) throws NacosException; /** - * Watch services change by pattern. + * Fuzzy watch services change by pattern. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern - * @param uuid UUID used to identify the Listener. Used for local initialization when repeating Watch + * @param uuid UUID used to identify the Listener. Used for local initialization when repeating fuzzy watch * @throws NacosException nacos exception */ void fuzzyWatch(String serviceNamePattern, String groupNamePattern, String uuid) throws NacosException; @@ -201,7 +201,7 @@ ListView getServiceList(int pageNo, int pageSize, String groupName, Abst */ boolean isFuzzyWatched(String serviceNamePattern, String groupNamePattern) throws NacosException; - /** Cancel watch pattern. + /** Cancel fuzzy watch pattern. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java index 1ca9da81731..8d3ed891014 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegate.java @@ -25,7 +25,7 @@ import com.alibaba.nacos.api.selector.AbstractSelector; import com.alibaba.nacos.client.env.NacosClientProperties; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; -import com.alibaba.nacos.client.naming.cache.WatchServiceListHolder; +import com.alibaba.nacos.client.naming.cache.FuzzyWatchServiceListHolder; import com.alibaba.nacos.client.naming.core.ServerListManager; import com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService; import com.alibaba.nacos.client.naming.event.InstancesChangeNotifier; @@ -57,8 +57,8 @@ public class NamingClientProxyDelegate implements NamingClientProxy { private final ServiceInfoUpdateService serviceInfoUpdateService; private final ServiceInfoHolder serviceInfoHolder; - - private final WatchServiceListHolder watchServiceListHolder; + + private final FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder; private final NamingHttpClientProxy httpClientProxy; @@ -68,19 +68,19 @@ public class NamingClientProxyDelegate implements NamingClientProxy { private ScheduledExecutorService executorService; - public NamingClientProxyDelegate(String namespace, ServiceInfoHolder serviceInfoHolder, WatchServiceListHolder watchServiceListHolder, + public NamingClientProxyDelegate(String namespace, ServiceInfoHolder serviceInfoHolder, FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder, NacosClientProperties properties, InstancesChangeNotifier changeNotifier) throws NacosException { this.serviceInfoUpdateService = new ServiceInfoUpdateService(properties, serviceInfoHolder, this, changeNotifier); this.serverListManager = new ServerListManager(properties, namespace); this.serviceInfoHolder = serviceInfoHolder; - this.watchServiceListHolder = watchServiceListHolder; + this.fuzzyWatchServiceListHolder = fuzzyWatchServiceListHolder; this.securityProxy = new SecurityProxy(this.serverListManager.getServerList(), NamingHttpClientManager.getInstance().getNacosRestTemplate()); initSecurityProxy(properties); this.httpClientProxy = new NamingHttpClientProxy(namespace, securityProxy, serverListManager, properties); this.grpcClientProxy = new NamingGrpcClientProxy(namespace, securityProxy, serverListManager, properties, - serviceInfoHolder, watchServiceListHolder); + serviceInfoHolder, fuzzyWatchServiceListHolder); } private void initSecurityProxy(NacosClientProperties properties) { @@ -195,13 +195,13 @@ public boolean isSubscribed(String serviceName, String groupName, String cluster @Override public void fuzzyWatch(String serviceNamePattern, String groupNamePattern, String uuid) throws NacosException { - NAMING_LOGGER.info("[WATCH] serviceNamePattern:{}, groupNamePattern:{}", serviceNamePattern, groupNamePattern); - if (!watchServiceListHolder.containsPatternMatchCache(serviceNamePattern, groupNamePattern) + NAMING_LOGGER.info("[FUZZY-WATCH] serviceNamePattern:{}, groupNamePattern:{}", serviceNamePattern, groupNamePattern); + if (!fuzzyWatchServiceListHolder.containsPatternMatchCache(serviceNamePattern, groupNamePattern) || !isFuzzyWatched(serviceNamePattern, groupNamePattern)) { - watchServiceListHolder.addPatternMatchCache(serviceNamePattern, groupNamePattern); + fuzzyWatchServiceListHolder.addPatternMatchCache(serviceNamePattern, groupNamePattern); grpcClientProxy.fuzzyWatch(serviceNamePattern, groupNamePattern, ""); } else { - watchServiceListHolder.duplicateWatchInit(serviceNamePattern, groupNamePattern, uuid); + fuzzyWatchServiceListHolder.duplicateFuzzyWatchInit(serviceNamePattern, groupNamePattern, uuid); } } @@ -213,8 +213,8 @@ public boolean isFuzzyWatched(String serviceNamePattern, String groupNamePattern @Override public void cancelFuzzyWatch(String serviceNamePattern, String groupNamePattern) throws NacosException { NAMING_LOGGER - .debug("[CANCEL-WATCH] serviceNamePattern:{}, groupNamePattern:{} ", serviceNamePattern, groupNamePattern); - watchServiceListHolder.removePatternMatchCache(serviceNamePattern, groupNamePattern); + .debug("[CANCEL-FUZZY-WATCH] serviceNamePattern:{}, groupNamePattern:{} ", serviceNamePattern, groupNamePattern); + fuzzyWatchServiceListHolder.removePatternMatchCache(serviceNamePattern, groupNamePattern); grpcClientProxy.cancelFuzzyWatch(serviceNamePattern, groupNamePattern); } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java index a6443ce0192..e29be80f042 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java @@ -30,12 +30,12 @@ import com.alibaba.nacos.api.naming.remote.request.ServiceListRequest; import com.alibaba.nacos.api.naming.remote.request.ServiceQueryRequest; import com.alibaba.nacos.api.naming.remote.request.SubscribeServiceRequest; -import com.alibaba.nacos.api.naming.remote.request.WatchServiceRequest; +import com.alibaba.nacos.api.naming.remote.request.FuzzyWatchRequest; import com.alibaba.nacos.api.naming.remote.response.BatchInstanceResponse; import com.alibaba.nacos.api.naming.remote.response.QueryServiceResponse; import com.alibaba.nacos.api.naming.remote.response.ServiceListResponse; import com.alibaba.nacos.api.naming.remote.response.SubscribeServiceResponse; -import com.alibaba.nacos.api.naming.remote.response.WatchServiceResponse; +import com.alibaba.nacos.api.naming.remote.response.FuzzyWatchResponse; import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.api.remote.RemoteConstants; import com.alibaba.nacos.api.remote.response.Response; @@ -44,7 +44,7 @@ import com.alibaba.nacos.api.selector.SelectorType; import com.alibaba.nacos.client.env.NacosClientProperties; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; -import com.alibaba.nacos.client.naming.cache.WatchServiceListHolder; +import com.alibaba.nacos.client.naming.cache.FuzzyWatchServiceListHolder; import com.alibaba.nacos.client.naming.event.ServerListChangedEvent; import com.alibaba.nacos.client.naming.remote.AbstractNamingClientProxy; import com.alibaba.nacos.client.naming.remote.gprc.redo.NamingGrpcRedoService; @@ -91,7 +91,7 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy { public NamingGrpcClientProxy(String namespaceId, SecurityProxy securityProxy, ServerListFactory serverListFactory, NacosClientProperties properties, ServiceInfoHolder serviceInfoHolder, - WatchServiceListHolder watchServiceListHolder) throws NacosException { + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder) throws NacosException { super(securityProxy); this.namespaceId = namespaceId; this.uuid = UUID.randomUUID().toString(); @@ -104,14 +104,15 @@ public NamingGrpcClientProxy(String namespaceId, SecurityProxy securityProxy, Se RpcClientTlsConfig.properties(properties.asProperties())); this.redoService = new NamingGrpcRedoService(this); NAMING_LOGGER.info("Create naming rpc client for uuid->{}", uuid); - start(serverListFactory, serviceInfoHolder, watchServiceListHolder); + start(serverListFactory, serviceInfoHolder, fuzzyWatchServiceListHolder); } private void start(ServerListFactory serverListFactory, ServiceInfoHolder serviceInfoHolder, - WatchServiceListHolder watchServiceListHolder) throws NacosException { + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder) throws NacosException { rpcClient.serverListFactory(serverListFactory); rpcClient.registerConnectionListener(redoService); - rpcClient.registerServerRequestHandler(new NamingPushRequestHandler(serviceInfoHolder, watchServiceListHolder)); + rpcClient.registerServerRequestHandler(new NamingPushRequestHandler(serviceInfoHolder, + fuzzyWatchServiceListHolder)); rpcClient.start(); NotifyCenter.registerSubscriber(this); } @@ -356,53 +357,53 @@ public void doUnsubscribe(String serviceName, String groupName, String clusters) @Override public void fuzzyWatch(String serviceNamePattern, String groupNamePattern, String watcherUuid) throws NacosException { if (NAMING_LOGGER.isDebugEnabled()) { - NAMING_LOGGER.debug("[GRPC-WATCH] servicePattern:{}, groupPattern:{}", serviceNamePattern, groupNamePattern); + NAMING_LOGGER.debug("[GRPC-FUZZY-WATCH] servicePattern:{}, groupPattern:{}", serviceNamePattern, groupNamePattern); } - redoService.cacheWatcherForRedo(serviceNamePattern, groupNamePattern); + redoService.cacheFuzzyWatcherForRedo(serviceNamePattern, groupNamePattern); doFuzzyWatch(serviceNamePattern, groupNamePattern); } /** - * Execute watch operation. + * Execute fuzzy watch operation. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern * @throws NacosException nacos exception */ public void doFuzzyWatch(String serviceNamePattern, String groupNamePattern) throws NacosException { - WatchServiceRequest request = new WatchServiceRequest(namespaceId, serviceNamePattern, groupNamePattern, - NamingRemoteConstants.WATCH_SERVICE); - requestToServer(request, WatchServiceResponse.class); - redoService.watcherRegistered(serviceNamePattern, groupNamePattern); + FuzzyWatchRequest request = new FuzzyWatchRequest(namespaceId, serviceNamePattern, groupNamePattern, + NamingRemoteConstants.FUZZY_WATCH_SERVICE); + requestToServer(request, FuzzyWatchResponse.class); + redoService.fuzzyWatcherRegistered(serviceNamePattern, groupNamePattern); } @Override public boolean isFuzzyWatched(String serviceNamePattern, String groupNamePattern) { - return redoService.isWatcherRegistered(serviceNamePattern, groupNamePattern); + return redoService.isFuzzyWatcherRegistered(serviceNamePattern, groupNamePattern); } @Override public void cancelFuzzyWatch(String serviceNamePattern, String groupNamePattern) throws NacosException { if (NAMING_LOGGER.isDebugEnabled()) { NAMING_LOGGER - .debug("[GRPC-CANCEL-WATCH] serviceNamePattern:{}, groupNamePattern:{}", serviceNamePattern, groupNamePattern); + .debug("[GRPC-CANCEL-FUZZY-WATCH] serviceNamePattern:{}, groupNamePattern:{}", serviceNamePattern, groupNamePattern); } - redoService.watcherDeregister(serviceNamePattern, groupNamePattern); + redoService.fuzzyWatcherDeregister(serviceNamePattern, groupNamePattern); doCancelFuzzyWatch(serviceNamePattern, groupNamePattern); } /** - * Send cancel watch request to server. + * Execute cancel fuzzy watch operation. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern * @throws NacosException nacos exception */ public void doCancelFuzzyWatch(String serviceNamePattern, String groupNamePattern) throws NacosException { - WatchServiceRequest request = new WatchServiceRequest(namespaceId, serviceNamePattern, groupNamePattern, - NamingRemoteConstants.CANCEL_WATCH_SERVICE); - requestToServer(request, WatchServiceResponse.class); - redoService.removeWatcherForRedo(serviceNamePattern, groupNamePattern); + FuzzyWatchRequest request = new FuzzyWatchRequest(namespaceId, serviceNamePattern, groupNamePattern, + NamingRemoteConstants.CANCEL_FUZZY_WATCH_SERVICE); + requestToServer(request, FuzzyWatchResponse.class); + redoService.removeFuzzyWatcherForRedo(serviceNamePattern, groupNamePattern); } @Override diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java index 9cca7c7c52f..bb521228d65 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java @@ -16,14 +16,14 @@ package com.alibaba.nacos.client.naming.remote.gprc; -import com.alibaba.nacos.api.naming.remote.request.AbstractWatchNotifyRequest; +import com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest; import com.alibaba.nacos.api.naming.remote.request.NotifySubscriberRequest; import com.alibaba.nacos.api.naming.remote.response.NotifySubscriberResponse; -import com.alibaba.nacos.api.naming.remote.response.NotifyWatcherResponse; +import com.alibaba.nacos.api.naming.remote.response.NotifyFuzzyWatcherResponse; import com.alibaba.nacos.api.remote.request.Request; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; -import com.alibaba.nacos.client.naming.cache.WatchServiceListHolder; +import com.alibaba.nacos.client.naming.cache.FuzzyWatchServiceListHolder; import com.alibaba.nacos.common.remote.client.ServerRequestHandler; /** @@ -35,11 +35,11 @@ public class NamingPushRequestHandler implements ServerRequestHandler { private final ServiceInfoHolder serviceInfoHolder; - private final WatchServiceListHolder watchServiceListHolder; + private final FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder; - public NamingPushRequestHandler(ServiceInfoHolder serviceInfoHolder, WatchServiceListHolder watchServiceListHolder) { + public NamingPushRequestHandler(ServiceInfoHolder serviceInfoHolder, FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder) { this.serviceInfoHolder = serviceInfoHolder; - this.watchServiceListHolder = watchServiceListHolder; + this.fuzzyWatchServiceListHolder = fuzzyWatchServiceListHolder; } @Override @@ -48,10 +48,10 @@ public Response requestReply(Request request) { NotifySubscriberRequest notifyRequest = (NotifySubscriberRequest) request; serviceInfoHolder.processServiceInfo(notifyRequest.getServiceInfo()); return new NotifySubscriberResponse(); - } else if (request instanceof AbstractWatchNotifyRequest) { - AbstractWatchNotifyRequest notifyRequest = (AbstractWatchNotifyRequest) request; - watchServiceListHolder.processServiceChange(notifyRequest); - return new NotifyWatcherResponse(); + } else if (request instanceof AbstractFuzzyWatchNotifyRequest) { + AbstractFuzzyWatchNotifyRequest notifyRequest = (AbstractFuzzyWatchNotifyRequest) request; + fuzzyWatchServiceListHolder.processFuzzyWatchNotify(notifyRequest); + return new NotifyFuzzyWatcherResponse(); } return null; } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java index f2aeeb1d097..8f78ab55584 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java @@ -23,7 +23,7 @@ import com.alibaba.nacos.client.naming.remote.gprc.redo.data.BatchInstanceRedoData; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.InstanceRedoData; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.SubscriberRedoData; -import com.alibaba.nacos.client.naming.remote.gprc.redo.data.WatcherRedoData; +import com.alibaba.nacos.client.naming.remote.gprc.redo.data.FuzzyWatcherRedoData; import com.alibaba.nacos.client.utils.LogUtils; import com.alibaba.nacos.common.executor.NameThreadFactory; import com.alibaba.nacos.common.remote.client.ConnectionEventListener; @@ -36,7 +36,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; /** * Naming client gprc redo service. @@ -60,7 +59,7 @@ public class NamingGrpcRedoService implements ConnectionEventListener { private final ConcurrentMap subscribes = new ConcurrentHashMap<>(); - private final ConcurrentMap watcher = new ConcurrentHashMap<>(); + private final ConcurrentMap fuzzyWatcher = new ConcurrentHashMap<>(); private final ScheduledExecutorService redoExecutor; @@ -92,8 +91,8 @@ public void onDisConnect() { synchronized (subscribes) { subscribes.values().forEach(subscriberRedoData -> subscriberRedoData.setRegistered(false)); } - synchronized (watcher) { - watcher.values().forEach(watcherRedoData -> watcherRedoData.setRegistered(false)); + synchronized (fuzzyWatcher) { + fuzzyWatcher.values().forEach(fuzzyWatcherRedoData -> fuzzyWatcherRedoData.setRegistered(false)); } LogUtils.NAMING_LOGGER.warn("mark to redo completed"); } @@ -311,29 +310,29 @@ public Set findSubscriberRedoData() { } /** - * Cache watcher for redo. + * Cache fuzzy watcher for redo. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern */ - public void cacheWatcherForRedo(String serviceNamePattern, String groupNamePattern) { + public void cacheFuzzyWatcherForRedo(String serviceNamePattern, String groupNamePattern) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - WatcherRedoData redoData = WatcherRedoData.build(serviceNamePattern, groupNamePattern); - synchronized (watcher) { - watcher.put(key, redoData); + FuzzyWatcherRedoData redoData = FuzzyWatcherRedoData.build(serviceNamePattern, groupNamePattern); + synchronized (fuzzyWatcher) { + fuzzyWatcher.put(key, redoData); } } /** - * Watcher register successfully, mark registered status as {@code true}. + * Fuzzy watcher register successfully, mark registered status as {@code true}. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern */ - public void watcherRegistered(String serviceNamePattern, String groupNamePattern) { + public void fuzzyWatcherRegistered(String serviceNamePattern, String groupNamePattern) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - synchronized (watcher) { - WatcherRedoData redoData = watcher.get(key); + synchronized (fuzzyWatcher) { + FuzzyWatcherRedoData redoData = fuzzyWatcher.get(key); if (null != redoData) { redoData.setRegistered(true); } @@ -341,15 +340,15 @@ public void watcherRegistered(String serviceNamePattern, String groupNamePattern } /** - * Watcher deregister, mark unregistering status as {@code true}. + * Fuzzy watcher deregister, mark unregistering status as {@code true}. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern */ - public void watcherDeregister(String serviceNamePattern, String groupNamePattern) { + public void fuzzyWatcherDeregister(String serviceNamePattern, String groupNamePattern) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - synchronized (watcher) { - WatcherRedoData redoData = watcher.get(key); + synchronized (fuzzyWatcher) { + FuzzyWatcherRedoData redoData = fuzzyWatcher.get(key); if (null != redoData) { redoData.setUnregistering(true); redoData.setExpectedRegistered(false); @@ -358,45 +357,51 @@ public void watcherDeregister(String serviceNamePattern, String groupNamePattern } /** - * Remove watcher for redo. + * Remove fuzzy watcher for redo. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern */ - public void removeWatcherForRedo(String serviceNamePattern, String groupNamePattern) { + public void removeFuzzyWatcherForRedo(String serviceNamePattern, String groupNamePattern) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - synchronized (watcher) { - WatcherRedoData redoData = watcher.get(key); + synchronized (fuzzyWatcher) { + FuzzyWatcherRedoData redoData = fuzzyWatcher.get(key); if (null != redoData && !redoData.isExpectedRegistered()) { - watcher.remove(key); + fuzzyWatcher.remove(key); } } } /** - * Judge watcher has registered to server. + * Judge fuzzy watcher has registered to server. * * @param serviceNamePattern service name pattern * @param groupNamePattern group name pattern * @return {@code true} if watched, otherwise {@code false} */ - public boolean isWatcherRegistered(String serviceNamePattern, String groupNamePattern) { + public boolean isFuzzyWatcherRegistered(String serviceNamePattern, String groupNamePattern) { String key = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); - synchronized (watcher) { - WatcherRedoData redoData = watcher.get(key); + synchronized (fuzzyWatcher) { + FuzzyWatcherRedoData redoData = fuzzyWatcher.get(key); return null != redoData && redoData.isRegistered(); } } /** - * Find all watcher redo data which need do redo. + * Find all fuzzy watcher redo data which need to redo. * - * @return set of {@code WatcherRedoData} need to do redo. + * @return set of {@code WatcherRedoData} need to redo. */ - public Set findWatcherRedoData() { - return watcher.values().stream() - .filter(WatcherRedoData::isNeedRedo) - .collect(Collectors.toSet()); + public Set findFuzzyWatcherRedoData() { + Set result = new HashSet<>(); + synchronized (fuzzyWatcher) { + for (FuzzyWatcherRedoData each : fuzzyWatcher.values()) { + if (each.isNeedRedo()) { + result.add(each); + } + } + } + return result; } /** diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/RedoScheduledTask.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/RedoScheduledTask.java index 355bc09ec40..f9166cc4529 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/RedoScheduledTask.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/RedoScheduledTask.java @@ -22,7 +22,7 @@ import com.alibaba.nacos.client.naming.remote.gprc.redo.data.InstanceRedoData; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.RedoData; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.SubscriberRedoData; -import com.alibaba.nacos.client.naming.remote.gprc.redo.data.WatcherRedoData; +import com.alibaba.nacos.client.naming.remote.gprc.redo.data.FuzzyWatcherRedoData; import com.alibaba.nacos.client.utils.LogUtils; import com.alibaba.nacos.common.task.AbstractExecuteTask; @@ -51,7 +51,7 @@ public void run() { try { redoForInstances(); redoForSubscribes(); - redoForWatchers(); + redoForFuzzyWatchers(); } catch (Exception e) { LogUtils.NAMING_LOGGER.warn("Redo task run with unexpected exception: ", e); } @@ -141,22 +141,22 @@ private void redoForSubscribe(SubscriberRedoData redoData) throws NacosException } } - private void redoForWatchers() { - for (WatcherRedoData each : redoService.findWatcherRedoData()) { + private void redoForFuzzyWatchers() { + for (FuzzyWatcherRedoData each : redoService.findFuzzyWatcherRedoData()) { try { - redoForWatcher(each); + redoForFuzzyWatcher(each); } catch (NacosException e) { - LogUtils.NAMING_LOGGER.error("Redo watcher operation {} for pattern {}@@{}, uuid {} failed. ", each.getRedoType(), - each.getGroupName(), each.getServiceName(), each.get(), e); + LogUtils.NAMING_LOGGER.error("Redo fuzzy watcher operation {} for pattern {}@@{} failed. ", each.getRedoType(), + each.getGroupName(), each.getServiceName(), e); } } } - private void redoForWatcher(WatcherRedoData redoData) throws NacosException { + private void redoForFuzzyWatcher(FuzzyWatcherRedoData redoData) throws NacosException { RedoData.RedoType redoType = redoData.getRedoType(); String serviceNamePattern = redoData.getServiceName(); String groupNamePattern = redoData.getGroupName(); - LogUtils.NAMING_LOGGER.info("Redo watcher operation {} for pattern {}@@{}", redoType, groupNamePattern, serviceNamePattern); + LogUtils.NAMING_LOGGER.info("Redo fuzzy watcher operation {} for pattern {}@@{}", redoType, groupNamePattern, serviceNamePattern); switch (redoType) { case REGISTER: if (isClientDisabled()) { @@ -171,7 +171,7 @@ private void redoForWatcher(WatcherRedoData redoData) throws NacosException { clientProxy.doCancelFuzzyWatch(serviceNamePattern, groupNamePattern); break; case REMOVE: - redoService.removeWatcherForRedo(redoData.getServiceName(), redoData.getGroupName()); + redoService.removeFuzzyWatcherForRedo(serviceNamePattern, groupNamePattern); break; default: } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/data/WatcherRedoData.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/data/FuzzyWatcherRedoData.java similarity index 68% rename from client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/data/WatcherRedoData.java rename to client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/data/FuzzyWatcherRedoData.java index 4a91d3dddc4..f0e820910dd 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/data/WatcherRedoData.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/data/FuzzyWatcherRedoData.java @@ -17,17 +17,17 @@ package com.alibaba.nacos.client.naming.remote.gprc.redo.data; /** - * Redo data for Watcher. + * Redo data for fuzzy watcher. * * @author tanyongquan */ -public class WatcherRedoData extends RedoData { +public class FuzzyWatcherRedoData extends RedoData { - private WatcherRedoData(String serviceNamePattern, String groupNamePattern) { + private FuzzyWatcherRedoData(String serviceNamePattern, String groupNamePattern) { super(serviceNamePattern, groupNamePattern); } - public static WatcherRedoData build(String serviceNamePattern, String groupNamePattern) { - return new WatcherRedoData(serviceNamePattern, groupNamePattern); + public static FuzzyWatcherRedoData build(String serviceNamePattern, String groupNamePattern) { + return new FuzzyWatcherRedoData(serviceNamePattern, groupNamePattern); } } diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/http/NamingHttpClientProxy.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/http/NamingHttpClientProxy.java index 605cc56fe23..23eb39e433f 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/http/NamingHttpClientProxy.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/http/NamingHttpClientProxy.java @@ -344,17 +344,17 @@ public boolean isSubscribed(String serviceName, String groupName, String cluster @Override public void fuzzyWatch(String serviceNamePattern, String groupNamePattern, String uuid) throws NacosException { - throw new UnsupportedOperationException("Do not support watch services by UDP, please use gRPC replaced."); + throw new UnsupportedOperationException("Do not support fuzzy watch services by UDP, please use gRPC replaced."); } @Override public void cancelFuzzyWatch(String serviceNamePattern, String groupNamePattern) throws NacosException { - throw new UnsupportedOperationException("Do not support watch service by UDP, please use gRPC replaced."); + throw new UnsupportedOperationException("Do not support fuzzy watch service by UDP, please use gRPC replaced."); } @Override public boolean isFuzzyWatched(String serviceNamePattern, String groupNamePattern) { - throw new UnsupportedOperationException("Do not support watch service by UDP, please use gRPC replaced."); + throw new UnsupportedOperationException("Do not support fuzzy watch service by UDP, please use gRPC replaced."); } public String reqApi(String api, Map params, String method) throws NacosException { diff --git a/client/src/main/resources/META-INF/native-image/com.alibaba.nacos/nacos-client/reflect-config.json b/client/src/main/resources/META-INF/native-image/com.alibaba.nacos/nacos-client/reflect-config.json index 4e84e144ac7..c3d4eaaf0e1 100644 --- a/client/src/main/resources/META-INF/native-image/com.alibaba.nacos/nacos-client/reflect-config.json +++ b/client/src/main/resources/META-INF/native-image/com.alibaba.nacos/nacos-client/reflect-config.json @@ -348,15 +348,14 @@ ] }, { - "name":"com.alibaba.nacos.api.naming.remote.request.AbstractWatchNotifyRequest", + "name":"com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true, "methods":[ {"name":"","parameterTypes":[] }, {"name":"getModule","parameterTypes":[] }, - {"name":"getServiceChangedType","parameterTypes":[] }, - {"name":"getPattern","parameterTypes":[] } + {"name":"getServiceChangedType","parameterTypes":[] } ] }, { @@ -379,6 +378,28 @@ {"name":"setServiceInfo","parameterTypes":["com.alibaba.nacos.api.naming.pojo.ServiceInfo"] } ] }, +{ + "name":"com.alibaba.nacos.api.naming.remote.request.FuzzyWatchNotifyChangeRequest", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[ + {"name":"","parameterTypes":[] }, + {"name":"getServiceName","parameterTypes":[] }, + {"name":"getGroupName","parameterTypes":[] } + ] +}, +{ + "name":"com.alibaba.nacos.api.naming.remote.request.FuzzyWatchNotifyInitRequest", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[ + {"name":"","parameterTypes":[] }, + {"name":"getServicesName","parameterTypes":[] }, + {"name":"getPattern","parameterTypes":[] } + ] +}, { "name":"com.alibaba.nacos.api.naming.remote.request.SubscribeServiceRequest", "allDeclaredFields":true, diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegateTest.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegateTest.java index 2c5ad2565f1..78b00d56e0d 100644 --- a/client/src/test/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegateTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/NamingClientProxyDelegateTest.java @@ -27,7 +27,7 @@ import com.alibaba.nacos.api.selector.NoneSelector; import com.alibaba.nacos.client.env.NacosClientProperties; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; -import com.alibaba.nacos.client.naming.cache.WatchServiceListHolder; +import com.alibaba.nacos.client.naming.cache.FuzzyWatchServiceListHolder; import com.alibaba.nacos.client.naming.event.InstancesChangeNotifier; import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy; @@ -50,12 +50,12 @@ public class NamingClientProxyDelegateTest { public void testRegisterServiceByGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -78,12 +78,12 @@ public void testRegisterServiceByGrpc() throws NacosException, NoSuchFieldExcept public void testBatchRegisterServiceByGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -107,13 +107,13 @@ public void testBatchRegisterServiceByGrpc() throws NacosException, NoSuchFieldE public void testRegisterServiceByHttp() throws NacosException, NoSuchFieldException, IllegalAccessException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingHttpClientProxy mockHttpClient = Mockito.mock(NamingHttpClientProxy.class); Field mockHttpClientField = NamingClientProxyDelegate.class.getDeclaredField("httpClientProxy"); @@ -137,13 +137,13 @@ public void testRegisterServiceByHttp() throws NacosException, NoSuchFieldExcept public void testDeregisterServiceGrpc() throws NacosException, NoSuchFieldException, IllegalAccessException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -167,13 +167,13 @@ public void testDeregisterServiceGrpc() throws NacosException, NoSuchFieldExcept public void testDeregisterServiceHttp() throws NacosException, NoSuchFieldException, IllegalAccessException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingHttpClientProxy mockHttpClient = Mockito.mock(NamingHttpClientProxy.class); Field mockHttpClientField = NamingClientProxyDelegate.class.getDeclaredField("httpClientProxy"); @@ -197,13 +197,13 @@ public void testDeregisterServiceHttp() throws NacosException, NoSuchFieldExcept public void testUpdateInstance() throws NacosException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); String serviceName = "service1"; String groupName = "group1"; @@ -219,13 +219,13 @@ public void testUpdateInstance() throws NacosException { public void testQueryInstancesOfService() throws NacosException, IllegalAccessException, NoSuchFieldException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -243,13 +243,13 @@ public void testQueryInstancesOfService() throws NacosException, IllegalAccessEx public void testQueryService() throws NacosException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); Service service = delegate.queryService("a", "b"); Assert.assertNull(service); @@ -259,13 +259,13 @@ public void testQueryService() throws NacosException { public void testCreateService() throws NacosException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); Service service = new Service(); try { @@ -279,13 +279,13 @@ public void testCreateService() throws NacosException { public void testDeleteService() throws NacosException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); Assert.assertFalse(delegate.deleteService("service", "group1")); } @@ -294,13 +294,13 @@ public void testDeleteService() throws NacosException { public void testUpdateService() throws NacosException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); Service service = new Service(); try { @@ -314,13 +314,13 @@ public void testUpdateService() throws NacosException { public void testGetServiceList() throws NacosException, NoSuchFieldException, IllegalAccessException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -340,13 +340,13 @@ public void testGetServiceList() throws NacosException, NoSuchFieldException, Il public void testSubscribe() throws NacosException, NoSuchFieldException, IllegalAccessException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -373,13 +373,13 @@ public void testSubscribe() throws NacosException, NoSuchFieldException, Illegal public void testUnsubscribe() throws NacosException, IllegalAccessException, NoSuchFieldException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -398,13 +398,13 @@ public void testUnsubscribe() throws NacosException, IllegalAccessException, NoS public void testServerHealthy() throws IllegalAccessException, NacosException, NoSuchFieldException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); @@ -419,13 +419,13 @@ public void testServerHealthy() throws IllegalAccessException, NacosException, N public void testShutdown() throws NacosException, IllegalAccessException, NoSuchFieldException { String ns = "ns1"; ServiceInfoHolder holder = Mockito.mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = Mockito.mock(WatchServiceListHolder.class); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = Mockito.mock(FuzzyWatchServiceListHolder.class); Properties props = new Properties(); props.setProperty("serverAddr", "localhost"); InstancesChangeNotifier notifier = new InstancesChangeNotifier(); final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(props); - NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, watchServiceListHolder, + NamingClientProxyDelegate delegate = new NamingClientProxyDelegate(ns, holder, fuzzyWatchServiceListHolder, nacosClientProperties, notifier); NamingGrpcClientProxy mockGrpcClient = Mockito.mock(NamingGrpcClientProxy.class); Field grpcClientProxyField = NamingClientProxyDelegate.class.getDeclaredField("grpcClientProxy"); diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxyTest.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxyTest.java index 7890443dd22..9bd64b1b6d1 100644 --- a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxyTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxyTest.java @@ -43,7 +43,7 @@ import com.alibaba.nacos.api.selector.NoneSelector; import com.alibaba.nacos.client.env.NacosClientProperties; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; -import com.alibaba.nacos.client.naming.cache.WatchServiceListHolder; +import com.alibaba.nacos.client.naming.cache.FuzzyWatchServiceListHolder; import com.alibaba.nacos.client.naming.event.ServerListChangedEvent; import com.alibaba.nacos.client.naming.remote.gprc.redo.NamingGrpcRedoService; import com.alibaba.nacos.client.security.SecurityProxy; @@ -114,7 +114,7 @@ public class NamingGrpcClientProxyTest { private ServiceInfoHolder holder; @Mock - private WatchServiceListHolder watchServiceListHolder; + private FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder; @Mock private RpcClient rpcClient; @@ -143,7 +143,7 @@ public void setUp() throws NacosException, NoSuchFieldException, IllegalAccessEx final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); client = new NamingGrpcClientProxy(NAMESPACE_ID, proxy, factory, nacosClientProperties, holder, - watchServiceListHolder); + fuzzyWatchServiceListHolder); Field uuidField = NamingGrpcClientProxy.class.getDeclaredField("uuid"); uuidField.setAccessible(true); @@ -506,7 +506,7 @@ public void close() { rpcClient.set(client, rpc); rpc.serverListFactory(factory); - rpc.registerServerRequestHandler(new NamingPushRequestHandler(holder, watchServiceListHolder)); + rpc.registerServerRequestHandler(new NamingPushRequestHandler(holder, fuzzyWatchServiceListHolder)); Field listenerField = NamingGrpcClientProxy.class.getDeclaredField("redoService"); listenerField.setAccessible(true); NamingGrpcRedoService listener = (NamingGrpcRedoService) listenerField.get(client); @@ -542,7 +542,7 @@ public void close() { public void testConfigAppNameLabels() throws Exception { final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(prop); client = new NamingGrpcClientProxy(NAMESPACE_ID, proxy, factory, nacosClientProperties, holder, - watchServiceListHolder); + fuzzyWatchServiceListHolder); Field rpcClientField = NamingGrpcClientProxy.class.getDeclaredField("rpcClient"); rpcClientField.setAccessible(true); RpcClient rpcClient = (RpcClient) rpcClientField.get(client); diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java index c31da262ed7..0f7075202a4 100644 --- a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java @@ -24,7 +24,7 @@ import com.alibaba.nacos.api.remote.request.Request; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; -import com.alibaba.nacos.client.naming.cache.WatchServiceListHolder; +import com.alibaba.nacos.client.naming.cache.FuzzyWatchServiceListHolder; import org.junit.Assert; import org.junit.Test; @@ -38,8 +38,8 @@ public class NamingPushRequestHandlerTest { public void testRequestReply() { //given ServiceInfoHolder holder = mock(ServiceInfoHolder.class); - WatchServiceListHolder watchServiceListHolder = mock(WatchServiceListHolder.class); - NamingPushRequestHandler handler = new NamingPushRequestHandler(holder, watchServiceListHolder); + FuzzyWatchServiceListHolder fuzzyWatchServiceListHolder = mock(FuzzyWatchServiceListHolder.class); + NamingPushRequestHandler handler = new NamingPushRequestHandler(holder, fuzzyWatchServiceListHolder); ServiceInfo info = new ServiceInfo("name", "cluster1"); Request req = NotifySubscriberRequest.buildNotifySubscriberRequest(info); //when diff --git a/example/src/main/java/com/alibaba/nacos/example/FuzzyWatchExample.java b/example/src/main/java/com/alibaba/nacos/example/FuzzyWatchExample.java new file mode 100644 index 00000000000..b4a8e5b207d --- /dev/null +++ b/example/src/main/java/com/alibaba/nacos/example/FuzzyWatchExample.java @@ -0,0 +1,115 @@ +/* + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * 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 com.alibaba.nacos.example; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingFactory; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.AbstractFuzzyWatchEventListener; +import com.alibaba.nacos.api.naming.listener.FuzzyWatchNotifyEvent; + +import java.util.Properties; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; + +/** + * Nacos naming fuzzy watch example. + *

Add the JVM parameter to run the NamingExample:

+ * {@code -DserverAddr=${nacos.server.ip}:${nacos.server.port} -Dnamespace=${namespaceId}} + * + * @author tanyongquan + */ +public class FuzzyWatchExample { + + public static void main(String[] args) throws NacosException, InterruptedException { + + Properties properties = new Properties(); + properties.setProperty("serverAddr", System.getProperty("serverAddr", "localhost")); + properties.setProperty("namespace", System.getProperty("namespace", "public")); + + NamingService naming = NamingFactory.createNamingService(properties); + + int num = 5; + for (int i = 1; i <= num; i++) { + String s = "nacos.test." + i; + naming.registerInstance(s, "11.11.11.11", 8888); + } + + System.out.println(num + " instance have been registered"); + + Executor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), + runnable -> { + Thread thread = new Thread(runnable); + thread.setName("test-thread"); + return thread; + }); + + naming.fuzzyWatch(DEFAULT_GROUP, new AbstractFuzzyWatchEventListener() { + + //EventListener onEvent is sync to handle, If process too low in onEvent, maybe block other onEvent callback. + //So you can override getExecutor() to async handle event. + @Override + public Executor getExecutor() { + return executor; + } + + @Override + public void onEvent(FuzzyWatchNotifyEvent event) { + System.out.println("[Fuzzy-Watch-GROUP]changed service name: " + event.getService().getGroupedServiceName()); + System.out.println("[Fuzzy-Watch-GROUP]change type: " + event.getChangeType()); + } + }); + + naming.fuzzyWatch("nacos.test", DEFAULT_GROUP, new AbstractFuzzyWatchEventListener() { + + @Override + public Executor getExecutor() { + return executor; + } + + @Override + public void onEvent(FuzzyWatchNotifyEvent event) { + System.out.println("[Prefix-Fuzzy-Watch]changed service name: " + event.getService().getGroupedServiceName()); + System.out.println("[Prefix-Fuzzy-Watch]change type: " + event.getChangeType()); + } + }); + + naming.registerInstance("nacos.test.-1", "11.11.11.11", 8888); + + Thread.sleep(1000); + + naming.registerInstance("nacos.OTHER-PREFIX", "11.11.11.11", 8888); + + Thread.sleep(1000); + + naming.registerInstance("nacos.OTHER-GROUP", "OTHER-GROUP", "11.11.11.11", 8888); + + Thread.sleep(1000); + + for (int i = 1; i <= num; i++) { + String s = "nacos.test." + i; + naming.deregisterInstance(s, "11.11.11.11", 8888); + } + + Thread.sleep(1000); + + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/AbstractClient.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/AbstractClient.java index 23c7086a6f6..097e8c13e7c 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/AbstractClient.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/AbstractClient.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.naming.core.v2.client; import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.utils.ConcurrentHashSet; import com.alibaba.nacos.naming.core.v2.event.client.ClientEvent; import com.alibaba.nacos.naming.core.v2.pojo.BatchInstanceData; import com.alibaba.nacos.naming.core.v2.pojo.BatchInstancePublishInfo; @@ -47,6 +48,8 @@ public abstract class AbstractClient implements Client { protected final ConcurrentHashMap subscribers = new ConcurrentHashMap<>(16, 0.75f, 1); + protected final ConcurrentHashSet watchedPattern = new ConcurrentHashSet<>(); + protected volatile long lastUpdatedTime; protected final AtomicLong revision; @@ -133,6 +136,34 @@ public Collection getAllSubscribeService() { return subscribers.keySet(); } + @Override + public boolean addWatchedPattern(String watchPattern) { + if (watchedPattern.add(watchPattern)) { + // TODO:Watch MetricsMonitor + return true; + } + return true; + } + + @Override + public boolean removeWatchedPattern(String watchPattern) { + if (watchedPattern.remove(watchPattern)) { + // TODO:Watch MetricsMonitor + return true; + } + return true; + } + + @Override + public boolean isWatchedPattern(String watchPattern) { + return watchedPattern.contains(watchPattern); + } + + @Override + public Collection getAllFuzzyWatchPattern() { + return watchedPattern; + } + @Override public ClientSyncData generateSyncData() { List namespaces = new LinkedList<>(); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/Client.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/Client.java index 6cbe0112dc8..94bfb33f7a9 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/Client.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/client/Client.java @@ -122,6 +122,37 @@ public interface Client { */ Collection getAllSubscribeService(); + /** + * Add a watched pattern for this client. + * + * @param pattern watch pattern. + * @return true if add successfully, otherwise false + */ + boolean addWatchedPattern(String pattern); + + /** + * Remove a watched pattern for this client. + * + * @param pattern watch pattern. + * @return true if remove successfully, otherwise false + */ + boolean removeWatchedPattern(String pattern); + + /** + * Judge whether watch this pattern of this client. + * + * @param watchPattern watch patten + * @return true if client watch the given pattern, otherwise false + */ + boolean isWatchedPattern(String watchPattern); + + /** + * Get all watched pattern of current client. + * + * @return watch patterns + */ + Collection getAllFuzzyWatchPattern(); + /** * Generate sync data. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/client/ClientOperationEvent.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/client/ClientOperationEvent.java index 93ecd25cdea..4274cfef9ea 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/client/ClientOperationEvent.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/client/ClientOperationEvent.java @@ -94,6 +94,45 @@ public ClientUnsubscribeServiceEvent(Service service, String clientId) { } } + /** + * Client fuzzy watch service event. + */ + public static class ClientFuzzyWatchEvent extends ClientOperationEvent { + + private static final long serialVersionUID = -4518919987813223119L; + + private final String pattern; + + public ClientFuzzyWatchEvent(String pattern, String clientId) { + super(clientId, null); + this.pattern = pattern; + } + + public String getPattern() { + return pattern; + } + + } + + /** + * Client cancel fuzzy watch service event. + */ + public static class ClientCancelFuzzyWatchEvent extends ClientOperationEvent { + + private static final long serialVersionUID = -4518919987813223118L; + + private final String pattern; + + public ClientCancelFuzzyWatchEvent(String pattern, String clientId) { + super(clientId, null); + this.pattern = pattern; + } + + public String getPattern() { + return pattern; + } + } + public static class ClientReleaseEvent extends ClientOperationEvent { private static final long serialVersionUID = -281486927726245701L; diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/service/ServiceEvent.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/service/ServiceEvent.java index 6d559529880..76ee2a7b2b9 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/service/ServiceEvent.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/event/service/ServiceEvent.java @@ -19,6 +19,8 @@ import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.naming.core.v2.pojo.Service; +import java.util.Collection; + /** * Service event. * @@ -28,7 +30,10 @@ public class ServiceEvent extends Event { private static final long serialVersionUID = -9173247502346692418L; - private final Service service; + private Service service; + + public ServiceEvent() { + } public ServiceEvent(Service service) { this.service = service; @@ -45,17 +50,25 @@ public static class ServiceChangedEvent extends ServiceEvent { private static final long serialVersionUID = 2123694271992630822L; - public ServiceChangedEvent(Service service) { - this(service, false); + private final String changedType; + + public ServiceChangedEvent(Service service, String changedType) { + this(service, changedType, false); } - public ServiceChangedEvent(Service service, boolean incrementRevision) { + public ServiceChangedEvent(Service service, String changedType, boolean incrementRevision) { super(service); + this.changedType = changedType; service.renewUpdateTime(); if (incrementRevision) { service.incrementRevision(); } } + + public String getChangedType() { + return changedType; + } + } /** @@ -77,4 +90,36 @@ public String getClientId() { } } + /** + * A client initiates a fuzzy watch request. + */ + public static class ServiceFuzzyWatchInitEvent extends ServiceEvent { + + private static final long serialVersionUID = -2645441445867337345L; + + private final String clientId; + + private final String pattern; + + private final Collection matchedService; + + public ServiceFuzzyWatchInitEvent(String clientId, String pattern, Collection matchedService) { + super(); + this.clientId = clientId; + this.pattern = pattern; + this.matchedService = matchedService; + } + + public String getClientId() { + return clientId; + } + + public String getPattern() { + return pattern; + } + + public Collection getMatchedService() { + return matchedService; + } + } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManager.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManager.java index d80824f59e6..69865fad06c 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManager.java @@ -16,21 +16,27 @@ package com.alibaba.nacos.naming.core.v2.index; +import com.alibaba.nacos.api.common.Constants; +import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.notify.listener.SmartSubscriber; import com.alibaba.nacos.common.trace.DeregisterInstanceReason; import com.alibaba.nacos.common.trace.event.naming.DeregisterInstanceTraceEvent; +import com.alibaba.nacos.common.utils.CollectionUtils; import com.alibaba.nacos.common.utils.ConcurrentHashSet; +import com.alibaba.nacos.naming.core.v2.ServiceManager; import com.alibaba.nacos.naming.core.v2.client.Client; import com.alibaba.nacos.naming.core.v2.event.client.ClientOperationEvent; import com.alibaba.nacos.naming.core.v2.event.publisher.NamingEventPublisherFactory; import com.alibaba.nacos.naming.core.v2.event.service.ServiceEvent; import com.alibaba.nacos.naming.core.v2.pojo.InstancePublishInfo; import com.alibaba.nacos.naming.core.v2.pojo.Service; +import com.alibaba.nacos.naming.misc.Loggers; import org.springframework.stereotype.Component; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -49,6 +55,16 @@ public class ClientServiceIndexesManager extends SmartSubscriber { private final ConcurrentMap> subscriberIndexes = new ConcurrentHashMap<>(); + /** + * The content of map is {fuzzy watch pattern -> Set[watcher clientID]}. + */ + private final ConcurrentMap> fuzzyWatcherIndexes = new ConcurrentHashMap<>(); + + /** + * The content of map is {service -> Set[matched fuzzy watch patterns]}. + */ + private final ConcurrentMap> fuzzyWatchPatternMatchIndexes = new ConcurrentHashMap<>(); + public ClientServiceIndexesManager() { NotifyCenter.registerSubscriber(this, NamingEventPublisherFactory.getInstance()); } @@ -65,6 +81,15 @@ public Collection getSubscribedService() { return subscriberIndexes.keySet(); } + public Collection getServiceMatchedPatterns(Service service) { + return fuzzyWatchPatternMatchIndexes.containsKey(service) + ? fuzzyWatchPatternMatchIndexes.get(service) : new ConcurrentHashSet<>(); + } + + public Collection getAllClientFuzzyWatchedPattern(String pattern) { + return fuzzyWatcherIndexes.containsKey(pattern) ? fuzzyWatcherIndexes.get(pattern) : new ConcurrentHashSet<>(); + } + /** * Clear the service index without instances. * @@ -73,6 +98,7 @@ public Collection getSubscribedService() { public void removePublisherIndexesByEmptyService(Service service) { if (publisherIndexes.containsKey(service) && publisherIndexes.get(service).isEmpty()) { publisherIndexes.remove(service); + fuzzyWatchPatternMatchIndexes.remove(service); } } @@ -83,6 +109,8 @@ public List> subscribeTypes() { result.add(ClientOperationEvent.ClientDeregisterServiceEvent.class); result.add(ClientOperationEvent.ClientSubscribeServiceEvent.class); result.add(ClientOperationEvent.ClientUnsubscribeServiceEvent.class); + result.add(ClientOperationEvent.ClientFuzzyWatchEvent.class); + result.add(ClientOperationEvent.ClientCancelFuzzyWatchEvent.class); result.add(ClientOperationEvent.ClientReleaseEvent.class); return result; } @@ -101,6 +129,9 @@ private void handleClientDisconnect(ClientOperationEvent.ClientReleaseEvent even for (Service each : client.getAllSubscribeService()) { removeSubscriberIndexes(each, client.getClientId()); } + for (String eachPattern : client.getAllFuzzyWatchPattern()) { + removeFuzzyWatcherIndexes(eachPattern, client.getClientId()); + } DeregisterInstanceReason reason = event.isNative() ? DeregisterInstanceReason.NATIVE_DISCONNECTED : DeregisterInstanceReason.SYNCED_DISCONNECTED; long currentTimeMillis = System.currentTimeMillis(); @@ -124,19 +155,33 @@ private void handleClientOperation(ClientOperationEvent event) { addSubscriberIndexes(service, clientId); } else if (event instanceof ClientOperationEvent.ClientUnsubscribeServiceEvent) { removeSubscriberIndexes(service, clientId); + } else if (event instanceof ClientOperationEvent.ClientFuzzyWatchEvent) { + String completedPattern = ((ClientOperationEvent.ClientFuzzyWatchEvent) event).getPattern(); + addFuzzyWatcherIndexes(completedPattern, clientId); + } else if (event instanceof ClientOperationEvent.ClientCancelFuzzyWatchEvent) { + String completedPattern = ((ClientOperationEvent.ClientCancelFuzzyWatchEvent) event).getPattern(); + removeFuzzyWatcherIndexes(completedPattern, clientId); } } private void addPublisherIndexes(Service service, String clientId) { + String serviceChangedType = Constants.ServiceChangedType.INSTANCE_CHANGED; + if (!publisherIndexes.containsKey(service)) { + // The only time the index needs to be updated is when the service is first created + updateWatchMatchIndex(service); + serviceChangedType = Constants.ServiceChangedType.ADD_SERVICE; + } publisherIndexes.computeIfAbsent(service, key -> new ConcurrentHashSet<>()); publisherIndexes.get(service).add(clientId); - NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true)); + NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, serviceChangedType, true)); } private void removePublisherIndexes(Service service, String clientId) { publisherIndexes.computeIfPresent(service, (s, ids) -> { ids.remove(clientId); - NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true)); + String serviceChangedType = ids.isEmpty() ? Constants.ServiceChangedType.DELETE_SERVICE : + Constants.ServiceChangedType.INSTANCE_CHANGED; + NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, serviceChangedType, true)); return ids.isEmpty() ? null : ids; }); } @@ -158,4 +203,86 @@ private void removeSubscriberIndexes(Service service, String clientId) { subscriberIndexes.remove(service); } } + + private void addFuzzyWatcherIndexes(String completedPattern, String clientId) { + fuzzyWatcherIndexes.computeIfAbsent(completedPattern, key -> new ConcurrentHashSet<>()); + fuzzyWatcherIndexes.get(completedPattern).add(clientId); + Collection matchedService = updateWatchMatchIndex(completedPattern); + NotifyCenter.publishEvent(new ServiceEvent.ServiceFuzzyWatchInitEvent(clientId, completedPattern, matchedService)); + } + + private void removeFuzzyWatcherIndexes(String completedPattern, String clientId) { + if (!fuzzyWatcherIndexes.containsKey(completedPattern)) { + return; + } + fuzzyWatcherIndexes.get(completedPattern).remove(clientId); + if (fuzzyWatcherIndexes.get(completedPattern).isEmpty()) { + fuzzyWatcherIndexes.remove(completedPattern); + } + } + + /** + * This method will build/update the fuzzy watch match index of all patterns. + * + * @param service The service of the Nacos. + */ + public void updateWatchMatchIndex(Service service) { + long matchBeginTime = System.currentTimeMillis(); + Set filteredPattern = NamingUtils.filterPatternWithNamespace(service.getNamespace(), fuzzyWatcherIndexes.keySet()); + Set matchedPattern = NamingUtils.getServiceMatchedPatterns(service.getName(), service.getGroup(), + filteredPattern); + if (CollectionUtils.isNotEmpty(matchedPattern)) { + fuzzyWatchPatternMatchIndexes.computeIfAbsent(service, key -> new ConcurrentHashSet<>()); + for (String each : matchedPattern) { + fuzzyWatchPatternMatchIndexes.get(service).add(NamingUtils.getPatternWithNamespace(service.getNamespace(), each)); + } + Loggers.PERFORMANCE_LOG.info("WATCH: new service {} match {} pattern, {}ms", service.getGroupedServiceName(), + matchedPattern.size(), System.currentTimeMillis() - matchBeginTime); + } + } + + /** + * This method will build/update the fuzzy watch match index for given patterns. + * + * @param completedPattern the completed pattern of watch (with namespace id). + * @return Updated set of services in Nacos server that can match this pattern. + */ + public Collection updateWatchMatchIndex(String completedPattern) { + long matchBeginTime = System.currentTimeMillis(); + String namespaceId = NamingUtils.getNamespaceFromPattern(completedPattern); + Collection serviceSet = ServiceManager.getInstance().getSingletons(namespaceId); + String pattern = NamingUtils.getPatternRemovedNamespace(completedPattern); + + Set matchedService = new HashSet<>(); + for (Service service : serviceSet) { + String serviceName = service.getName(); + String groupName = service.getGroup(); + String serviceNamePattern = NamingUtils.getServiceName(pattern); + String groupNamePattern = NamingUtils.getGroupName(pattern); + if (NamingUtils.isMatchPattern(serviceName, groupName, serviceNamePattern, groupNamePattern)) { + fuzzyWatchPatternMatchIndexes.computeIfAbsent(service, key -> new ConcurrentHashSet<>()); + fuzzyWatchPatternMatchIndexes.get(service).add(completedPattern); + matchedService.add(service); + } + } + Loggers.PERFORMANCE_LOG.info("WATCH: pattern {} match {} services, {}ms", completedPattern, + matchedService.size(), System.currentTimeMillis() - matchBeginTime); + return matchedService; + } + + /** + * This method will remove the match index of fuzzy watch pattern. + * + * @param service The service of the Nacos. + * @param matchedPattern the pattern to remove + */ + public void removeWatchPatternMatchIndex(Service service, String matchedPattern) { + if (!fuzzyWatchPatternMatchIndexes.containsKey(service)) { + return; + } + fuzzyWatchPatternMatchIndexes.get(service).remove(matchedPattern); + if (fuzzyWatchPatternMatchIndexes.get(service).isEmpty()) { + fuzzyWatchPatternMatchIndexes.remove(service); + } + } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/InstanceMetadataProcessor.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/InstanceMetadataProcessor.java index 92cb1ee4f51..d7e6514f287 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/InstanceMetadataProcessor.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/InstanceMetadataProcessor.java @@ -108,7 +108,8 @@ private void updateInstanceMetadata(MetadataOperation op) { Service service = Service.newService(op.getNamespace(), op.getGroup(), op.getServiceName()); service = ServiceManager.getInstance().getSingleton(service); namingMetadataManager.updateInstanceMetadata(service, op.getTag(), op.getMetadata()); - NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true)); + NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, + com.alibaba.nacos.api.common.Constants.ServiceChangedType.INSTANCE_CHANGED, true)); } private void deleteInstanceMetadata(MetadataOperation op) { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationService.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationService.java index 3addf41e62f..b2696dbc68a 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationService.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationService.java @@ -85,6 +85,30 @@ default void unsubscribeService(Service service, Subscriber subscriber, String c } + /** + * Fuzzy watch a pattern. + * + * @param namespaceId namespace id of this pattern + * @param serviceNamePattern watch service name pattern rule + * @param groupNamePattern watch service name pattern rule + * @param clientId id of client + */ + default void fuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + + } + + /** + * Cancel fuzzy watch a pattern. + * + * @param namespaceId namespace id of this pattern + * @param serviceNamePattern watch service name pattern + * @param groupNamePattern watch service name pattern + * @param clientId id of client + */ + default void cancelFuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + + } + /** * get publish info. * diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationServiceProxy.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationServiceProxy.java index 2efa7c6dd9f..7284af587e1 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationServiceProxy.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/ClientOperationServiceProxy.java @@ -85,6 +85,16 @@ public void unsubscribeService(Service service, Subscriber subscriber, String cl ephemeralClientOperationService.unsubscribeService(service, subscriber, clientId); } + @Override + public void fuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + ephemeralClientOperationService.fuzzyWatch(namespaceId, serviceNamePattern, groupNamePattern, clientId); + } + + @Override + public void cancelFuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + ephemeralClientOperationService.cancelFuzzyWatch(namespaceId, serviceNamePattern, groupNamePattern, clientId); + } + private ClientOperationService chooseClientOperationService(final Instance instance) { return instance.isEphemeral() ? ephemeralClientOperationService : persistentClientOperationService; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java index f2223a49f1e..bc7606bf92d 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java @@ -146,6 +146,33 @@ public void unsubscribeService(Service service, Subscriber subscriber, String cl NotifyCenter.publishEvent(new ClientOperationEvent.ClientUnsubscribeServiceEvent(singleton, clientId)); } + @Override + public void fuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + String patternWithoutNamespace = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); + // need store namespace id in server side + String completedPattern = NamingUtils.getPatternWithNamespace(namespaceId, patternWithoutNamespace); + Client client = clientManager.getClient(clientId); + if (!clientIsLegal(client, clientId)) { + return; + } + client.addWatchedPattern(completedPattern); + client.setLastUpdatedTime(); + NotifyCenter.publishEvent(new ClientOperationEvent.ClientFuzzyWatchEvent(completedPattern, clientId)); + } + + @Override + public void cancelFuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + String patternWithoutNamespace = NamingUtils.getGroupedName(serviceNamePattern, groupNamePattern); + String completedPattern = NamingUtils.getPatternWithNamespace(namespaceId, patternWithoutNamespace); + Client client = clientManager.getClient(clientId); + if (!clientIsLegal(client, clientId)) { + return; + } + client.removeWatchedPattern(completedPattern); + client.setLastUpdatedTime(); + NotifyCenter.publishEvent(new ClientOperationEvent.ClientCancelFuzzyWatchEvent(completedPattern, clientId)); + } + private boolean clientIsLegal(Client client, String clientId) { if (client == null) { Loggers.SRV_LOG.warn("Client connection {} already disconnect", clientId); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/PersistentClientOperationServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/PersistentClientOperationServiceImpl.java index e7df05b3ee9..bdfb5180eeb 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/PersistentClientOperationServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/PersistentClientOperationServiceImpl.java @@ -181,6 +181,16 @@ public void unsubscribeService(Service service, Subscriber subscriber, String cl throw new UnsupportedOperationException("No persistent subscribers"); } + @Override + public void fuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + throw new UnsupportedOperationException("No persistent fuzzy watcher"); + } + + @Override + public void cancelFuzzyWatch(String namespaceId, String serviceNamePattern, String groupNamePattern, String clientId) { + throw new UnsupportedOperationException("No persistent fuzzy watcher"); + } + @Override public Response onRequest(ReadRequest request) { throw new UnsupportedOperationException("Temporary does not support"); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatProcessorV2.java b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatProcessorV2.java index dee58b8c67f..d1125aac39a 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatProcessorV2.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/ClientBeatProcessorV2.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.naming.healthcheck.heartbeat; +import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.naming.utils.NamingUtils; import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.trace.event.naming.HealthStateChangeTraceEvent; @@ -67,7 +68,7 @@ public void run() { instance.setHealthy(true); Loggers.EVT_LOG.info("service: {} {POS} {IP-ENABLED} valid: {}:{}@{}, region: {}, msg: client beat ok", rsInfo.getServiceName(), ip, port, rsInfo.getCluster(), UtilsAndCommons.LOCALHOST_SITE); - NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service)); + NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, Constants.ServiceChangedType.HEART_BEAT)); NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(client)); NotifyCenter.publishEvent(new HealthStateChangeTraceEvent(System.currentTimeMillis(), service.getNamespace(), service.getGroup(), service.getName(), instance.getIp(), diff --git a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java index 1614a5cf7aa..b3d65847d56 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/healthcheck/heartbeat/UnhealthyInstanceChecker.java @@ -76,7 +76,7 @@ private void changeHealthyStatus(Client client, Service service, HealthCheckInst .info("{POS} {IP-DISABLED} valid: {}:{}@{}@{}, region: {}, msg: client last beat: {}", instance.getIp(), instance.getPort(), instance.getCluster(), service.getName(), UtilsAndCommons.LOCALHOST_SITE, instance.getLastHeartBeatTime()); - NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service)); + NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, Constants.ServiceChangedType.HEART_BEAT)); NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(client)); NotifyCenter.publishEvent(new HealthStateChangeTraceEvent(System.currentTimeMillis(), service.getNamespace(), service.getGroup(), service.getName(), instance.getIp(), instance.getPort(), diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2Impl.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2Impl.java index 6933779d0a5..2383fb430e2 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2Impl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2Impl.java @@ -16,7 +16,9 @@ package com.alibaba.nacos.naming.push.v2; +import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.api.utils.StringUtils; import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.notify.listener.SmartSubscriber; @@ -33,6 +35,9 @@ import com.alibaba.nacos.naming.pojo.Subscriber; import com.alibaba.nacos.naming.push.NamingSubscriberService; import com.alibaba.nacos.naming.push.v2.executor.PushExecutorDelegate; +import com.alibaba.nacos.naming.push.v2.task.FuzzyWatchInitDelayTask; +import com.alibaba.nacos.naming.push.v2.task.FuzzyWatchNotifyChangeDelayTask; +import com.alibaba.nacos.naming.push.v2.task.FuzzyWatchPushDelayTaskEngine; import com.alibaba.nacos.naming.push.v2.task.PushDelayTask; import com.alibaba.nacos.naming.push.v2.task.PushDelayTaskExecuteEngine; @@ -40,6 +45,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -58,6 +64,8 @@ public class NamingSubscriberServiceV2Impl extends SmartSubscriber implements Na private final PushDelayTaskExecuteEngine delayTaskEngine; + private final FuzzyWatchPushDelayTaskEngine fuzzyWatchPushDelayTaskEngine; + public NamingSubscriberServiceV2Impl(ClientManagerDelegate clientManager, ClientServiceIndexesManager indexesManager, ServiceStorage serviceStorage, NamingMetadataManager metadataManager, PushExecutorDelegate pushExecutor, SwitchDomain switchDomain) { @@ -65,6 +73,8 @@ public NamingSubscriberServiceV2Impl(ClientManagerDelegate clientManager, this.indexesManager = indexesManager; this.delayTaskEngine = new PushDelayTaskExecuteEngine(clientManager, indexesManager, serviceStorage, metadataManager, pushExecutor, switchDomain); + this.fuzzyWatchPushDelayTaskEngine = new FuzzyWatchPushDelayTaskEngine(clientManager, indexesManager, + serviceStorage, metadataManager, pushExecutor, switchDomain); NotifyCenter.registerSubscriber(this, NamingEventPublisherFactory.getInstance()); } @@ -108,6 +118,7 @@ public List> subscribeTypes() { List> result = new LinkedList<>(); result.add(ServiceEvent.ServiceChangedEvent.class); result.add(ServiceEvent.ServiceSubscribedEvent.class); + result.add(ServiceEvent.ServiceFuzzyWatchInitEvent.class); return result; } @@ -118,6 +129,9 @@ public void onEvent(Event event) { ServiceEvent.ServiceChangedEvent serviceChangedEvent = (ServiceEvent.ServiceChangedEvent) event; Service service = serviceChangedEvent.getService(); delayTaskEngine.addTask(service, new PushDelayTask(service, PushConfig.getInstance().getPushTaskDelay())); + // watch notify push task specify by service + fuzzyWatchPushDelayTaskEngine.addTask(service, new FuzzyWatchNotifyChangeDelayTask(service, + serviceChangedEvent.getChangedType(), PushConfig.getInstance().getPushTaskDelay())); MetricsMonitor.incrementServiceChangeCount(service.getNamespace(), service.getGroup(), service.getName()); } else if (event instanceof ServiceEvent.ServiceSubscribedEvent) { // If service is subscribed by one client, only push this client. @@ -125,7 +139,31 @@ public void onEvent(Event event) { Service service = subscribedEvent.getService(); delayTaskEngine.addTask(service, new PushDelayTask(service, PushConfig.getInstance().getPushTaskDelay(), subscribedEvent.getClientId())); + } else if (event instanceof ServiceEvent.ServiceFuzzyWatchInitEvent) { + ServiceEvent.ServiceFuzzyWatchInitEvent serviceFuzzyWatchInitEvent = (ServiceEvent.ServiceFuzzyWatchInitEvent) event; + + String completedPattern = serviceFuzzyWatchInitEvent.getPattern(); + String clientId = serviceFuzzyWatchInitEvent.getClientId(); + String taskKey = getTaskKey(clientId, completedPattern); + Collection matchedService = serviceFuzzyWatchInitEvent.getMatchedService().stream() + .map(Service::getGroupedServiceName) + .collect(Collectors.toSet()); + int originSize = matchedService.size(); + // watch init push task is specify by client id with pattern + // The key is just used to differentiate between different initialization tasks and merge them if needed. + fuzzyWatchPushDelayTaskEngine.addTask(taskKey, new FuzzyWatchInitDelayTask(taskKey, clientId, completedPattern, matchedService, + originSize, PushConfig.getInstance().getPushTaskDelay(), false)); + } + } + + private String getTaskKey(String clientId, String pattern) { + if (StringUtils.isBlank(clientId)) { + throw new IllegalArgumentException("Param 'clientId' is illegal, clientId is blank"); + } + if (StringUtils.isBlank(pattern)) { + throw new IllegalArgumentException("Param 'pattern' is illegal, pattern is blank"); } + return clientId + Constants.SERVICE_INFO_SPLITER + pattern; } private Stream getServiceStream() { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutor.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutor.java index 21bcfab0d4b..553ac555a5f 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutor.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutor.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.naming.push.v2.executor; +import com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest; +import com.alibaba.nacos.api.remote.PushCallBack; import com.alibaba.nacos.naming.pojo.Subscriber; import com.alibaba.nacos.naming.push.v2.PushDataWrapper; import com.alibaba.nacos.naming.push.v2.task.NamingPushCallback; @@ -45,4 +47,23 @@ public interface PushExecutor { * @param callBack callback */ void doPushWithCallback(String clientId, Subscriber subscriber, PushDataWrapper data, NamingPushCallback callBack); + + + /** + * Do push to notify fuzzy watcher. + * + * @param clientId client id + * @param fuzzyWatchNotifyRequest request for fuzzy watch notification + */ + void doWatcherNotifyPush(String clientId, AbstractFuzzyWatchNotifyRequest fuzzyWatchNotifyRequest); + + /** + * Do push to notify fuzzy watcher with call back. + * + * @param clientId client id + * @param fuzzyWatchNotifyRequest request for fuzzy watch notification + * @param callBack callback + */ + void doFuzzyWatchNotifyPushWithCallBack(String clientId, AbstractFuzzyWatchNotifyRequest fuzzyWatchNotifyRequest, PushCallBack callBack); + } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorDelegate.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorDelegate.java index f1fa7288e07..4acad457d27 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorDelegate.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorDelegate.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.naming.push.v2.executor; +import com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest; +import com.alibaba.nacos.api.remote.PushCallBack; import com.alibaba.nacos.naming.core.v2.client.impl.IpPortBasedClient; import com.alibaba.nacos.naming.pojo.Subscriber; import com.alibaba.nacos.naming.push.v2.PushDataWrapper; @@ -53,6 +55,19 @@ public void doPushWithCallback(String clientId, Subscriber subscriber, PushDataW getPushExecuteService(clientId, subscriber).doPushWithCallback(clientId, subscriber, data, callBack); } + @Override + public void doWatcherNotifyPush(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest) { + // only support fuzzy watch by rpc + rpcPushExecuteService.doWatcherNotifyPush(clientId, watchNotifyRequest); + } + + @Override + public void doFuzzyWatchNotifyPushWithCallBack(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest, + PushCallBack callBack) { + // only support fuzzy watch by rpc + rpcPushExecuteService.doFuzzyWatchNotifyPushWithCallBack(clientId, watchNotifyRequest, callBack); + } + private PushExecutor getPushExecuteService(String clientId, Subscriber subscriber) { Optional result = SpiImplPushExecutorHolder.getInstance() .findPushExecutorSpiImpl(clientId, subscriber); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorRpcImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorRpcImpl.java index 143d4715bdf..d540ca54223 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorRpcImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorRpcImpl.java @@ -17,7 +17,9 @@ package com.alibaba.nacos.naming.push.v2.executor; import com.alibaba.nacos.api.naming.pojo.ServiceInfo; +import com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest; import com.alibaba.nacos.api.naming.remote.request.NotifySubscriberRequest; +import com.alibaba.nacos.api.remote.PushCallBack; import com.alibaba.nacos.core.remote.RpcPushService; import com.alibaba.nacos.naming.misc.GlobalExecutor; import com.alibaba.nacos.naming.pojo.Subscriber; @@ -60,4 +62,15 @@ private ServiceInfo getServiceInfo(PushDataWrapper data, Subscriber subscriber) .selectInstancesWithHealthyProtection(data.getOriginalData(), data.getServiceMetadata(), false, true, subscriber); } + + @Override + public void doWatcherNotifyPush(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest) { + pushService.pushWithoutAck(clientId, watchNotifyRequest); + } + + @Override + public void doFuzzyWatchNotifyPushWithCallBack(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest, PushCallBack callBack) { + pushService.pushWithCallback(clientId, watchNotifyRequest, callBack, GlobalExecutor.getCallbackExecutor()); + } + } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorUdpImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorUdpImpl.java index c60478166d9..3324a3345d2 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorUdpImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/executor/PushExecutorUdpImpl.java @@ -17,7 +17,9 @@ package com.alibaba.nacos.naming.push.v2.executor; import com.alibaba.nacos.api.naming.pojo.ServiceInfo; +import com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest; import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.api.remote.PushCallBack; import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.naming.pojo.Subscriber; import com.alibaba.nacos.naming.push.UdpPushService; @@ -93,4 +95,14 @@ private ServiceInfo handleClusterData(ServiceInfo data, Subscriber subscriber) { return StringUtils.isBlank(subscriber.getCluster()) ? data : ServiceUtil.selectInstances(data, subscriber.getCluster()); } + + @Override + public void doWatcherNotifyPush(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest) { + + } + + @Override + public void doFuzzyWatchNotifyPushWithCallBack(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest, PushCallBack callBack) { + + } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitDelayTask.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitDelayTask.java new file mode 100644 index 00000000000..3e5f9c66c28 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitDelayTask.java @@ -0,0 +1,91 @@ +/* + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * 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 com.alibaba.nacos.naming.push.v2.task; + +import com.alibaba.nacos.common.task.AbstractDelayTask; +import com.alibaba.nacos.naming.misc.Loggers; + +import java.util.Collection; + +/** + * Nacos naming fuzzy watch initial push delay task. + * + * @author tanyongquan + */ +public class FuzzyWatchInitDelayTask extends AbstractDelayTask { + + private final String taskKey; + + private final String clientId; + + private final String pattern; + + private final Collection matchedService; + + private final int originSize; + + private final boolean isFinishInit; + + public FuzzyWatchInitDelayTask(String taskKey, String clientId, String pattern, Collection matchedService, + int originSize, long delay, boolean isFinishInit) { + this.taskKey = taskKey; + this.clientId = clientId; + this.pattern = pattern; + this.matchedService = matchedService; + this.originSize = originSize; + this.isFinishInit = isFinishInit; + setTaskInterval(delay); + setLastProcessTime(System.currentTimeMillis()); + } + + @Override + public void merge(AbstractDelayTask task) { + if (!(task instanceof FuzzyWatchInitDelayTask)) { + return; + } + FuzzyWatchInitDelayTask oldTask = (FuzzyWatchInitDelayTask) task; + if (!isFinishInit) { + matchedService.addAll(oldTask.getMatchedService()); + } + setLastProcessTime(Math.min(getLastProcessTime(), task.getLastProcessTime())); + Loggers.PUSH.info("[FUZZY-WATCH-INIT-PUSH] Task merge for pattern {}", pattern); + } + + public String getTaskKey() { + return taskKey; + } + + public String getPattern() { + return pattern; + } + + public Collection getMatchedService() { + return matchedService; + } + + public boolean isFinishInit() { + return isFinishInit; + } + + public int getOriginSize() { + return originSize; + } + + public String getClientId() { + return clientId; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitExecuteTask.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitExecuteTask.java new file mode 100644 index 00000000000..b4cb47469ea --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchInitExecuteTask.java @@ -0,0 +1,209 @@ +/* + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * 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 com.alibaba.nacos.naming.push.v2.task; + +import com.alibaba.nacos.api.naming.remote.request.FuzzyWatchNotifyInitRequest; +import com.alibaba.nacos.api.naming.utils.NamingUtils; +import com.alibaba.nacos.api.remote.PushCallBack; +import com.alibaba.nacos.common.task.AbstractExecuteTask; +import com.alibaba.nacos.naming.core.v2.client.Client; +import com.alibaba.nacos.naming.core.v2.client.manager.ClientManager; +import com.alibaba.nacos.naming.misc.Loggers; +import com.alibaba.nacos.naming.push.v2.NoRequiredRetryException; +import com.alibaba.nacos.naming.push.v2.PushConfig; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Nacos naming fuzzy watch initial push execute task. + * + * @author tanyongquan + */ +public class FuzzyWatchInitExecuteTask extends AbstractExecuteTask { + + private final String taskKey; + + private final String clientId; + + private final String pattern; + + private final FuzzyWatchPushDelayTaskEngine delayTaskEngine; + + private final FuzzyWatchInitDelayTask delayTask; + + /** + * Fuzzy watch origin push matched service size, if there is no failure while executing push, {@code originSize == latch}. + * just use to record log after finish all push. + */ + private final int originSize; + + private final int latch; + + /** + * TODO set batch size from config. + */ + private final int batchSize = 10; + + private int sendCount; + + private boolean isFinishInitTask; + + private boolean haveFailPush; + + public FuzzyWatchInitExecuteTask(String taskKey, String clientId, String pattern, int originSize, + FuzzyWatchPushDelayTaskEngine delayTaskEngine, FuzzyWatchInitDelayTask delayTask, boolean isFinishInitTask) { + this.taskKey = taskKey; + this.clientId = clientId; + this.pattern = pattern; + this.delayTaskEngine = delayTaskEngine; + this.delayTask = delayTask; + this.originSize = originSize; + this.latch = delayTask.getMatchedService().size(); + this.sendCount = 0; + this.isFinishInitTask = isFinishInitTask; + this.haveFailPush = false; + } + + @Override + public void run() { + ClientManager clientManager = delayTaskEngine.getClientManager(); + Collection> dividedServices = divideServiceByBatch(delayTask.getMatchedService()); + Client client = clientManager.getClient(clientId); + String patternWithoutNameSpace = NamingUtils.getPatternRemovedNamespace(pattern); + String nameSpaceId = NamingUtils.getNamespaceFromPattern(pattern); + if (null == client) { + return; + } + if (!client.isWatchedPattern(pattern)) { + return; + } + if (isFinishInitTask || delayTask.getMatchedService().isEmpty()) { + // do not match any exist service, just finish init + delayTaskEngine.getPushExecutor().doFuzzyWatchNotifyPushWithCallBack(clientId, + FuzzyWatchNotifyInitRequest.buildInitFinishRequest(nameSpaceId, patternWithoutNameSpace), + new FuzzyWatchInitPushCallback(clientId, null, originSize, true, haveFailPush)); + } else { + for (Collection batchData : dividedServices) { + delayTaskEngine.getPushExecutor().doFuzzyWatchNotifyPushWithCallBack(clientId, FuzzyWatchNotifyInitRequest.buildInitRequest( + nameSpaceId, patternWithoutNameSpace, batchData), + new FuzzyWatchInitPushCallback(clientId, batchData, originSize, false, haveFailPush)); + } + } + + } + + private Collection> divideServiceByBatch(Collection matchedService) { + Collection> result = new ArrayList<>(); + if (matchedService.isEmpty()) { + return result; + } + Set currentBatch = new HashSet<>(); + for (String groupedServiceName : matchedService) { + currentBatch.add(groupedServiceName); + if (currentBatch.size() >= this.batchSize) { + result.add(currentBatch); + currentBatch = new HashSet<>(); + } + } + if (!currentBatch.isEmpty()) { + result.add(currentBatch); + } + return result; + } + + private class FuzzyWatchInitPushCallback implements PushCallBack { + + private final String clientId; + + private final Collection groupedServiceName; + + private final int originSize; + + /** + * Record the push task execute start time. + */ + private final long executeStartTime; + + private boolean isFinishInitTask; + + private boolean haveFailPush; + + private FuzzyWatchInitPushCallback(String clientId, Collection groupedServiceName, int originSize, + boolean isFinishInitTask, boolean haveFailPush) { + this.clientId = clientId; + this.groupedServiceName = groupedServiceName; + this.originSize = originSize; + this.executeStartTime = System.currentTimeMillis(); + this.isFinishInitTask = isFinishInitTask; + this.haveFailPush = haveFailPush; + } + + @Override + public long getTimeout() { + return PushConfig.getInstance().getPushTaskTimeout(); + } + + @Override + public void onSuccess() { + long pushFinishTime = System.currentTimeMillis(); + long pushCostTimeForNetWork = pushFinishTime - executeStartTime; + long pushCostTimeForAll = pushFinishTime - delayTask.getLastProcessTime(); + + if (isFinishInitTask) { + Loggers.PUSH.info("[FUZZY-WATCH-INIT-COMPLETE] {}ms, all delay time {}ms for client {} watch init push finish," + + " pattern {}, all push service size {}", + pushCostTimeForNetWork, pushCostTimeForAll, clientId, pattern, originSize); + } else { + Loggers.PUSH.info("[FUZZY-WATCH-PUSH-SUCC] {}ms, all delay time {}ms for client {}, pattern {}, push size {} : {}", + pushCostTimeForNetWork, pushCostTimeForAll, clientId, pattern, groupedServiceName.size(), + groupedServiceName); + sendCount += groupedServiceName.size(); + // this task is an init push task(not finish notify), and with no failure in this task when executing push batched services + if (!haveFailPush && sendCount >= latch) { + delayTaskEngine.addTask(taskKey, new FuzzyWatchInitDelayTask(taskKey, clientId, pattern, null, + originSize, PushConfig.getInstance().getPushTaskDelay(), true)); + } + } + } + + @Override + public void onFail(Throwable e) { + long pushCostTime = System.currentTimeMillis() - executeStartTime; + Loggers.PUSH.error("[FUZZY-WATCH-PUSH-FAIL] {}ms, pattern {} match {} service: {}, reason={}, client={}", pushCostTime, pattern, + groupedServiceName.size(), groupedServiceName, e.getMessage(), clientId); + setHaveFailPush(true); + if (!(e instanceof NoRequiredRetryException)) { + Loggers.PUSH.error("Reason detail: ", e); + if (isFinishInitTask) { + delayTaskEngine.addTask(taskKey, new FuzzyWatchInitDelayTask(taskKey, clientId, pattern, null, + originSize, PushConfig.getInstance().getPushTaskRetryDelay(), true)); + } else { + delayTaskEngine.addTask(taskKey, new FuzzyWatchInitDelayTask(taskKey, clientId, pattern, groupedServiceName, + originSize, PushConfig.getInstance().getPushTaskRetryDelay(), false)); + } + + } + } + } + + private void setHaveFailPush(boolean haveFailPush) { + this.haveFailPush = haveFailPush; + } +} \ No newline at end of file diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeDelayTask.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeDelayTask.java new file mode 100644 index 00000000000..e6e8a1893b7 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeDelayTask.java @@ -0,0 +1,90 @@ +/* + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * 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 com.alibaba.nacos.naming.push.v2.task; + +import com.alibaba.nacos.common.task.AbstractDelayTask; +import com.alibaba.nacos.naming.core.v2.pojo.Service; +import com.alibaba.nacos.naming.misc.Loggers; + +import java.util.HashSet; +import java.util.Set; + +/** + * Nacos naming fuzzy watch notify service change push delay task. + * + * @author tanyongquan + */ +public class FuzzyWatchNotifyChangeDelayTask extends AbstractDelayTask { + private final Service service; + + private final String serviceChangedType; + + private boolean pushToAll; + + private Set targetClients; + + public FuzzyWatchNotifyChangeDelayTask(Service service, String serviceChangedType, long delay) { + this.service = service; + this.serviceChangedType = serviceChangedType; + pushToAll = true; + targetClients = null; + setTaskInterval(delay); + setLastProcessTime(System.currentTimeMillis()); + } + + public FuzzyWatchNotifyChangeDelayTask(Service service, String serviceChangedType, long delay, String targetClient) { + this.service = service; + this.serviceChangedType = serviceChangedType; + this.pushToAll = false; + this.targetClients = new HashSet<>(1); + this.targetClients.add(targetClient); + setTaskInterval(delay); + setLastProcessTime(System.currentTimeMillis()); + } + + @Override + public void merge(AbstractDelayTask task) { + if (!(task instanceof FuzzyWatchNotifyChangeDelayTask)) { + return; + } + FuzzyWatchNotifyChangeDelayTask oldTask = (FuzzyWatchNotifyChangeDelayTask) task; + if (isPushToAll() || oldTask.isPushToAll()) { + pushToAll = true; + targetClients = null; + } else { + targetClients.addAll(oldTask.getTargetClients()); + } + setLastProcessTime(Math.min(getLastProcessTime(), task.getLastProcessTime())); + Loggers.PUSH.info("[FUZZY-WATCH-PUSH] Task merge for {}", service); + } + + public Service getService() { + return service; + } + + public boolean isPushToAll() { + return pushToAll; + } + + public String getServiceChangedType() { + return serviceChangedType; + } + + public Set getTargetClients() { + return targetClients; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeExecuteTask.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeExecuteTask.java new file mode 100644 index 00000000000..49e1d7a07d2 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchNotifyChangeExecuteTask.java @@ -0,0 +1,145 @@ +/* + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * 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 com.alibaba.nacos.naming.push.v2.task; + +import com.alibaba.nacos.api.naming.remote.request.FuzzyWatchNotifyChangeRequest; +import com.alibaba.nacos.api.remote.PushCallBack; +import com.alibaba.nacos.common.task.AbstractExecuteTask; +import com.alibaba.nacos.naming.core.v2.client.Client; +import com.alibaba.nacos.naming.core.v2.client.manager.ClientManager; +import com.alibaba.nacos.naming.core.v2.index.ClientServiceIndexesManager; +import com.alibaba.nacos.naming.core.v2.pojo.Service; +import com.alibaba.nacos.naming.misc.Loggers; +import com.alibaba.nacos.naming.push.v2.NoRequiredRetryException; +import com.alibaba.nacos.naming.push.v2.PushConfig; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Nacos naming fuzzy watch notify service change push execute task. + * + * @author tanyongquan + */ +public class FuzzyWatchNotifyChangeExecuteTask extends AbstractExecuteTask { + + private final Service service; + + private final FuzzyWatchPushDelayTaskEngine delayTaskEngine; + + private final FuzzyWatchNotifyChangeDelayTask delayTask; + + public FuzzyWatchNotifyChangeExecuteTask(Service service, FuzzyWatchPushDelayTaskEngine delayTaskEngine, + FuzzyWatchNotifyChangeDelayTask delayTask) { + this.service = service; + this.delayTaskEngine = delayTaskEngine; + this.delayTask = delayTask; + } + + @Override + public void run() { + try { + ClientManager clientManager = delayTaskEngine.getClientManager(); + String serviceChangedType = delayTask.getServiceChangedType(); + for (String clientId : getWatchTargetClientIds()) { + Client client = clientManager.getClient(clientId); + if (null == client) { + continue; + } + delayTaskEngine.getPushExecutor().doFuzzyWatchNotifyPushWithCallBack(clientId, new FuzzyWatchNotifyChangeRequest( + service.getNamespace(), service.getName(), service.getGroup(), serviceChangedType), + new WatchNotifyPushCallback(clientId, serviceChangedType)); + } + } catch (Exception e) { + Loggers.PUSH.error("Fuzzy watch notify task for service" + service.getGroupedServiceName() + " execute failed ", e); + delayTaskEngine.addTask(service, new FuzzyWatchNotifyChangeDelayTask(service, delayTask.getServiceChangedType(), 1000L)); + } + } + + /** + * get watch notify client id. + * + * @return A set of ClientID need to be notified + */ + private Set getWatchTargetClientIds() { + if (!delayTask.isPushToAll()) { + return delayTask.getTargetClients(); + } + Set watchNotifyClientIds = new HashSet<>(16); + ClientServiceIndexesManager indexesManager = delayTaskEngine.getIndexesManager(); + // get match result from index + Collection matchedPatterns = indexesManager.getServiceMatchedPatterns(service); + + for (String eachPattern : matchedPatterns) { + // for every matched pattern, get client id which watching this pattern + Collection clientIDs = indexesManager.getAllClientFuzzyWatchedPattern(eachPattern); + if (clientIDs == null || clientIDs.isEmpty()) { + // find there is nobody watch this pattern anymore (lazy remove) + indexesManager.removeWatchPatternMatchIndex(service, eachPattern); + continue; + } + watchNotifyClientIds.addAll(clientIDs); + } + return watchNotifyClientIds; + } + + private class WatchNotifyPushCallback implements PushCallBack { + + private final String clientId; + + private final String serviceChangedType; + + /** + * Record the push task execute start time. + */ + private final long executeStartTime; + + private WatchNotifyPushCallback(String clientId, String serviceChangedType) { + this.clientId = clientId; + this.serviceChangedType = serviceChangedType; + this.executeStartTime = System.currentTimeMillis(); + } + + @Override + public long getTimeout() { + return PushConfig.getInstance().getPushTaskTimeout(); + } + + @Override + public void onSuccess() { + long pushFinishTime = System.currentTimeMillis(); + long pushCostTimeForNetWork = pushFinishTime - executeStartTime; + long pushCostTimeForAll = pushFinishTime - delayTask.getLastProcessTime(); + + Loggers.PUSH.info("[WATCH-PUSH-SUCC] {}ms, all delay time {}ms for client {}, service {}, changed type {} ", + pushCostTimeForNetWork, pushCostTimeForAll, clientId, service.getGroupedServiceName(), serviceChangedType); + } + + @Override + public void onFail(Throwable e) { + long pushCostTime = System.currentTimeMillis() - executeStartTime; + Loggers.PUSH.error("[WATCH-PUSH-FAIL] {}ms, service {}, changed type {}, reason={}, client={}", pushCostTime, + service.getGroupedServiceName(), serviceChangedType, e.getMessage(), clientId); + if (!(e instanceof NoRequiredRetryException)) { + Loggers.PUSH.error("Reason detail: ", e); + delayTaskEngine.addTask(service, new FuzzyWatchNotifyChangeDelayTask(service, + serviceChangedType, PushConfig.getInstance().getPushTaskDelay(), clientId)); + } + } + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchPushDelayTaskEngine.java b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchPushDelayTaskEngine.java new file mode 100644 index 00000000000..dba23e8bab5 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/push/v2/task/FuzzyWatchPushDelayTaskEngine.java @@ -0,0 +1,120 @@ +/* + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * 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 com.alibaba.nacos.naming.push.v2.task; + +import com.alibaba.nacos.common.task.NacosTask; +import com.alibaba.nacos.common.task.NacosTaskProcessor; +import com.alibaba.nacos.common.task.engine.NacosDelayTaskExecuteEngine; +import com.alibaba.nacos.naming.core.v2.client.manager.ClientManager; +import com.alibaba.nacos.naming.core.v2.index.ClientServiceIndexesManager; +import com.alibaba.nacos.naming.core.v2.index.ServiceStorage; +import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager; +import com.alibaba.nacos.naming.core.v2.pojo.Service; +import com.alibaba.nacos.naming.misc.Loggers; +import com.alibaba.nacos.naming.misc.NamingExecuteTaskDispatcher; +import com.alibaba.nacos.naming.misc.SwitchDomain; +import com.alibaba.nacos.naming.push.v2.executor.PushExecutor; + +/** + * Nacos naming fuzzy watch notify service change push delay task execute engine. + * + * @author tanyongquan + */ +public class FuzzyWatchPushDelayTaskEngine extends NacosDelayTaskExecuteEngine { + + private final ClientManager clientManager; + + private final ClientServiceIndexesManager indexesManager; + + private final ServiceStorage serviceStorage; + + private final NamingMetadataManager metadataManager; + + private final PushExecutor pushExecutor; + + private final SwitchDomain switchDomain; + + public FuzzyWatchPushDelayTaskEngine(ClientManager clientManager, ClientServiceIndexesManager indexesManager, + ServiceStorage serviceStorage, NamingMetadataManager metadataManager, + PushExecutor pushExecutor, SwitchDomain switchDomain) { + super(FuzzyWatchPushDelayTaskEngine.class.getSimpleName(), Loggers.PUSH); + this.clientManager = clientManager; + this.indexesManager = indexesManager; + this.serviceStorage = serviceStorage; + this.metadataManager = metadataManager; + this.pushExecutor = pushExecutor; + this.switchDomain = switchDomain; + setDefaultTaskProcessor(new WatchPushDelayTaskProcessor(this)); + } + + public ClientManager getClientManager() { + return clientManager; + } + + public ClientServiceIndexesManager getIndexesManager() { + return indexesManager; + } + + public ServiceStorage getServiceStorage() { + return serviceStorage; + } + + public NamingMetadataManager getMetadataManager() { + return metadataManager; + } + + public PushExecutor getPushExecutor() { + return pushExecutor; + } + + @Override + protected void processTasks() { + if (!switchDomain.isPushEnabled()) { + return; + } + super.processTasks(); + } + + private static class WatchPushDelayTaskProcessor implements NacosTaskProcessor { + + private final FuzzyWatchPushDelayTaskEngine executeEngine; + + public WatchPushDelayTaskProcessor(FuzzyWatchPushDelayTaskEngine executeEngine) { + this.executeEngine = executeEngine; + } + + @Override + public boolean process(NacosTask task) { + if (task instanceof FuzzyWatchNotifyChangeDelayTask) { + FuzzyWatchNotifyChangeDelayTask notifyDelayTask = (FuzzyWatchNotifyChangeDelayTask) task; + Service service = notifyDelayTask.getService(); + NamingExecuteTaskDispatcher.getInstance() + .dispatchAndExecuteTask(service, new FuzzyWatchNotifyChangeExecuteTask(service, executeEngine, notifyDelayTask)); + } else if (task instanceof FuzzyWatchInitDelayTask) { + FuzzyWatchInitDelayTask fuzzyWatchInitDelayTask = (FuzzyWatchInitDelayTask) task; + String pattern = fuzzyWatchInitDelayTask.getPattern(); + String clientId = fuzzyWatchInitDelayTask.getClientId(); + String taskKey = fuzzyWatchInitDelayTask.getTaskKey(); + NamingExecuteTaskDispatcher.getInstance() + .dispatchAndExecuteTask(taskKey, new FuzzyWatchInitExecuteTask(taskKey, clientId, pattern, + fuzzyWatchInitDelayTask.getOriginSize(), executeEngine, fuzzyWatchInitDelayTask, + fuzzyWatchInitDelayTask.isFinishInit())); + } + return true; + } + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/remote/rpc/handler/FuzzyWatchRequestHandler.java b/naming/src/main/java/com/alibaba/nacos/naming/remote/rpc/handler/FuzzyWatchRequestHandler.java new file mode 100644 index 00000000000..bd7f07f0147 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/remote/rpc/handler/FuzzyWatchRequestHandler.java @@ -0,0 +1,63 @@ +/* + * Copyright 1999-2023 Alibaba Group Holding Ltd. + * + * 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 com.alibaba.nacos.naming.remote.rpc.handler; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.remote.NamingRemoteConstants; +import com.alibaba.nacos.api.naming.remote.request.FuzzyWatchRequest; +import com.alibaba.nacos.api.naming.remote.response.FuzzyWatchResponse; +import com.alibaba.nacos.api.remote.request.RequestMeta; +import com.alibaba.nacos.auth.annotation.Secured; +import com.alibaba.nacos.core.remote.RequestHandler; +import com.alibaba.nacos.naming.core.v2.service.impl.EphemeralClientOperationServiceImpl; +import com.alibaba.nacos.plugin.auth.constant.ActionTypes; +import org.springframework.stereotype.Component; + +/** + * Fuzzy watch service request handler. + * + * @author tanyongquan + */ +@Component("fuzzyWatchRequestHandler") +public class FuzzyWatchRequestHandler extends RequestHandler { + + private final EphemeralClientOperationServiceImpl clientOperationService; + + public FuzzyWatchRequestHandler(EphemeralClientOperationServiceImpl clientOperationService) { + this.clientOperationService = clientOperationService; + } + + @Override + @Secured(action = ActionTypes.READ) + public FuzzyWatchResponse handle(FuzzyWatchRequest request, RequestMeta meta) throws NacosException { + String serviceNamePattern = request.getServiceName(); + String groupNamePattern = request.getGroupName(); + String namespaceId = request.getNamespace(); + + switch (request.getType()) { + case NamingRemoteConstants.FUZZY_WATCH_SERVICE: + clientOperationService.fuzzyWatch(namespaceId, serviceNamePattern, groupNamePattern, meta.getConnectionId()); + return FuzzyWatchResponse.buildSuccessResponse(NamingRemoteConstants.FUZZY_WATCH_SERVICE); + case NamingRemoteConstants.CANCEL_FUZZY_WATCH_SERVICE: + clientOperationService.cancelFuzzyWatch(namespaceId, serviceNamePattern, groupNamePattern, meta.getConnectionId()); + return FuzzyWatchResponse.buildSuccessResponse(NamingRemoteConstants.CANCEL_FUZZY_WATCH_SERVICE); + default: + throw new NacosException(NacosException.INVALID_PARAM, + String.format("Unsupported request type %s", request.getType())); + } + } +} diff --git a/naming/src/test/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManagerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManagerTest.java index 0aa980ba64f..e7c56d9528d 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManagerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/core/v2/index/ClientServiceIndexesManagerTest.java @@ -120,7 +120,7 @@ public void testSubscribeTypes() { List> classes = clientServiceIndexesManager.subscribeTypes(); Assert.assertNotNull(classes); - Assert.assertEquals(classes.size(), 5); + Assert.assertEquals(classes.size(), 7); } @Test diff --git a/naming/src/test/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2ImplTest.java b/naming/src/test/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2ImplTest.java index cb5a7dfb73a..6cc5121fd2a 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2ImplTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/push/v2/NamingSubscriberServiceV2ImplTest.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.naming.push.v2; +import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.naming.core.v2.client.Client; import com.alibaba.nacos.naming.core.v2.client.manager.ClientManagerDelegate; import com.alibaba.nacos.naming.core.v2.event.service.ServiceEvent; @@ -117,7 +118,7 @@ public void testGetFuzzySubscribersByService() { @Test public void onEvent() { - subscriberService.onEvent(new ServiceEvent.ServiceChangedEvent(service)); + subscriberService.onEvent(new ServiceEvent.ServiceChangedEvent(service, Constants.ServiceChangedType.ADD_SERVICE)); verify(delayTaskEngine).addTask(eq(service), any(PushDelayTask.class)); } } diff --git a/naming/src/test/java/com/alibaba/nacos/naming/push/v2/task/FixturePushExecutor.java b/naming/src/test/java/com/alibaba/nacos/naming/push/v2/task/FixturePushExecutor.java index 021dc619518..dbbebaf9b63 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/push/v2/task/FixturePushExecutor.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/push/v2/task/FixturePushExecutor.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.naming.push.v2.task; +import com.alibaba.nacos.api.naming.remote.request.AbstractFuzzyWatchNotifyRequest; +import com.alibaba.nacos.api.remote.PushCallBack; import com.alibaba.nacos.naming.pojo.Subscriber; import com.alibaba.nacos.naming.push.v2.PushDataWrapper; import com.alibaba.nacos.naming.push.v2.executor.PushExecutor; @@ -40,6 +42,21 @@ public void doPushWithCallback(String clientId, Subscriber subscriber, PushDataW } } + @Override + public void doWatcherNotifyPush(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest) { + + } + + @Override + public void doFuzzyWatchNotifyPushWithCallBack(String clientId, AbstractFuzzyWatchNotifyRequest watchNotifyRequest, + PushCallBack callBack) { + if (shouldSuccess) { + callBack.onSuccess(); + } else { + callBack.onFail(failedException); + } + } + public void setShouldSuccess(boolean shouldSuccess) { this.shouldSuccess = shouldSuccess; }