diff --git a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java index 915610b7ba5..68903e6d543 100644 --- a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java +++ b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java @@ -48,6 +48,7 @@ import org.apache.servicecomb.core.provider.producer.ProducerProviderManager; import org.apache.servicecomb.core.transport.TransportManager; import org.apache.servicecomb.foundation.common.VendorExtensions; +import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper; import org.apache.servicecomb.foundation.common.event.EnableExceptionPropagation; import org.apache.servicecomb.foundation.common.event.EventManager; import org.apache.servicecomb.foundation.common.log.LogMarkerLeakFixUtils; @@ -55,6 +56,8 @@ import org.apache.servicecomb.foundation.vertx.VertxUtils; import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser; import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader; @@ -78,6 +81,10 @@ public class SCBEngine { static final long DEFAULT_WAIT_UP_TIMEOUT = 10_000; + static final String CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC = "servicecomb.boot.turnDown.waitInSeconds"; + + static final long DEFAULT_TURN_DOWN_STATUS_WAIT_SEC = 0; + private static final Object initializationLock = new Object(); private volatile static SCBEngine INSTANCE; @@ -103,8 +110,6 @@ public class SCBEngine { private volatile SCBStatus status = SCBStatus.DOWN; - private ServiceRegistry serviceRegistry; - private EventBus eventBus; private ExecutorManager executorManager = new ExecutorManager(); @@ -123,8 +128,7 @@ public class SCBEngine { private Thread shutdownHook; protected SCBEngine() { - serviceRegistry = RegistryUtils.getServiceRegistry(); - eventBus = serviceRegistry.getEventBus(); + eventBus = EventManager.getEventBus(); // see SCB-1266, fix Log4j2 leak marker problem LogMarkerLeakFixUtils.fix(); @@ -142,7 +146,7 @@ public VendorExtensions getVendorExtensions() { } public String getAppId() { - return serviceRegistry.getAppId(); + return RegistryUtils.getAppId(); } public void setStatus(SCBStatus status) { @@ -165,11 +169,11 @@ public static SCBEngine getInstance() { } public ServiceRegistry getServiceRegistry() { - return serviceRegistry; + return RegistryUtils.getServiceRegistry(); } public SwaggerLoader getSwaggerLoader() { - return serviceRegistry.getSwaggerLoader(); + return RegistryUtils.getSwaggerLoader(); } public ConsumerHandlerManager getConsumerHandlerManager() { @@ -318,19 +322,18 @@ public synchronized SCBEngine run() { private void printServiceInfo() { StringBuilder serviceInfo = new StringBuilder(); serviceInfo.append("Service information is shown below:\n"); - for (int i = 0; i < bootUpInformationCollectors.size(); i++) { - serviceInfo.append(bootUpInformationCollectors.get(i).collect()).append('\n'); + for (BootUpInformationCollector bootUpInformationCollector : bootUpInformationCollectors) { + serviceInfo.append(bootUpInformationCollector.collect()).append('\n'); } LOGGER.info(serviceInfo.toString()); } - private void doRun() throws Exception { status = SCBStatus.STARTING; bootListeners.sort(Comparator.comparingInt(BootListener::getOrder)); - AbstractEndpointsCache.init(serviceRegistry.getInstanceCacheManager(), transportManager); + AbstractEndpointsCache.init(RegistryUtils.getInstanceCacheManager(), transportManager); triggerEvent(EventType.BEFORE_HANDLER); HandlerConfigUtils.init(consumerHandlerManager, producerHandlerManager); @@ -354,14 +357,14 @@ private void doRun() throws Exception { triggerAfterRegistryEvent(); - serviceRegistry.run(); + RegistryUtils.run(); shutdownHook = new Thread(this::destroyForShutdownHook); Runtime.getRuntime().addShutdownHook(shutdownHook); } private void createProducerMicroserviceMeta() { - String microserviceName = serviceRegistry.getMicroservice().getServiceName(); + String microserviceName = RegistryUtils.getMicroservice().getServiceName(); List consumerHandlerChain = consumerHandlerManager.getOrCreate(microserviceName); List producerHandlerChain = producerHandlerManager.getOrCreate(microserviceName); @@ -391,6 +394,12 @@ private void doDestroy() { if (shutdownHook != null) { Runtime.getRuntime().removeShutdownHook(shutdownHook); } + + //Step 0: turn down the status of this instance in service center, + // so that the consumers can remove this instance record in advance + turnDownInstanceStatus(); + blockShutDownOperationForConsumerRefresh(); + //Step 1: notify all component stop invoke via BEFORE_CLOSE Event safeTriggerEvent(EventType.BEFORE_CLOSE); @@ -399,7 +408,7 @@ private void doDestroy() { //Step 3: Unregister microservice instance from Service Center and close vertx // Forbidden other consumers find me - serviceRegistry.destroy(); + RegistryUtils.destroy(); VertxUtils.blockCloseVertxByName("registry"); serviceRegistryListener.destroy(); @@ -422,6 +431,30 @@ private void doDestroy() { safeTriggerEvent(EventType.AFTER_CLOSE); } + private void turnDownInstanceStatus() { + RegistryUtils.executeOnEachServiceRegistry(sr -> new SuppressedRunnableWrapper(() -> { + MicroserviceInstance selfInstance = sr.getMicroserviceInstance(); + sr.getServiceRegistryClient().updateMicroserviceInstanceStatus( + selfInstance.getServiceId(), + selfInstance.getInstanceId(), + MicroserviceInstanceStatus.DOWN); + }).run()); + } + + private void blockShutDownOperationForConsumerRefresh() { + try { + long turnDownWaitSeconds = DynamicPropertyFactory.getInstance() + .getLongProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC) + .get(); + if (turnDownWaitSeconds <= 0) { + return; + } + Thread.sleep(TimeUnit.SECONDS.toMillis(turnDownWaitSeconds)); + } catch (InterruptedException e) { + LOGGER.warn("failed to block the shutdown procedure", e); + } + } + private void validAllInvocationFinished() throws InterruptedException { long start = System.currentTimeMillis(); while (true) { @@ -464,7 +497,7 @@ public MicroserviceReferenceConfig createMicroserviceReferenceConfig(String micr * @return */ public MicroserviceReferenceConfig createMicroserviceReferenceConfig(String microserviceName, String versionRule) { - MicroserviceVersions microserviceVersions = serviceRegistry.getAppManager() + MicroserviceVersions microserviceVersions = RegistryUtils.getAppManager() .getOrCreateMicroserviceVersions(parseAppId(microserviceName), microserviceName); ConsumerMicroserviceVersionsMeta microserviceVersionsMeta = CoreMetaUtils .getMicroserviceVersionsMeta(microserviceVersions); diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java b/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java index 7f5b5497360..75e7492ffa3 100644 --- a/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java +++ b/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java @@ -22,7 +22,6 @@ import javax.ws.rs.core.Response.Status; -import org.apache.servicecomb.core.Const; import org.apache.servicecomb.core.Handler; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.exception.ExceptionUtils; diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java index d6f5740ae61..feaf882c235 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java @@ -100,7 +100,7 @@ public ReferenceConfig createReferenceConfig(String transport, OperationMeta ope } private void mark3rdPartyService(OperationMeta operationMeta, ReferenceConfig referenceConfig) { - final MicroserviceVersions microserviceVersions = RegistryUtils.getServiceRegistry().getAppManager() + final MicroserviceVersions microserviceVersions = RegistryUtils.getAppManager() .getOrCreateMicroserviceVersions( operationMeta.getMicroserviceMeta().getAppId(), operationMeta.getMicroserviceName()); diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java index aec2e339189..4b859091547 100644 --- a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java +++ b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java @@ -28,6 +28,7 @@ import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.core.definition.SchemaMeta; import org.apache.servicecomb.foundation.common.utils.IOUtils; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.Const; import org.apache.servicecomb.serviceregistry.api.registry.BasePath; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; @@ -65,10 +66,14 @@ public void onAfterTransport(BootEvent event) { microserviceMeta.getMicroserviceName(), schemaMeta.getSchemaId(), content); - microservice.addSchema(schemaMeta.getSchemaId(), content); + RegistryUtils.executeOnEachServiceRegistry(sr -> { + sr.getMicroservice().addSchema(schemaMeta.getSchemaId(), content); + }); } - saveBasePaths(microserviceMeta, microservice); + RegistryUtils.executeOnEachServiceRegistry(sr -> { + saveBasePaths(microserviceMeta, sr.getMicroservice()); + }); } // just compatible to old 3rd components, servicecomb not use it...... diff --git a/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java b/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java index 2e02279c6a9..a52c93bf766 100644 --- a/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java +++ b/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java @@ -29,6 +29,7 @@ import org.apache.servicecomb.core.Transport; import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,8 +61,10 @@ public void init(SCBEngine scbEngine) throws Exception { Endpoint endpoint = transport.getPublishEndpoint(); if (endpoint != null && endpoint.getEndpoint() != null) { LOGGER.info("endpoint to publish: {}", endpoint.getEndpoint()); - Microservice microservice = scbEngine.getServiceRegistry().getMicroservice(); - microservice.getInstance().getEndpoints().add(endpoint.getEndpoint()); + RegistryUtils.executeOnEachServiceRegistry(sr -> { + Microservice microservice = sr.getMicroservice(); + microservice.getInstance().getEndpoints().add(endpoint.getEndpoint()); + }); } continue; } diff --git a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java b/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java index fc4545a5092..3f6c708b583 100644 --- a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java +++ b/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java @@ -27,6 +27,7 @@ import org.apache.servicecomb.core.bootstrap.SCBBootstrap; import org.apache.servicecomb.foundation.common.cache.VersionedCache; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; import org.apache.servicecomb.swagger.invocation.AsyncResponse; @@ -67,9 +68,9 @@ public void setUp() throws Exception { } }; - new Expectations(scbEngine.getServiceRegistry().getInstanceCacheManager()) { + new Expectations(RegistryUtils.getInstanceCacheManager()) { { - scbEngine.getServiceRegistry().getInstanceCacheManager() + RegistryUtils.getInstanceCacheManager() .getOrCreateVersionedCache(anyString, anyString, anyString); result = instanceVersionedCache; } diff --git a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java index 7117f076157..7d5d567b41c 100644 --- a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java +++ b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java @@ -264,7 +264,7 @@ protected void invoke(String appendUrl, int x, int y, List r private URIEndpointObject prepareEdge(String prefix) { Microservice microservice = RegistryUtils.getMicroservice(); - MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils.getServiceRegistry() + MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils .getAppManager() .getOrCreateMicroserviceVersionRule(microservice.getAppId(), "edge", DefinitionConst.VERSION_RULE_ALL) .getVersionedCache() diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java index a58cbc59fa2..3a7ec706afc 100644 --- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java +++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java @@ -78,7 +78,7 @@ public void testHighwayTransport() throws Exception { private static void prepareServerDirectURL() { Microservice microservice = RegistryUtils.getMicroservice(); - MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils.getServiceRegistry() + MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils .getAppManager() .getOrCreateMicroserviceVersionRule(microservice.getAppId(), "jaxrs", DefinitionConst.VERSION_RULE_ALL) .getVersionedCache() diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java index 2ff69984be2..e209f44e4b5 100644 --- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java +++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java @@ -106,8 +106,8 @@ public void dispatchEvent(Object event) { try { dispatcher.accept(event); } catch (Throwable e) { - LOGGER.error("event process should not throw error. ", e); if (enableExceptionPropagation) { + LOGGER.error("event process should not throw error. ", e); throw e; } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java index e34057714fd..36ee88a68b2 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java @@ -119,7 +119,7 @@ public void testZoneAwareAndIsolationFilterWorks() throws Exception { Invocation invocation = new Invocation(referenceConfig, operationMeta, new HashMap<>()); InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); + ServiceRegistry serviceRegistry = mockUpServiceRegistry(); TransportManager transportManager = Mockito.mock(TransportManager.class); Transport transport = Mockito.mock(Transport.class); ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); @@ -172,7 +172,7 @@ public void testZoneAwareAndIsolationFilterWorks() throws Exception { RegistryUtils.setServiceRegistry(serviceRegistry); when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); + mockUpInstanceCacheManager(instanceCacheManager); when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) .thenReturn(parent); when(transportManager.findTransport("rest")).thenReturn(transport); @@ -268,7 +268,7 @@ public void testIsolationEventWithEndpoint() throws Exception { Invocation invocation = new Invocation(referenceConfig, operationMeta, new HashMap<>()); InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); + ServiceRegistry serviceRegistry = mockUpServiceRegistry(); TransportManager transportManager = Mockito.mock(TransportManager.class); Transport transport = Mockito.mock(Transport.class); ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); @@ -299,7 +299,7 @@ public void testIsolationEventWithEndpoint() throws Exception { RegistryUtils.setServiceRegistry(serviceRegistry); when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); + mockUpInstanceCacheManager(instanceCacheManager); when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) .thenReturn(parent); when(transportManager.findTransport("rest")).thenReturn(transport); @@ -357,7 +357,7 @@ public void testZoneAwareAndIsolationFilterWorksEmptyInstanceProtectionEnabled() Invocation invocation = new Invocation(referenceConfig, operationMeta, new HashMap<>()); InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); + ServiceRegistry serviceRegistry = mockUpServiceRegistry(); TransportManager transportManager = Mockito.mock(TransportManager.class); Transport transport = Mockito.mock(Transport.class); ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); @@ -410,7 +410,7 @@ public void testZoneAwareAndIsolationFilterWorksEmptyInstanceProtectionEnabled() RegistryUtils.setServiceRegistry(serviceRegistry); when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); + mockUpInstanceCacheManager(instanceCacheManager); when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) .thenReturn(parent); when(transportManager.findTransport("rest")).thenReturn(transport); @@ -484,7 +484,7 @@ public void testZoneAwareAndIsolationFilterUsingMockedInvocationWorks() throws E }); InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); + ServiceRegistry serviceRegistry = mockUpServiceRegistry(); TransportManager transportManager = Mockito.mock(TransportManager.class); Transport transport = Mockito.mock(Transport.class); ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); @@ -537,7 +537,7 @@ public void testZoneAwareAndIsolationFilterUsingMockedInvocationWorks() throws E RegistryUtils.setServiceRegistry(serviceRegistry); when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); + mockUpInstanceCacheManager(instanceCacheManager); when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) .thenReturn(parent); when(transportManager.findTransport("rest")).thenReturn(transport); @@ -627,7 +627,7 @@ public void testStatusFilterUsingMockedInvocationWorks() throws Exception { }); InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); + ServiceRegistry serviceRegistry = mockUpServiceRegistry(); TransportManager transportManager = Mockito.mock(TransportManager.class); Transport transport = Mockito.mock(Transport.class); ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); @@ -681,7 +681,7 @@ public void testStatusFilterUsingMockedInvocationWorks() throws Exception { RegistryUtils.setServiceRegistry(serviceRegistry); when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); + mockUpInstanceCacheManager(instanceCacheManager); when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) .thenReturn(parent); when(transportManager.findTransport("rest")).thenReturn(transport); @@ -778,7 +778,7 @@ public void testConfigEndpoint() { AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class); InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class); - ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); + ServiceRegistry serviceRegistry = mockUpServiceRegistry(); TransportManager transportManager = Mockito.mock(TransportManager.class); Transport transport = Mockito.mock(Transport.class); ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false"); @@ -800,7 +800,7 @@ public void testConfigEndpoint() { RegistryUtils.setServiceRegistry(serviceRegistry); when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself); - when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager); + mockUpInstanceCacheManager(instanceCacheManager); when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+")) .thenReturn(parent); when(transportManager.findTransport("rest")).thenReturn(transport); @@ -983,4 +983,19 @@ private DiscoveryTree createMockedDiscoveryTree(List servers) private void mockDelayMillis(long delay) { mockTimeMillis.value += delay; } + + private void mockUpInstanceCacheManager(InstanceCacheManager instanceCacheManager) { + new MockUp() { + @Mock + InstanceCacheManager getInstanceCacheManager() { + return instanceCacheManager; + } + }; + } + + private ServiceRegistry mockUpServiceRegistry() { + ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class); + when(serviceRegistry.getEventBus()).thenReturn(EventManager.getEventBus()); + return serviceRegistry; + } } diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java index 6f3282e9b10..94f484d44a5 100644 --- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java +++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java @@ -35,6 +35,7 @@ import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.ServiceRegistry; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; @@ -99,7 +100,7 @@ public class TestLoadbalanceHandler { public static void classSetup() { scbEngine = new SCBBootstrap().useLocalRegistry().createSCBEngineForTest().run(); serviceRegistry = scbEngine.getServiceRegistry(); - instanceCacheManager = serviceRegistry.getInstanceCacheManager(); + instanceCacheManager = RegistryUtils.getInstanceCacheManager(); transportManager = scbEngine.getTransportManager(); } diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java index 89efccaf0c3..f57e8351d10 100644 --- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java +++ b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java @@ -77,7 +77,7 @@ public static Map waitMicroserviceReady(String app Map instances; for (; ; ) { - MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry() + MicroserviceVersionRule microserviceVersionRule = RegistryUtils .getAppManager() .getOrCreateMicroserviceVersionRule(appId, microserviceName, strVersionRule); instances = microserviceVersionRule.getInstances(); @@ -92,7 +92,7 @@ public static Map waitMicroserviceReady(String app minInstanceCount, instances.size()); // pull at once - RegistryUtils.getServiceRegistry().getAppManager().pullInstances(); + RegistryUtils.getAppManager().pullInstances(); forceWait(TimeUnit.SECONDS, 1); } diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java index e24cfcbecc9..4988caf2876 100644 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java @@ -55,7 +55,7 @@ protected String[] addArgs(String[] cmds) { } public void ensureReady() throws Throwable { - MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager() + MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getAppManager() .getOrCreateMicroserviceVersionRule(microserviceDeployDefinition.getAppId(), microserviceDeployDefinition.getMicroserviceName(), microserviceDeployDefinition.getVersion()); diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java index 5fde52b2066..c9ea374da69 100644 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java @@ -70,7 +70,7 @@ public String getUrlPrefix() { } private String getUrlPrefix(String gateName, String producerName, String schemaId) { - MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager() + MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getAppManager() .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), gateName, DefinitionConst.VERSION_RULE_ALL); MicroserviceInstance microserviceInstance = microserviceVersionRule.getInstances().values().stream().findFirst() diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java index 51aa2e574cc..21f55a82999 100644 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java @@ -51,7 +51,7 @@ public ITSCBAsyncRestTemplate init() { ensureProviderBasePath(producerName); urlPrefix = String.format("cse://%s%s", producerName, basePath); - instance = RegistryUtils.getServiceRegistry().getAppManager() + instance = RegistryUtils.getAppManager() .getOrCreateMicroserviceManager(RegistryUtils.getAppId()) .getOrCreateMicroserviceVersions(producerName).getPulledInstances().get(0); @@ -78,7 +78,7 @@ public String getAddress(String transport) { private void ensureProviderBasePath(String producerName) { MicroserviceManager microserviceManager = - RegistryUtils.getServiceRegistry().getAppManager().getOrCreateMicroserviceManager(RegistryUtils.getAppId()); + RegistryUtils.getAppManager().getOrCreateMicroserviceManager(RegistryUtils.getAppId()); MicroserviceVersions producerMicroserviceVersions = microserviceManager.getOrCreateMicroserviceVersions(producerName); Optional latestMicroserviceVersion = diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java index f83291b9e2d..f37d139d217 100644 --- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java +++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java @@ -48,7 +48,7 @@ public ITSCBRestTemplate init() { SchemaMeta schemaMeta = microserviceMeta.ensureFindSchemaMeta(schemaId); basePath = schemaMeta.getSwagger().getBasePath(); urlPrefix = String.format("cse://%s%s", producerName, basePath); - instance = RegistryUtils.getServiceRegistry().getAppManager() + instance = RegistryUtils.getAppManager() .getOrCreateMicroserviceManager(RegistryUtils.getAppId()) .getOrCreateMicroserviceVersions(producerName).getPulledInstances().get(0); diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java index e1e1343f398..b047ffa534f 100644 --- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java +++ b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java @@ -36,7 +36,7 @@ public int getOrder() { @Override public void onBootEvent(BootEvent bootEvent) { if (bootEvent.getEventType() == EventType.BEFORE_REGISTRY) { - MicroserviceVersionRule rule = RegistryUtils.getServiceRegistry().getAppManager() + MicroserviceVersionRule rule = RegistryUtils.getAppManager() .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), "it-producer", "0+"); if (rule.getInstances().size() == 0) { LOGGER.warn("Prefetch not successful, maybe the provider not started."); diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java index c80566f3d32..ed6a0a412a0 100644 --- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java +++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java @@ -25,6 +25,8 @@ import org.apache.servicecomb.core.bootstrap.SCBBootstrap; import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse; +import org.apache.servicecomb.serviceregistry.RegistryUtils; +import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.swagger.invocation.Response; import org.junit.AfterClass; import org.junit.Assert; @@ -38,11 +40,14 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import mockit.Deencapsulation; + public class CseAsyncClientHttpRequestTest { static SCBEngine scbEngine; @BeforeClass public static void classSetup() { + Deencapsulation.setField(RegistryUtils.class, "appManager", new AppManager()); scbEngine = new SCBBootstrap().useLocalRegistry().createSCBEngineForTest() .addProducerMeta("sid1", new CseAsyncClientHttpRequestTestSchema()).run(); } @@ -81,7 +86,7 @@ protected CompletableFuture doAsyncInvoke(Invocation invocat byte[] body = "abc".getBytes(); client.setRequestBody(body); client.executeAsync(); - Assert.assertArrayEquals(body, ( byte[])holder.value.getInvocationArguments().get("input")); + Assert.assertArrayEquals(body, (byte[]) holder.value.getInvocationArguments().get("input")); } @Test diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java index cdfad6bc8ea..3f99eae9c70 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java @@ -20,62 +20,120 @@ import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Matcher; import org.apache.http.client.utils.URIBuilder; import org.apache.servicecomb.config.ConfigUtil; import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; +import org.apache.servicecomb.foundation.common.Holder; import org.apache.servicecomb.foundation.common.event.EventManager; import org.apache.servicecomb.foundation.common.net.IpPort; import org.apache.servicecomb.foundation.common.net.NetUtils; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; +import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew; import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; +import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; +import org.apache.servicecomb.serviceregistry.registry.cache.AggregateServiceRegistryCache; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey; +import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader; +import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceRegisterTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; import com.google.common.base.Charsets; +import com.google.common.eventbus.Subscribe; import com.google.common.hash.Hashing; import com.netflix.config.DynamicPropertyFactory; public final class RegistryUtils { private static final Logger LOGGER = LoggerFactory.getLogger(RegistryUtils.class); - private static ServiceRegistry serviceRegistry; + /** + * The default ServiceRegistry instance + */ + private static volatile ServiceRegistry serviceRegistry; // value is ip or {interface name} public static final String PUBLISH_ADDRESS = "servicecomb.service.publishAddress"; private static final String PUBLISH_PORT = "servicecomb.{transport_name}.publishPort"; + private static SwaggerLoader swaggerLoader = new SwaggerLoader(); + + private static AppManager appManager = new AppManager(); + + private static InstanceCacheManager instanceCacheManager = new InstanceCacheManagerNew(appManager); + + private static final Map EXTRA_SERVICE_REGISTRY_CONFIGS = new LinkedHashMap<>(); + + private static final Map EXTRA_SERVICE_REGISTRIES = new LinkedHashMap<>(); + + static AggregateServiceRegistryCache aggregateServiceRegistryCache; + private RegistryUtils() { } - public static void init() { + public static synchronized void init() { if (serviceRegistry != null) { return; } MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader(); MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels()); + initializeServiceRegistries(microserviceDefinition); + + initAggregateServiceRegistryCache(); + } + + private static void initAggregateServiceRegistryCache() { + ArrayList serviceRegistries = new ArrayList<>(); + executeOnEachServiceRegistry(serviceRegistries::add); + aggregateServiceRegistryCache = new AggregateServiceRegistryCache(serviceRegistries); + aggregateServiceRegistryCache.setCacheRefreshedWatcher(refreshedCaches -> { + appManager.pullInstances(); + }); + + executeOnEachServiceRegistry( + serviceRegistry -> serviceRegistry + .getEventBus() + .register(aggregateServiceRegistryCache)); + } + + private static void initializeServiceRegistries(MicroserviceDefinition microserviceDefinition) { serviceRegistry = - ServiceRegistryFactory - .getOrCreate(EventManager.eventBus, ServiceRegistryConfig.INSTANCE, microserviceDefinition); - serviceRegistry.init(); + ServiceRegistryFactory.create(ServiceRegistryConfig.INSTANCE, microserviceDefinition); + EXTRA_SERVICE_REGISTRY_CONFIGS.forEach((k, v) -> { + ServiceRegistry serviceRegistry = ServiceRegistryFactory.create(v, microserviceDefinition); + addExtraServiceRegistry(serviceRegistry); + }); + executeOnEachServiceRegistry(ServiceRegistry::init); + executeOnEachServiceRegistry(AfterServiceInstanceRegistryHandler::new); } public static void run() { - serviceRegistry.run(); + executeOnEachServiceRegistry(ServiceRegistry::run); } public static void destroy() { - serviceRegistry.destroy(); + executeOnEachServiceRegistry(ServiceRegistry::destroy); } /** @@ -92,14 +150,24 @@ public static ServiceRegistry getServiceRegistry() { public static void setServiceRegistry(ServiceRegistry serviceRegistry) { RegistryUtils.serviceRegistry = serviceRegistry; + initAggregateServiceRegistryCache(); } + @Deprecated public static ServiceRegistryClient getServiceRegistryClient() { return serviceRegistry.getServiceRegistryClient(); } public static InstanceCacheManager getInstanceCacheManager() { - return serviceRegistry.getInstanceCacheManager(); + return instanceCacheManager; + } + + public static SwaggerLoader getSwaggerLoader() { + return swaggerLoader; + } + + public static AppManager getAppManager() { + return appManager; } public static String getAppId() { @@ -214,24 +282,163 @@ private static IpPort genPublishIpPort(String schema, IpPort ipPort) { public static List findServiceInstance(String appId, String serviceName, String versionRule) { - return serviceRegistry.findServiceInstance(appId, serviceName, versionRule); + MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache( + MicroserviceCacheKey.builder() + .appId(appId).serviceName(serviceName).env(getMicroservice().getEnvironment()) + .build() + ); + return MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(serviceCache.getStatus()) ? + null : serviceCache.getInstances(); } // update microservice instance properties public static boolean updateInstanceProperties(Map instanceProperties) { - return serviceRegistry.updateInstanceProperties(instanceProperties); + Holder resultHolder = new Holder<>(true); + executeOnEachServiceRegistry(sr -> { + boolean updateResult = sr.updateInstanceProperties(instanceProperties); + resultHolder.value = updateResult && resultHolder.value; + }); + return resultHolder.value; } public static Microservice getMicroservice(String microserviceId) { - return serviceRegistry.getRemoteMicroservice(microserviceId); + return getResultFromFirstValidServiceRegistry(sr -> sr.getRemoteMicroservice(microserviceId)); } public static MicroserviceInstances findServiceInstances(String appId, String serviceName, String versionRule, String revision) { - return serviceRegistry.findServiceInstances(appId, serviceName, versionRule, revision); + MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache( + MicroserviceCacheKey.builder().appId(appId).serviceName(serviceName).env(getMicroservice().getEnvironment()) + .build()); + return convertCacheToMicroserviceInstances(serviceCache); + } + + /** + * for compatibility + */ + public static MicroserviceInstances convertCacheToMicroserviceInstances(MicroserviceCache microserviceCache) { + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + switch (microserviceCache.getStatus()) { + case SERVICE_NOT_FOUND: + microserviceInstances.setMicroserviceNotExist(true); + microserviceInstances.setNeedRefresh(false); + microserviceInstances.setRevision(""); + microserviceInstances.setInstancesResponse(null); + return microserviceInstances; + case NO_CHANGE: + microserviceInstances.setMicroserviceNotExist(false); + microserviceInstances.setNeedRefresh(false); + microserviceInstances.setRevision(microserviceCache.getRevisionId()); + return microserviceInstances; + case REFRESHED: + microserviceInstances.setMicroserviceNotExist(false); + microserviceInstances.setNeedRefresh(true); + microserviceInstances.setRevision(microserviceCache.getRevisionId()); + FindInstancesResponse findInstancesResponse = new FindInstancesResponse(); + findInstancesResponse.setInstances(new ArrayList<>(microserviceCache.getInstances())); + microserviceInstances.setInstancesResponse(findInstancesResponse); + return microserviceInstances; + default: + return null; + } } public static String calcSchemaSummary(String schemaContent) { return Hashing.sha256().newHasher().putString(schemaContent, Charsets.UTF_8).hash().toString(); } + + public static String getAggregatedSchema(String microserviceId, String schemaId) { + return getResultFromFirstValidServiceRegistry( + sr -> sr.getServiceRegistryClient().getAggregatedSchema(microserviceId, schemaId)); + } + + public static Microservice getAggregatedRemoteMicroservice(String microserviceId) { + return getResultFromFirstValidServiceRegistry( + sr -> sr.getAggregatedRemoteMicroservice(microserviceId)); + } + + public static T getResultFromFirstValidServiceRegistry(Function action) { + Holder resultHolder = new Holder<>(); + executeOnEachServiceRegistry(sr -> { + if (null == resultHolder.value) { + resultHolder.value = action.apply(sr); + } + }); + return resultHolder.value; + } + + public static void executeOnEachServiceRegistry(Consumer action) { + if (null != getServiceRegistry()) { + action.accept(getServiceRegistry()); + } + if (!EXTRA_SERVICE_REGISTRIES.isEmpty()) { + EXTRA_SERVICE_REGISTRIES.forEach((k, v) -> action.accept(v)); + } + } + + public static void addExtraServiceRegistry(ServiceRegistry serviceRegistry) { + Objects.requireNonNull(serviceRegistry); + LOGGER.info("extra ServiceRegistry added: [{}], [{}]", serviceRegistry.getName(), serviceRegistry.getClass()); + EXTRA_SERVICE_REGISTRIES.put(serviceRegistry.getName(), serviceRegistry); + } + + /** + * Add the configuration object of {@link ServiceRegistry}. + * The corresponding {@link ServiceRegistry} instances are instantiated later in {@link #init()} + */ + public static void addExtraServiceRegistryConfig(ServiceRegistryConfig serviceRegistryConfig) { + validateRegistryConfig(serviceRegistryConfig); + EXTRA_SERVICE_REGISTRY_CONFIGS.put(serviceRegistryConfig.getRegistryName(), serviceRegistryConfig); + } + + /** + * @throws NullPointerException serviceRegistryConfig is null + * @throws IllegalArgumentException config value is illegal + */ + public static void validateRegistryConfig(ServiceRegistryConfig serviceRegistryConfig) { + Objects.requireNonNull(serviceRegistryConfig); + validateRegistryName(serviceRegistryConfig.getRegistryName()); + } + + /** + * To validate whether the name is legal value. + * @param name name of the {@link ServiceRegistry} + * @throws IllegalArgumentException the input value is illegal + */ + public static void validateRegistryName(String name) { + Objects.requireNonNull(name, "null value is not allowed for the name of ServiceRegistry"); + Matcher checkMatcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher(name); + boolean isNameValid = checkMatcher.matches(); + if (!isNameValid) { + throw new IllegalArgumentException( + "Illegal registry name, the format should be " + ServiceRegistry.REGISTRY_NAME_FORMAT); + } + } + + public static class AfterServiceInstanceRegistryHandler { + private static AtomicInteger instanceRegisterCounter = new AtomicInteger(EXTRA_SERVICE_REGISTRIES.size() + 1); + + private ServiceRegistry serviceRegistry; + + AfterServiceInstanceRegistryHandler(ServiceRegistry serviceRegistry) { + this.serviceRegistry = serviceRegistry; + serviceRegistry.getEventBus().register(this); + } + + @Subscribe + public void afterRegistryInstance(MicroserviceInstanceRegisterTask microserviceInstanceRegisterTask) { + LOGGER.info("receive MicroserviceInstanceRegisterTask event of [{}]", serviceRegistry.getName()); + if (StringUtils.isEmpty(serviceRegistry.getMicroserviceInstance().getInstanceId())) { + return; + } + + LOGGER.info("ServiceRegistry[{}] has completed instance registry", serviceRegistry.getName()); + EventManager.unregister(this); + + if (instanceRegisterCounter.decrementAndGet() > 0) { + return; + } + EventManager.getEventBus().post(microserviceInstanceRegisterTask); + } + } } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java index 9e1b144f678..2de3e83a871 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java @@ -19,18 +19,28 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; -import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey; import com.google.common.eventbus.EventBus; public interface ServiceRegistry { + String DEFAULT_REGISTRY_NAME = "Default"; + String REGISTRY_NAME_FORMAT = "[a-zA-Z]([-_]?[a-zA-Z0-9])+"; + Pattern REGISTRY_NAME_PATTERN = Pattern.compile(REGISTRY_NAME_FORMAT); + + /** + * Get a name representing this ServiceRegistry instance. + * The name should be unique. + */ + String getName(); + void init(); void run(); @@ -39,34 +49,37 @@ public interface ServiceRegistry { EventBus getEventBus(); - SwaggerLoader getSwaggerLoader(); - Set getCombinedMicroserviceNames(); + /** + * Get the AppId of this microservice instance itself. + */ String getAppId(); + /** + * Get the {@link Microservice} of this microservice instance itself. + */ Microservice getMicroservice(); + /** + * Get the {@link MicroserviceInstance} of this microservice instance itself. + */ MicroserviceInstance getMicroserviceInstance(); ServiceRegistryClient getServiceRegistryClient(); - AppManager getAppManager(); - - InstanceCacheManager getInstanceCacheManager(); - List findServiceInstance(String appId, String microserviceName, String microserviceVersionRule); MicroserviceInstances findServiceInstances(String appId, String microserviceName, String microserviceVersionRule, String revision); + MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey); + boolean updateMicroserviceProperties(Map properties); /** * full update, not increase update - * @param instanceProperties - * @return */ boolean updateInstanceProperties(Map instanceProperties); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java index 16a03819ace..80c8fb53127 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java @@ -52,7 +52,7 @@ public class MicroserviceInstanceCache { public static Microservice getOrCreate(String serviceId) { try { return microservices.get(serviceId, () -> { - Microservice microservice = RegistryUtils.getServiceRegistryClient().getAggregatedMicroservice(serviceId); + Microservice microservice = RegistryUtils.getAggregatedRemoteMicroservice(serviceId); if (microservice == null) { throw new IllegalArgumentException("service id not exists."); } @@ -70,9 +70,9 @@ public static MicroserviceInstance getOrCreate(String serviceId, String instance return instances.get(key, new Callable() { @Override - public MicroserviceInstance call() throws Exception { - MicroserviceInstance instance = RegistryUtils.getServiceRegistryClient() - .findServiceInstance(serviceId, instanceId); + public MicroserviceInstance call() { + MicroserviceInstance instance = RegistryUtils.getResultFromFirstValidServiceRegistry( + sr -> sr.getServiceRegistryClient().findServiceInstance(serviceId, instanceId)); if (instance == null) { throw new IllegalArgumentException("instance id not exists."); } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java index 18115c1d472..947a38631af 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java @@ -30,7 +30,9 @@ import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint; import org.apache.servicecomb.serviceregistry.cache.InstanceCache; import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; +import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew; import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; +import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,7 +42,7 @@ public class IpPortManager { private ServiceRegistryConfig serviceRegistryConfig; - private InstanceCacheManager instanceCacheManager; + InstanceCacheManager instanceCacheManager; private String defaultTransport = "rest"; @@ -60,9 +62,9 @@ public int getMaxRetryTimes() { return maxRetryTimes; } - public IpPortManager(ServiceRegistryConfig serviceRegistryConfig, InstanceCacheManager instanceCacheManager) { + public IpPortManager(ServiceRegistryConfig serviceRegistryConfig) { this.serviceRegistryConfig = serviceRegistryConfig; - this.instanceCacheManager = instanceCacheManager; + this.instanceCacheManager = new InstanceCacheManagerNew(new AppManager()); defaultTransport = serviceRegistryConfig.getTransport(); defaultIpPort = serviceRegistryConfig.getIpPort(); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java index 4b1b6a6e11b..cf8963f35a4 100755 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java @@ -434,30 +434,26 @@ public ServiceCenterInfo getServiceCenterInfo() { } @Override - public boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId, String status) { + public boolean updateMicroserviceInstanceStatus(String microserviceId, String instanceId, + MicroserviceInstanceStatus status) { + if (null == status) { + throw new IllegalArgumentException("null status is now allowed"); + } + Map instanceMap = microserviceInstanceMap.get(microserviceId); if (instanceMap == null) { throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId); } - MicroserviceInstance microserviceInstance = instanceMap.get(microserviceInstanceId); + MicroserviceInstance microserviceInstance = instanceMap.get(instanceId); if (microserviceInstance == null) { throw new IllegalArgumentException( - String.format("Invalid argument. microserviceId=%s, microserviceInstanceId=%s.", - microserviceId, - microserviceInstanceId)); - } - MicroserviceInstanceStatus instanceStatus; - try { - instanceStatus = MicroserviceInstanceStatus.valueOf(status); - } - catch (IllegalArgumentException e){ - throw new IllegalArgumentException("Invalid status."); - } - if (null != instanceStatus) { - microserviceInstance.setStatus(instanceStatus); - return true; + String.format("Invalid argument. microserviceId=%s, instanceId=%s.", + microserviceId, + instanceId)); } - return false; + + microserviceInstance.setStatus(status); + return true; } } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java index 81f61bf4573..b093c0c7cf7 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java @@ -179,6 +179,27 @@ MicroserviceInstances findServiceInstances(String consumerId, String appId, Stri * @param microserviceId * @param microserviceInstanceId * @return + * @deprecated use {@link #updateMicroserviceInstanceStatus(String, String, MicroserviceInstanceStatus)} instead */ - boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId, String status); + @Deprecated + default boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId, + String status) { + MicroserviceInstanceStatus instanceStatus; + try { + instanceStatus = MicroserviceInstanceStatus.valueOf(status); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Invalid status: " + status); + } + + return updateMicroserviceInstanceStatus(microserviceId, microserviceInstanceId, instanceStatus); + } + + /** + * Update the instance status registered in service center. + * @param microserviceId the microserviceId of the instance + * @param instanceId the instanceId of the instance + * @param status update to this status + * @return whether this operation success + */ + boolean updateMicroserviceInstanceStatus(String microserviceId, String instanceId, MicroserviceInstanceStatus status); } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java index 5992c056cb3..c7096929d86 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java @@ -17,9 +17,6 @@ package org.apache.servicecomb.serviceregistry.client.http; -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicPropertyFactory; - import org.apache.servicecomb.foundation.vertx.AddressResolverConfig; import org.apache.servicecomb.foundation.vertx.VertxUtils; import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager; @@ -30,6 +27,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.netflix.config.DynamicIntProperty; +import com.netflix.config.DynamicPropertyFactory; + import io.vertx.core.DeploymentOptions; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; @@ -38,38 +38,48 @@ /** * Created by on 2017/4/28. */ -public abstract class AbstractClientPool implements ClientPool { +abstract class AbstractClientPool implements ClientPool { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientPool.class); - private ClientPoolManager clientMgr; + private ServiceRegistryConfig serviceRegistryConfig; + + private HttpClientOptions httpClientOptions; - public AbstractClientPool() { + private ClientPoolManager clientMgr; + + AbstractClientPool(ServiceRegistryConfig serviceRegistryConfig) { + this.serviceRegistryConfig = serviceRegistryConfig; + this.httpClientOptions = getHttpClientOptionsFromConfigurations(serviceRegistryConfig); create(); } protected abstract boolean isWorker(); + protected abstract HttpClientOptions getHttpClientOptionsFromConfigurations( + ServiceRegistryConfig serviceRegistryConfig); + public HttpClientWithContext getClient() { return this.clientMgr.findThreadBindClientPool(); } public void create() { - DynamicIntProperty property = DynamicPropertyFactory.getInstance().getIntProperty(ServiceRegistryConfig.EVENT_LOOP_POOL_SIZE, 4); - DynamicIntProperty workerPoolSize = DynamicPropertyFactory.getInstance().getIntProperty(ServiceRegistryConfig.WORKER_POOL_SIZE, 4); + DynamicIntProperty property = DynamicPropertyFactory.getInstance() + .getIntProperty(ServiceRegistryConfig.EVENT_LOOP_POOL_SIZE, 4); + DynamicIntProperty workerPoolSize = DynamicPropertyFactory.getInstance() + .getIntProperty(ServiceRegistryConfig.WORKER_POOL_SIZE, 4); // 这里面是同步接口,且好像直接在事件线程中用,保险起见,先使用独立的vertx实例 VertxOptions vertxOptions = new VertxOptions() - .setAddressResolverOptions(AddressResolverConfig.getAddressResover(ServiceRegistryConfig.SSL_KEY)) - .setEventLoopPoolSize(property.get()); + .setAddressResolverOptions(AddressResolverConfig.getAddressResover(serviceRegistryConfig.getSslConfigTag())) + .setEventLoopPoolSize(property.get()); Vertx vertx = VertxUtils.getOrCreateVertxByName("registry", vertxOptions); - HttpClientOptions httpClientOptions = createHttpClientOptions(); clientMgr = new ClientPoolManager<>(vertx, new HttpClientPoolFactory(httpClientOptions)); DeploymentOptions deployOptions = VertxUtils.createClientDeployOptions(this.clientMgr, - ServiceRegistryConfig.INSTANCE.getInstances()) - .setWorker(isWorker()) - .setWorkerPoolName(ServiceRegistryConfig.WORKER_POOL_NAME) - .setWorkerPoolSize(workerPoolSize.get()); + ServiceRegistryConfig.INSTANCE.getInstances()) + .setWorker(isWorker()) + .setWorkerPoolName(ServiceRegistryConfig.WORKER_POOL_NAME) + .setWorkerPoolSize(workerPoolSize.get()); try { VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions); } catch (InterruptedException e) { diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java index e5db5597bef..3784d985a75 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java @@ -19,15 +19,11 @@ import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; -import io.vertx.core.http.HttpClientOptions; - /** * Created by on 2017/4/28. */ -public interface ClientPool { +interface ClientPool { void create(); - HttpClientOptions createHttpClientOptions(); - HttpClientWithContext getClient(); } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java index a3136693c4b..962a81ce322 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java @@ -27,16 +27,21 @@ import io.vertx.core.http.HttpVersion; import io.vertx.core.net.ProxyOptions; -/** - * Created by on 2017/4/28. - */ -public final class HttpClientPool extends AbstractClientPool { +class HttpClientPool extends AbstractClientPool { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientPool.class); + /** + * The default instance, for default sc cluster. + */ public static final HttpClientPool INSTANCE = new HttpClientPool(); private HttpClientPool() { + super(ServiceRegistryConfig.INSTANCE); + } + + HttpClientPool(ServiceRegistryConfig serviceRegistryConfig) { + super(serviceRegistryConfig); } @Override @@ -45,27 +50,28 @@ protected boolean isWorker() { } @Override - public HttpClientOptions createHttpClientOptions() { - HttpVersion ver = ServiceRegistryConfig.INSTANCE.getHttpVersion(); + protected HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) { + HttpVersion ver = serviceRegistryConfig.getHttpVersion(); HttpClientOptions httpClientOptions = new HttpClientOptions(); httpClientOptions.setProtocolVersion(ver); - httpClientOptions.setConnectTimeout(ServiceRegistryConfig.INSTANCE.getConnectionTimeout()); - httpClientOptions.setIdleTimeout(ServiceRegistryConfig.INSTANCE.getIdleConnectionTimeout()); - if (ServiceRegistryConfig.INSTANCE.isProxyEnable()) { + httpClientOptions.setConnectTimeout(serviceRegistryConfig.getConnectionTimeout()); + httpClientOptions.setIdleTimeout(serviceRegistryConfig.getIdleConnectionTimeout()); + if (serviceRegistryConfig.isProxyEnable()) { ProxyOptions proxy = new ProxyOptions(); - proxy.setHost(ServiceRegistryConfig.INSTANCE.getProxyHost()); - proxy.setPort(ServiceRegistryConfig.INSTANCE.getProxyPort()); - proxy.setUsername(ServiceRegistryConfig.INSTANCE.getProxyUsername()); - proxy.setPassword(Encryptions.decode(ServiceRegistryConfig.INSTANCE.getProxyPasswd(), ServiceRegistryConfig.PROXY_KEY)); + proxy.setHost(serviceRegistryConfig.getProxyHost()); + proxy.setPort(serviceRegistryConfig.getProxyPort()); + proxy.setUsername(serviceRegistryConfig.getProxyUsername()); + proxy.setPassword( + Encryptions.decode(serviceRegistryConfig.getProxyPasswd(), serviceRegistryConfig.getProxyConfigTag())); httpClientOptions.setProxyOptions(proxy); } if (ver == HttpVersion.HTTP_2) { LOGGER.debug("service center client protocol version is HTTP/2"); httpClientOptions.setHttp2ClearTextUpgrade(false); } - if (ServiceRegistryConfig.INSTANCE.isSsl()) { + if (serviceRegistryConfig.isSsl()) { LOGGER.debug("service center client performs requests over TLS"); - VertxTLSBuilder.buildHttpClientOptions(ServiceRegistryConfig.SSL_KEY, httpClientOptions); + VertxTLSBuilder.buildHttpClientOptions(serviceRegistryConfig.getSslConfigTag(), httpClientOptions); } return httpClientOptions; } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java new file mode 100644 index 00000000000..6f0e8b0b4a2 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.client.http; + +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.auth.SignRequest; +import org.apache.servicecomb.foundation.common.net.IpPort; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; +import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.Handler; +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.CaseInsensitiveHeaders; +import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.http.HttpMethod; + +final class RestClientUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(RestClientUtil.class); + + static final String HEADER_CONTENT_TYPE = "Content-Type"; + + static final String HEADER_USER_AGENT = "User-Agent"; + + static final String HEADER_TENANT_NAME = "x-domain-name"; + + private List authHeaderProviders; + + private int requestTimeout; + + private String tenantName; + + private HttpClientPool httpClientPool; + + RestClientUtil(ServiceRegistryConfig serviceRegistryConfig) { + this.authHeaderProviders = serviceRegistryConfig.getAuthHeaderProviders(); + this.requestTimeout = serviceRegistryConfig.getRequestTimeout(); + this.tenantName = serviceRegistryConfig.getTenantName(); + this.httpClientPool = new HttpClientPool(serviceRegistryConfig); + } + + public void httpDo(RequestContext requestContext, Handler responseHandler) { + if (requestContext.getParams().getTimeout() != 0) { + httpDo(requestContext.getParams().getTimeout(), requestContext, responseHandler); + return; + } + httpDo(requestTimeout, requestContext, responseHandler); + } + + public void httpDo(long timeout, RequestContext requestContext, Handler responseHandler) { + HttpClientWithContext vertxHttpClient = httpClientPool.getClient(); + vertxHttpClient.runOnContext(httpClient -> { + IpPort ipPort = requestContext.getIpPort(); + HttpMethod httpMethod = requestContext.getMethod(); + RequestParam requestParam = requestContext.getParams(); + + if (ipPort == null) { + LOGGER.error("request address is null"); + responseHandler.handle(new RestResponse(requestContext, null)); + return; + } + + // query params + StringBuilder url = new StringBuilder(requestContext.getUri()); + String queryParams = requestParam.getQueryParams(); + if (!queryParams.isEmpty()) { + url.append(url.lastIndexOf("?") > 0 ? "&" : "?") + .append(queryParams); + } + + @SuppressWarnings("deprecation") + HttpClientRequest httpClientRequest = httpClient + .request(httpMethod, ipPort.getPort(), ipPort.getHostOrIp(), url.toString(), response -> { + responseHandler.handle(new RestResponse(requestContext, response)); + }); + + httpClientRequest.setTimeout(timeout) + .exceptionHandler(e -> { + LOGGER.error("{} {} fail, endpoint is {}:{}, message: {}", + httpMethod, + url.toString(), + ipPort.getHostOrIp(), + ipPort.getPort(), + e.getMessage()); + if (e instanceof UnknownHostException) { + // help analyses DNS problem + LOGGER.error("DNS resolve failed!", e); + } + responseHandler.handle(new RestResponse(requestContext, null)); + }); + + //headers + Map headers = defaultHeaders(); + httpClientRequest.headers().addAll(headers); + + if (requestParam.getHeaders() != null && requestParam.getHeaders().size() > 0) { + headers.putAll(requestParam.getHeaders()); + for (Map.Entry header : requestParam.getHeaders().entrySet()) { + httpClientRequest.putHeader(header.getKey(), header.getValue()); + } + } + + // cookies header + if (requestParam.getCookies() != null && requestParam.getCookies().size() > 0) { + StringBuilder stringBuilder = new StringBuilder(); + for (Map.Entry cookie : requestParam.getCookies().entrySet()) { + stringBuilder.append(cookie.getKey()) + .append("=") + .append(cookie.getValue()) + .append("; "); + } + httpClientRequest.putHeader("Cookie", stringBuilder.toString()); + headers.put("Cookie", stringBuilder.toString()); + } + + //SignAuth + SignRequest signReq = createSignRequest(requestContext.getMethod().toString(), + requestContext.getIpPort(), + requestContext.getParams(), + url.toString(), + headers); + httpClientRequest.headers().addAll(getSignAuthHeaders(signReq)); + + // body + if (httpMethod != HttpMethod.GET && requestParam.getBody() != null && requestParam.getBody().length > 0) { + httpClientRequest.end(Buffer.buffer(requestParam.getBody())); + } else { + httpClientRequest.end(); + } + }); + } + + public RequestContext createRequestContext(HttpMethod method, IpPort ipPort, String uri, + RequestParam requestParam) { + RequestContext requestContext = new RequestContext(); + requestContext.setMethod(method); + requestContext.setIpPort(ipPort); + requestContext.setUri(uri); + requestContext.setParams(requestParam); + return requestContext; + } + + public SignRequest createSignRequest(String method, IpPort ipPort, RequestParam requestParam, String url, + Map headers) { + SignRequest signReq = new SignRequest(); + StringBuilder endpoint = new StringBuilder("https://" + ipPort.getHostOrIp()); + endpoint.append(":" + ipPort.getPort()); + endpoint.append(url); + try { + signReq.setEndpoint(new URI(endpoint.toString())); + } catch (URISyntaxException e) { + LOGGER.error("set uri failed, uri is {}, message: {}", endpoint.toString(), e.getMessage()); + } + signReq.setContent((requestParam.getBody() != null && requestParam.getBody().length > 0) + ? new ByteArrayInputStream(requestParam.getBody()) + : null); + signReq.setHeaders(headers); + signReq.setHttpMethod(method); + signReq.setQueryParams(requestParam.getQueryParamsMap()); + return signReq; + } + + public void addDefaultHeaders(HttpClientRequest request) { + request.headers().addAll(getDefaultHeaders()); + } + + private Map defaultHeaders() { + Map headers = new HashMap<>(); + headers.put(HEADER_CONTENT_TYPE, "application/json"); + headers.put(HEADER_USER_AGENT, "cse-serviceregistry-client/1.0.0"); + headers.put(HEADER_TENANT_NAME, tenantName); + + return headers; + } + + public MultiMap getDefaultHeaders() { + return new CaseInsensitiveHeaders().addAll(defaultHeaders()); + } + + public void get(IpPort ipPort, String uri, RequestParam requestParam, + Handler responseHandler) { + httpDo(createRequestContext(HttpMethod.GET, ipPort, uri, requestParam), responseHandler); + } + + public void post(IpPort ipPort, String uri, RequestParam requestParam, + Handler responseHandler) { + httpDo(createRequestContext(HttpMethod.POST, ipPort, uri, requestParam), responseHandler); + } + + public void put(IpPort ipPort, String uri, RequestParam requestParam, + Handler responseHandler) { + httpDo(createRequestContext(HttpMethod.PUT, ipPort, uri, requestParam), responseHandler); + } + + public void delete(IpPort ipPort, String uri, RequestParam requestParam, + Handler responseHandler) { + httpDo(createRequestContext(HttpMethod.DELETE, ipPort, uri, requestParam), responseHandler); + } + + public Map getSignAuthHeaders(SignRequest signReq) { + Map headers = new HashMap<>(); + authHeaderProviders.forEach(provider -> headers.putAll(provider.getSignAuthHeaders(signReq))); + return headers; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java index 42d1e039b0f..b9026112d3c 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java @@ -40,6 +40,11 @@ import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpMethod; +/** + * This class is designed following singleton pattern, but it's not suitable for multi sc cluster occasion. + * @deprecated consider to use {@link RestClientUtil} instead. + */ +@Deprecated final class RestUtils { private static final Logger LOGGER = LoggerFactory.getLogger(RestUtils.class); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java index 3c5930fd7aa..12019076001 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java @@ -39,6 +39,7 @@ import org.apache.servicecomb.serviceregistry.api.Const; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; import org.apache.servicecomb.serviceregistry.api.request.CreateSchemaRequest; import org.apache.servicecomb.serviceregistry.api.request.CreateServiceRequest; @@ -60,14 +61,16 @@ import org.apache.servicecomb.serviceregistry.client.IpPortManager; import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; +import org.apache.servicecomb.serviceregistry.task.HeartbeatResult; +import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceHeartbeatTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.eventbus.Subscribe; import io.netty.handler.codec.http.HttpStatusClass; import io.vertx.core.Handler; @@ -78,7 +81,9 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient { private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryClientImpl.class); private static final String ERROR_CODE = "errorCode"; + private static final String ERR_SERVICE_NOT_EXISTS = "400012"; + private static final String ERR_SCHEMA_NOT_EXISTS = "400016"; private IpPortManager ipPortManager; @@ -87,8 +92,14 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient { // extract this, ServiceRegistryClient is better to be no status. private Map watchServices = new ConcurrentHashMap<>(); - public ServiceRegistryClientImpl(IpPortManager ipPortManager) { - this.ipPortManager = ipPortManager; + private RestClientUtil restClientUtil; + + private WebsocketClientUtil websocketClientUtil; + + public ServiceRegistryClientImpl(ServiceRegistryConfig serviceRegistryConfig) { + this.ipPortManager = new IpPortManager(serviceRegistryConfig); + this.restClientUtil = new RestClientUtil(serviceRegistryConfig); + this.websocketClientUtil = new WebsocketClientUtil(serviceRegistryConfig); } private LoadingCache> schemaCache = CacheBuilder.newBuilder() @@ -111,7 +122,7 @@ private void retry(RequestContext requestContext, Handler response LOGGER.warn("invoke service [{}] failed, retry.", requestContext.getUri()); requestContext.setIpPort(ipPortManager.getNextAvailableAddress(requestContext.getIpPort())); requestContext.incrementRetryTimes(); - RestUtils.httpDo(requestContext, responseHandler); + restClientUtil.httpDo(requestContext, responseHandler); } @VisibleForTesting @@ -195,7 +206,7 @@ static class ResponseWrapper { } // temporary copy from syncHandler - // we will use swagger invocation to replace RestUtils later. + // we will use swagger invocation to replace restClientUtil later. private Handler syncHandlerEx(CountDownLatch countDownLatch, Holder holder) { return restResponse -> { RequestContext requestContext = restResponse.getRequestContext(); @@ -282,7 +293,7 @@ public List getAllMicroservices() { IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, + restClientUtil.get(ipPort, Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL, new RequestParam(), syncHandler(countDownLatch, GetAllServicesResponse.class, holder)); @@ -303,7 +314,7 @@ public String getMicroserviceId(String appId, String microserviceName, String ve IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, + restClientUtil.get(ipPort, Const.REGISTRY_API.MICROSERVICE_EXISTENCE, new RequestParam().addQueryParam("type", "microservice") .addQueryParam("appId", appId) @@ -332,7 +343,7 @@ public boolean isSchemaExist(String microserviceId, String schemaId) { IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, + restClientUtil.get(ipPort, Const.REGISTRY_API.MICROSERVICE_EXISTENCE, new RequestParam().addQueryParam("type", "schema") .addQueryParam("serviceId", microserviceId) @@ -361,7 +372,7 @@ public boolean registerSchema(String microserviceId, String schemaId, String sch byte[] body = JsonUtils.writeValueAsBytes(request); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.put(ipPort, + restClientUtil.put(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_SCHEMA, microserviceId, schemaId), new RequestParam().setBody(body), syncHandlerEx(countDownLatch, holder)); @@ -419,7 +430,7 @@ private String doGetSchema(String microserviceId, String schemaId, boolean globa if (global) { param.addQueryParam("global", "true"); } - RestUtils.get(ipPort, + restClientUtil.get(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_SCHEMA, microserviceId, schemaId), param, syncHandler(countDownLatch, GetSchemaResponse.class, holder)); @@ -462,7 +473,7 @@ private Holder> getSchemas(String microserviceId, boolea requestParam.addQueryParam("global", "true"); } - RestUtils.get(ipPort, + restClientUtil.get(ipPort, String.format(url, microserviceId), requestParam, syncHandler(countDownLatch, GetSchemasResponse.class, holder)); @@ -498,7 +509,7 @@ public String registerMicroservice(Microservice microservice) { } CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.post(ipPort, + restClientUtil.post(ipPort, Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL, new RequestParam().setBody(body), syncHandler(countDownLatch, CreateServiceResponse.class, holder)); @@ -530,7 +541,7 @@ private Microservice doGetMicroservice(String microserviceId, boolean global) { if (global) { param.addQueryParam("global", "true"); } - RestUtils.get(ipPort, + restClientUtil.get(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_OPERATION_ONE, microserviceId), param, syncHandler(countDownLatch, GetServiceResponse.class, holder)); @@ -565,7 +576,7 @@ public String registerMicroserviceInstance(MicroserviceInstance instance) { } CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.post(ipPort, + restClientUtil.post(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL, instance.getServiceId()), new RequestParam().setBody(body), syncHandler(countDownLatch, RegisterInstanceResponse.class, holder)); @@ -585,7 +596,7 @@ public List getMicroserviceInstance(String consumerId, Str IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, + restClientUtil.get(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL, providerId), new RequestParam().addHeader("X-ConsumerId", consumerId), syncHandler(countDownLatch, GetInstancesResponse.class, holder)); @@ -606,7 +617,7 @@ public boolean unregisterMicroserviceInstance(String microserviceId, String micr IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.delete(ipPort, + restClientUtil.delete(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE, microserviceId, microserviceInstanceId), new RequestParam(), syncHandler(countDownLatch, HttpClientResponse.class, holder)); @@ -633,7 +644,7 @@ public HeartbeatResponse heartbeat(String microserviceId, String microserviceIns IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.put(ipPort, + restClientUtil.put(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_HEARTBEAT, microserviceId, microserviceInstanceId), new RequestParam().setTimeout(ServiceRegistryConfig.INSTANCE.getHeartBeatRequestTimeout()), syncHandler(countDownLatch, HttpClientResponse.class, holder)); @@ -677,7 +688,7 @@ public void watch(String selfMicroserviceId, AsyncResultCallback { + websocketClientUtil.open(ipPort, url, o -> { onOpen.success(o); LOGGER.info( "watching microservice {} successfully, " @@ -691,7 +702,7 @@ public void watch(String selfMicroserviceId, AsyncResultCallback { - MicroserviceInstanceChangedEvent response = null; + MicroserviceInstanceChangedEvent response; try { response = JsonUtils.readValue(bodyBuffer.getBytes(), MicroserviceInstanceChangedEvent.class); @@ -751,7 +762,7 @@ public MicroserviceInstances findServiceInstances(String consumerId, String appI requestParam.addQueryParam("rev", revision); } - RestUtils.get(ipPort, + restClientUtil.get(ipPort, Const.REGISTRY_API.MICROSERVICE_INSTANCES, requestParam, syncHandlerForInstances(countDownLatch, microserviceInstances)); @@ -803,7 +814,7 @@ public boolean updateMicroserviceProperties(String microserviceId, Map holder = new Holder<>(); IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, + restClientUtil.get(ipPort, String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE, serviceId, instanceId), new RequestParam().addHeader("X-ConsumerId", serviceId).addQueryParam("global", "true"), syncHandler(countDownLatch, MicroserviceInstanceResponse.class, holder)); @@ -888,7 +899,7 @@ public ServiceCenterInfo getServiceCenterInfo() { IpPort ipPort = ipPortManager.getAvailableAddress(); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.get(ipPort, + restClientUtil.get(ipPort, Const.REGISTRY_API.SERVICECENTER_VERSION, new RequestParam(), syncHandler(countDownLatch, ServiceCenterInfo.class, holder)); @@ -904,22 +915,22 @@ public ServiceCenterInfo getServiceCenterInfo() { } @Override - public boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId, String status) { + public boolean updateMicroserviceInstanceStatus(String microserviceId, String instanceId, + MicroserviceInstanceStatus status) { + if (null == status) { + throw new IllegalArgumentException("null status is now allowed"); + } + Holder holder = new Holder<>(); IpPort ipPort = ipPortManager.getAvailableAddress(); try { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("update status of microservice instance: {}", status); - } - String url = String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_STATUS, microserviceId, microserviceInstanceId); - if (StringUtils.isEmpty(status)) { - LOGGER.debug("empty status"); - return false; - } + LOGGER.debug("update status of microservice instance: {}", status); + String url = String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_STATUS, microserviceId, instanceId); Map queryParams = new HashMap<>(); - queryParams.put("value", new String[] {status}); + queryParams.put("value", new String[] {status.toString()}); CountDownLatch countDownLatch = new CountDownLatch(1); - RestUtils.put(ipPort, url, new RequestParam().setQueryParams(queryParams), syncHandler(countDownLatch, HttpClientResponse.class, holder)); + restClientUtil.put(ipPort, url, new RequestParam().setQueryParams(queryParams), + syncHandler(countDownLatch, HttpClientResponse.class, holder)); countDownLatch.await(); if (holder.value != null) { if (holder.value.statusCode() == Status.OK.getStatusCode()) { @@ -929,10 +940,17 @@ public boolean undateMicroserviceInstanceStatus(String microserviceId, String mi } } catch (Exception e) { LOGGER.error("update status of microservice instance {}/{} failed", - microserviceId, - microserviceInstanceId, - e); + microserviceId, + instanceId, + e); } return false; } + + @Subscribe + public void onMicroserviceHeartbeatTask(MicroserviceInstanceHeartbeatTask event) { + if (HeartbeatResult.SUCCESS.equals(event.getHeartbeatResult())) { + ipPortManager.initAutoDiscovery(); + } + } } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java index 2c96f5bd76a..96ab64fc76c 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java @@ -25,16 +25,21 @@ import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpVersion; -/** - * Created by on 2017/4/28. - */ -public final class WebsocketClientPool extends AbstractClientPool { +public class WebsocketClientPool extends AbstractClientPool { private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketClientPool.class); + /** + * The default instance, for default sc cluster. + */ public static final WebsocketClientPool INSTANCE = new WebsocketClientPool(); private WebsocketClientPool() { + super(ServiceRegistryConfig.INSTANCE); + } + + WebsocketClientPool(ServiceRegistryConfig serviceRegistryConfig) { + super(serviceRegistryConfig); } @Override @@ -43,19 +48,19 @@ protected boolean isWorker() { } @Override - public HttpClientOptions createHttpClientOptions() { - HttpVersion ver = ServiceRegistryConfig.INSTANCE.getHttpVersion(); + protected HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) { + HttpVersion ver = serviceRegistryConfig.getHttpVersion(); HttpClientOptions httpClientOptions = new HttpClientOptions(); httpClientOptions.setProtocolVersion(ver); - httpClientOptions.setConnectTimeout(ServiceRegistryConfig.INSTANCE.getConnectionTimeout()); - httpClientOptions.setIdleTimeout(ServiceRegistryConfig.INSTANCE.getIdleWatchTimeout()); + httpClientOptions.setConnectTimeout(serviceRegistryConfig.getConnectionTimeout()); + httpClientOptions.setIdleTimeout(serviceRegistryConfig.getIdleWatchTimeout()); if (ver == HttpVersion.HTTP_2) { LOGGER.debug("service center ws client protocol version is HTTP/2"); httpClientOptions.setHttp2ClearTextUpgrade(false); } - if (ServiceRegistryConfig.INSTANCE.isSsl()) { + if (serviceRegistryConfig.isSsl()) { LOGGER.debug("service center ws client performs requests over TLS"); - VertxTLSBuilder.buildHttpClientOptions(ServiceRegistryConfig.SSL_KEY, httpClientOptions); + VertxTLSBuilder.buildHttpClientOptions(serviceRegistryConfig.getSslConfigTag(), httpClientOptions); } return httpClientOptions; } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientUtil.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientUtil.java new file mode 100644 index 00000000000..9262752bc28 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientUtil.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.client.http; + +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.auth.SignRequest; +import org.apache.servicecomb.foundation.common.net.IpPort; +import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext; +import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.vertx.core.Handler; +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.CaseInsensitiveHeaders; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.WebSocketConnectOptions; + +public final class WebsocketClientUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketClientUtil.class); + + private WebsocketClientPool websocketClientPool; + + private List authHeaderProviders; + + WebsocketClientUtil(ServiceRegistryConfig serviceRegistryConfig) { + websocketClientPool = new WebsocketClientPool(serviceRegistryConfig); + authHeaderProviders = serviceRegistryConfig.getAuthHeaderProviders(); + } + + public void open(IpPort ipPort, String url, Handler onOpen, Handler onClose, + Handler onMessage, Handler onException, + Handler onConnectFailed) { + HttpClientWithContext vertxHttpClient = websocketClientPool.getClient(); + vertxHttpClient.runOnContext(client -> { + WebSocketConnectOptions options = new WebSocketConnectOptions(); + options.setHost(ipPort.getHostOrIp()).setPort(ipPort.getPort()).setURI(url) + .setHeaders(getDefaultHeaders().addAll(getSignAuthHeaders( + createSignRequest(HttpMethod.GET.name(), ipPort, new RequestParam(), url, new HashMap<>())))); + client.webSocket(options, asyncResult -> { + if (asyncResult.failed()) { + onConnectFailed.handle(asyncResult.cause()); + } else { + onOpen.handle(null); + asyncResult.result().exceptionHandler(v -> { + onException.handle(v); + try { + asyncResult.result().close(); + } catch (Exception err) { + LOGGER.error("ws close error.", err); + } + }); + asyncResult.result().closeHandler(v -> { + onClose.handle(v); + }); + asyncResult.result().pongHandler(pong -> { + // ignore, just prevent NPE. + }); + asyncResult.result().frameHandler((frame) -> onMessage.handle(frame.binaryData())); + } + }); + }); + } + + public MultiMap getDefaultHeaders() { + return new CaseInsensitiveHeaders().addAll(defaultHeaders()); + } + + private Map defaultHeaders() { + Map headers = new HashMap<>(); + headers.put(RestClientUtil.HEADER_CONTENT_TYPE, "application/json"); + headers.put(RestClientUtil.HEADER_USER_AGENT, "cse-serviceregistry-client/1.0.0"); + headers.put(RestClientUtil.HEADER_TENANT_NAME, ServiceRegistryConfig.INSTANCE.getTenantName()); + + return headers; + } + + public Map getSignAuthHeaders(SignRequest signReq) { + Map headers = new HashMap<>(); + authHeaderProviders.forEach(provider -> headers.putAll(provider.getSignAuthHeaders(signReq))); + return headers; + } + + public SignRequest createSignRequest(String method, IpPort ipPort, RequestParam requestParam, String url, + Map headers) { + SignRequest signReq = new SignRequest(); + StringBuilder endpoint = new StringBuilder("https://" + ipPort.getHostOrIp()); + endpoint.append(":" + ipPort.getPort()); + endpoint.append(url); + try { + signReq.setEndpoint(new URI(endpoint.toString())); + } catch (URISyntaxException e) { + LOGGER.error("set uri failed, uri is {}, message: {}", endpoint.toString(), e.getMessage()); + } + signReq.setContent((requestParam.getBody() != null && requestParam.getBody().length > 0) + ? new ByteArrayInputStream(requestParam.getBody()) + : null); + signReq.setHeaders(headers); + signReq.setHttpMethod(method); + signReq.setQueryParams(requestParam.getQueryParamsMap()); + return signReq; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java index 1426de91316..d7427ff384e 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java @@ -30,8 +30,10 @@ import io.vertx.core.http.WebSocketConnectOptions; /** - * Created by on 2017/4/28. + * This class is designed following singleton pattern, but it's not suitable for multi sc cluster occasion. + * @deprecated consider to use {@link WebsocketClientUtil} instead. */ +@Deprecated public final class WebsocketUtils { private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketUtils.class); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java index 2badf45982c..af1e5d736da 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java @@ -17,44 +17,32 @@ package org.apache.servicecomb.serviceregistry.config; -import java.net.URI; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.function.Function; -import org.apache.servicecomb.deployment.Deployment; -import org.apache.servicecomb.deployment.DeploymentProvider; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; import org.apache.servicecomb.foundation.common.net.IpPort; -import org.apache.servicecomb.foundation.common.net.NetUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicBooleanProperty; -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; +import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; +import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl; import io.vertx.core.http.HttpVersion; -/** - * Created by on 2016/12/23. - */ public final class ServiceRegistryConfig { - private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryConfig.class); + public static final ServiceRegistryConfig INSTANCE = buildFromConfiguration(); - public static final ServiceRegistryConfig INSTANCE = new ServiceRegistryConfig(); + public static final int DEFAULT_TIMEOUT_IN_MS = 30000; - private static final int DEFAULT_TIMEOUT_IN_MS = 30000; + public static final int DEFAULT_TIMEOUT_IN_SECONDS = 30; - private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30; + public static final int DEFAULT_REQUEST_TIMEOUT_IN_MS = 30000; - private static final int DEFAULT_REQUEST_TIMEOUT_IN_MS = 30000; + public static final int DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS = 3000; - private static final int DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS = 3000; + public static final int DEFAULT_CHECK_INTERVAL_IN_S = 30; - private static final int DEFAULT_CHECK_INTERVAL_IN_S = 30; - - private static final int DEFAULT_CHECK_TIMES = 3; + public static final int DEFAULT_CHECK_TIMES = 3; public static final String AUTH_ENABLED = "servicecomb.auth.enabled"; @@ -72,8 +60,6 @@ public final class ServiceRegistryConfig { public static final String NO_DOMAIN = "default"; - private boolean ssl = true; - public static final String PROXY_PRE_NAME = "servicecomb.proxy."; public static final String PROXY_ENABLE = PROXY_PRE_NAME + "enable"; @@ -98,238 +84,387 @@ public final class ServiceRegistryConfig { public static final String WORKER_POOL_NAME = "registry-vert.x-worker-thread"; - private ServiceRegistryConfig() { + private String registryName = ServiceRegistry.DEFAULT_REGISTRY_NAME; + + private HttpVersion httpVersion; + + private int instances; + + // TODO SCB-1691 getter of this field's behavior changed, should check + private boolean ssl = true; + + private ArrayList ipPort; + + private int connectionTimeout; + + private int idleConnectionTimeout; + + private int idleWatchTimeout; + + private int requestTimeout; + + //Set the timeout of the heartbeat request + private int heartBeatRequestTimeout; + + private int heartbeatInterval; + + private int instancePullInterval; + + private boolean registryAutoDiscovery; + + private int resendHeartBeatTimes; + + private boolean emptyInstanceProtectionEnabled; + + private boolean alwaysOverrideSchema; + + private boolean preferIpAddress; + + private boolean watch; + + private boolean clientAuthEnabled; + + private String registryApiVersion; + + private String tenantName; + + private String domainName; + + private String accessKey; + + private String secretKey; + + private boolean proxyEnable; + private String proxyHost; + + private int proxyPort; + + private String proxyUsername; + + private String proxyPasswd; + + private String sslConfigTag = SSL_KEY; + + private String proxyConfigTag = PROXY_KEY; + + private List authHeaderProviders; + + private Function serviceRegistryClientConstructor = + serviceRegistry -> new ServiceRegistryClientImpl(this); + + public ServiceRegistryConfig() { + } + + /** + * Read the service registry related configurations and build the {@link ServiceRegistryConfig} + * object. Since most of the service registry configurations are similar, this method may be + * convenient to construct multiple config objects. + */ + public static ServiceRegistryConfig buildFromConfiguration() { + return new ServiceRegistryConfigBuilder().build(); + } + + public String getTransport() { + return "rest"; + } + + public String getRegistryName() { + return registryName; + } + + public ServiceRegistryConfig setRegistryName(String registryName) { + this.registryName = registryName; + return this; } public HttpVersion getHttpVersion() { - DynamicStringProperty property = - DynamicPropertyFactory.getInstance() - .getStringProperty("servicecomb.service.registry.client.httpVersion", "HTTP_1_1"); - return HttpVersion.valueOf(property.get()); + return httpVersion; + } + + public ServiceRegistryConfig setHttpVersion(HttpVersion httpVersion) { + this.httpVersion = httpVersion; + return this; } public int getInstances() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty(VERTICLE_INSTANCES, 1); - int deployInstances = property.get(); - if (deployInstances <= 0) { - int nAvailableProcessors = Runtime.getRuntime().availableProcessors(); - LOGGER.warn("The property `{}` must be positive integer, fallback to use number of available processors: {}", - VERTICLE_INSTANCES, - nAvailableProcessors); - return nAvailableProcessors; - } - return deployInstances; + return instances; } + public ServiceRegistryConfig setInstances(int instances) { + this.instances = instances; + return this; + } public boolean isSsl() { - getIpPort(); - return this.ssl; + return ssl; + } + + public ServiceRegistryConfig setSsl(boolean ssl) { + this.ssl = ssl; + return this; } public ArrayList getIpPort() { - List uriList = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER) - .getAccessURL(); - ArrayList ipPortList = new ArrayList<>(); - uriList.forEach(anUriList -> { - try { - URI uri = new URI(anUriList.trim()); - this.ssl = "https".equals(uri.getScheme()); - ipPortList.add(NetUtils.parseIpPort(uri)); - } catch (Exception e) { - LOGGER.error("servicecomb.service.registry.address invalid : {}", anUriList, e); - } - }); - return ipPortList; + return ipPort; } - public String getTransport() { - return "rest"; + public ServiceRegistryConfig setIpPort(ArrayList ipPort) { + this.ipPort = ipPort; + return this; } public int getConnectionTimeout() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.connection", DEFAULT_TIMEOUT_IN_MS); - int timeout = property.get(); - return timeout < 0 ? DEFAULT_TIMEOUT_IN_MS : timeout; + return connectionTimeout; + } + + public ServiceRegistryConfig setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + return this; } public int getIdleConnectionTimeout() { - // connection pool idle timeout based on client heart beat interval. Heart beat default value is 30. - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.idle", DEFAULT_TIMEOUT_IN_SECONDS * 2); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout; + return idleConnectionTimeout; + } + + public ServiceRegistryConfig setIdleConnectionTimeout(int idleConnectionTimeout) { + this.idleConnectionTimeout = idleConnectionTimeout; + return this; } public int getIdleWatchTimeout() { - // watch idle timeout based on SC PING/PONG interval. SC default value is 30. - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.watch", DEFAULT_TIMEOUT_IN_SECONDS * 2); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout; + return idleWatchTimeout; + } + + public ServiceRegistryConfig setIdleWatchTimeout(int idleWatchTimeout) { + this.idleWatchTimeout = idleWatchTimeout; + return this; } public int getRequestTimeout() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.request", DEFAULT_REQUEST_TIMEOUT_IN_MS); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_REQUEST_TIMEOUT_IN_MS : timeout; + return requestTimeout; + } + + public ServiceRegistryConfig setRequestTimeout(int requestTimeout) { + this.requestTimeout = requestTimeout; + return this; } - //Set the timeout of the heartbeat request public int getHeartBeatRequestTimeout() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.client.timeout.heartbeat", - DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS); - int timeout = property.get(); - return timeout < 1 ? DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS : timeout; + return heartBeatRequestTimeout; + } + + public ServiceRegistryConfig setHeartBeatRequestTimeout(int heartBeatRequestTimeout) { + this.heartBeatRequestTimeout = heartBeatRequestTimeout; + return this; } public int getHeartbeatInterval() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.instance.healthCheck.interval", - DEFAULT_CHECK_INTERVAL_IN_S); - int interval = property.get(); - return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval; + return heartbeatInterval; + } + + public ServiceRegistryConfig setHeartbeatInterval(int heartbeatInterval) { + this.heartbeatInterval = heartbeatInterval; + return this; } public int getInstancePullInterval() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.instance.pull.interval", - DEFAULT_CHECK_INTERVAL_IN_S); - int interval = property.get(); - return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval; + return instancePullInterval; } - public long getMsInstancePullInterval() { - return TimeUnit.SECONDS.toMillis(getInstancePullInterval()); + public ServiceRegistryConfig setInstancePullInterval(int instancePullInterval) { + this.instancePullInterval = instancePullInterval; + return this; } public boolean isRegistryAutoDiscovery() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.autodiscovery", - false); - return property.get(); + return registryAutoDiscovery; + } + + public ServiceRegistryConfig setRegistryAutoDiscovery(boolean registryAutoDiscovery) { + this.registryAutoDiscovery = registryAutoDiscovery; + return this; } public int getResendHeartBeatTimes() { - DynamicIntProperty property = - DynamicPropertyFactory.getInstance() - .getIntProperty("servicecomb.service.registry.instance.healthCheck.times", - DEFAULT_CHECK_TIMES); - int times = property.get(); - return times < 0 ? DEFAULT_CHECK_TIMES : times; + return resendHeartBeatTimes; + } + + public ServiceRegistryConfig setResendHeartBeatTimes(int resendHeartBeatTimes) { + this.resendHeartBeatTimes = resendHeartBeatTimes; + return this; } public boolean isEmptyInstanceProtectionEnabled() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.instance.empty.protection", - true); - return property.get(); + return emptyInstanceProtectionEnabled; + } + + public ServiceRegistryConfig setEmptyInstanceProtectionEnabled(boolean emptyInstanceProtectionEnabled) { + this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled; + return this; } public boolean isAlwaysOverrideSchema() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.instance.alwaysOverrideSchema", - false); - return property.get(); + return alwaysOverrideSchema; + } + + public ServiceRegistryConfig setAlwaysOverrideSchema(boolean alwaysOverrideSchema) { + this.alwaysOverrideSchema = alwaysOverrideSchema; + return this; } public boolean isPreferIpAddress() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.instance.preferIpAddress", - false); - return property.get(); + return preferIpAddress; + } + + public ServiceRegistryConfig setPreferIpAddress(boolean preferIpAddress) { + this.preferIpAddress = preferIpAddress; + return this; } public boolean isWatch() { - DynamicBooleanProperty property = - DynamicPropertyFactory.getInstance() - .getBooleanProperty("servicecomb.service.registry.instance.watch", - true); - return property.get(); + return watch; + } + + public ServiceRegistryConfig setWatch(boolean watch) { + this.watch = watch; + return this; } public boolean isClientAuthEnabled() { - String isAuthEnabled = getProperty("false", AUTH_ENABLED); - return Boolean.parseBoolean(isAuthEnabled); + return clientAuthEnabled; + } + + public ServiceRegistryConfig setClientAuthEnabled(boolean clientAuthEnabled) { + this.clientAuthEnabled = clientAuthEnabled; + return this; } public String getRegistryApiVersion() { - return getProperty("v4", REGISTRY_API_VERSION); + return registryApiVersion; + } + + public ServiceRegistryConfig setRegistryApiVersion(String registryApiVersion) { + this.registryApiVersion = registryApiVersion; + return this; } public String getTenantName() { - return getProperty(NO_TENANT, TENANT_NAME); + return tenantName; + } + + public ServiceRegistryConfig setTenantName(String tenantName) { + this.tenantName = tenantName; + return this; } public String getDomainName() { - return getProperty(NO_DOMAIN, DOMAIN_NAME); + return domainName; + } + + public ServiceRegistryConfig setDomainName(String domainName) { + this.domainName = domainName; + return this; } public String getAccessKey() { - String tenantName = getProperty(null, TENANT_ACCESS_KEY); - return tenantName; + return accessKey; + } + + public ServiceRegistryConfig setAccessKey(String accessKey) { + this.accessKey = accessKey; + return this; } public String getSecretKey() { - String tenantName = getProperty(null, TENANT_SECRET_KEY); - return tenantName; + return secretKey; + } + + public ServiceRegistryConfig setSecretKey(String secretKey) { + this.secretKey = secretKey; + return this; } public Boolean isProxyEnable() { - String enable = getProperty("false", PROXY_ENABLE); - return Boolean.parseBoolean(enable); + return proxyEnable; + } + + public ServiceRegistryConfig setProxyEnable(Boolean proxyEnable) { + this.proxyEnable = proxyEnable; + return this; } public String getProxyHost() { - String host = getProperty("127.0.0.1", PROXY_HOST); - return host; + return proxyHost; + } + + public ServiceRegistryConfig setProxyHost(String proxyHost) { + this.proxyHost = proxyHost; + return this; } public int getProxyPort() { - String port = getProperty("8080", PROXY_PORT); - return Integer.parseInt(port); + return proxyPort; + } + + public ServiceRegistryConfig setProxyPort(int proxyPort) { + this.proxyPort = proxyPort; + return this; } public String getProxyUsername() { - String username = getProperty(null, PROXY_USERNAME); - return username; + return proxyUsername; + } + + public ServiceRegistryConfig setProxyUsername(String proxyUsername) { + this.proxyUsername = proxyUsername; + return this; } public String getProxyPasswd() { - String passwd = getProperty(null, PROXY_PASSWD); - return passwd; - } - - private String getProperty(String defaultValue, String... keys) { - String property = null; - for (String key : keys) { - property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get(); - if (property != null) { - break; - } - } - - if (property != null) { - return property; - } else { - return defaultValue; - } + return proxyPasswd; + } + + public ServiceRegistryConfig setProxyPasswd(String proxyPasswd) { + this.proxyPasswd = proxyPasswd; + return this; + } + + public String getSslConfigTag() { + return sslConfigTag; + } + + public ServiceRegistryConfig setSslConfigTag(String sslConfigTag) { + this.sslConfigTag = sslConfigTag; + return this; + } + + public String getProxyConfigTag() { + return proxyConfigTag; + } + + public ServiceRegistryConfig setProxyConfigTag(String proxyConfigTag) { + this.proxyConfigTag = proxyConfigTag; + return this; + } + + public List getAuthHeaderProviders() { + return authHeaderProviders; + } + + public ServiceRegistryConfig setAuthHeaderProviders( + List authHeaderProviders) { + this.authHeaderProviders = authHeaderProviders; + return this; + } + + public ServiceRegistryConfig setServiceRegistryClientConstructor( + Function serviceRegistryClientConstructor) { + this.serviceRegistryClientConstructor = serviceRegistryClientConstructor; + return this; + } + + public ServiceRegistryClient createServiceRegistryClient(ServiceRegistry serviceRegistry) { + return this.serviceRegistryClientConstructor.apply(serviceRegistry); } } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java new file mode 100644 index 00000000000..16515324969 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java @@ -0,0 +1,317 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.config; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.apache.servicecomb.config.ConfigUtil; +import org.apache.servicecomb.deployment.Deployment; +import org.apache.servicecomb.deployment.DeploymentProvider; +import org.apache.servicecomb.foundation.auth.AuthHeaderProvider; +import org.apache.servicecomb.foundation.common.net.IpPort; +import org.apache.servicecomb.foundation.common.net.NetUtils; +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netflix.config.DynamicBooleanProperty; +import com.netflix.config.DynamicIntProperty; +import com.netflix.config.DynamicPropertyFactory; +import com.netflix.config.DynamicStringProperty; + +import io.vertx.core.http.HttpVersion; + +class ServiceRegistryConfigBuilder { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryConfigBuilder.class); + + static { + // ensure configurations are loaded properly + ConfigUtil.installDynamicConfig(); + } + + private boolean ssl; + + public ServiceRegistryConfig build() { + return new ServiceRegistryConfig() + .setHttpVersion(getHttpVersion()) + .setInstances(getInstances()) + .setIpPort(getIpPort()) + .setSsl(isSsl()) + .setConnectionTimeout(getConnectionTimeout()) + .setIdleConnectionTimeout(getIdleConnectionTimeout()) + .setIdleWatchTimeout(getIdleWatchTimeout()) + .setRequestTimeout(getRequestTimeout()) + .setHeartBeatRequestTimeout(getHeartBeatRequestTimeout()) + .setHeartbeatInterval(getHeartbeatInterval()) + .setInstancePullInterval(getInstancePullInterval()) + .setRegistryAutoDiscovery(isRegistryAutoDiscovery()) + .setResendHeartBeatTimes(getResendHeartBeatTimes()) + .setEmptyInstanceProtectionEnabled(isEmptyInstanceProtectionEnabled()) + .setAlwaysOverrideSchema(isAlwaysOverrideSchema()) + .setPreferIpAddress(isPreferIpAddress()) + .setWatch(isWatch()) + .setClientAuthEnabled(isClientAuthEnabled()) + .setRegistryApiVersion(getRegistryApiVersion()) + .setTenantName(getTenantName()) + .setDomainName(getDomainName()) + .setAccessKey(getAccessKey()) + .setSecretKey(getSecretKey()) + .setProxyEnable(isProxyEnable()) + .setProxyHost(getProxyHost()) + .setProxyPort(getProxyPort()) + .setProxyUsername(getProxyUsername()) + .setProxyPasswd(getProxyPasswd()) + .setAuthHeaderProviders(getAuthHeaderProviders()); + } + + public HttpVersion getHttpVersion() { + DynamicStringProperty property = + DynamicPropertyFactory.getInstance() + .getStringProperty("servicecomb.service.registry.client.httpVersion", "HTTP_1_1"); + return HttpVersion.valueOf(property.get()); + } + + public int getInstances() { + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty(ServiceRegistryConfig.VERTICLE_INSTANCES, 1); + int deployInstances = property.get(); + if (deployInstances <= 0) { + int nAvailableProcessors = Runtime.getRuntime().availableProcessors(); + LOGGER.warn("The property `{}` must be positive integer, fallback to use number of available processors: {}", + ServiceRegistryConfig.VERTICLE_INSTANCES, + nAvailableProcessors); + return nAvailableProcessors; + } + return deployInstances; + } + + /** + * must be invoked after {@link #getIpPort()} + */ + public boolean isSsl() { + return this.ssl; + } + + public ArrayList getIpPort() { + List uriList = Objects + .requireNonNull(Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER), + "no sc address found!") + .getAccessURL(); + ArrayList ipPortList = new ArrayList<>(); + uriList.forEach(anUriList -> { + try { + URI uri = new URI(anUriList.trim()); + this.ssl = "https".equals(uri.getScheme()); + ipPortList.add(NetUtils.parseIpPort(uri)); + } catch (Exception e) { + LOGGER.error("servicecomb.service.registry.address invalid : {}", anUriList, e); + } + }); + return ipPortList; + } + + public String getTransport() { + return "rest"; + } + + public int getConnectionTimeout() { + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.client.timeout.connection", + ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_MS); + int timeout = property.get(); + return timeout < 0 ? ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_MS : timeout; + } + + public int getIdleConnectionTimeout() { + // connection pool idle timeout based on client heart beat interval. Heart beat default value is 30. + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.client.timeout.idle", + ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2); + int timeout = property.get(); + return timeout < 1 ? ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout; + } + + public int getIdleWatchTimeout() { + // watch idle timeout based on SC PING/PONG interval. SC default value is 30. + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.client.timeout.watch", + ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2); + int timeout = property.get(); + return timeout < 1 ? ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout; + } + + public int getRequestTimeout() { + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.client.timeout.request", + ServiceRegistryConfig.DEFAULT_REQUEST_TIMEOUT_IN_MS); + int timeout = property.get(); + return timeout < 1 ? ServiceRegistryConfig.DEFAULT_REQUEST_TIMEOUT_IN_MS : timeout; + } + + //Set the timeout of the heartbeat request + public int getHeartBeatRequestTimeout() { + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.client.timeout.heartbeat", + ServiceRegistryConfig.DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS); + int timeout = property.get(); + return timeout < 1 ? ServiceRegistryConfig.DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS : timeout; + } + + public int getHeartbeatInterval() { + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.instance.healthCheck.interval", + ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S); + int interval = property.get(); + return interval < 0 ? ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S : interval; + } + + public int getInstancePullInterval() { + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.instance.pull.interval", + ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S); + int interval = property.get(); + return interval < 0 ? ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S : interval; + } + + public boolean isRegistryAutoDiscovery() { + DynamicBooleanProperty property = + DynamicPropertyFactory.getInstance() + .getBooleanProperty("servicecomb.service.registry.autodiscovery", + false); + return property.get(); + } + + public int getResendHeartBeatTimes() { + DynamicIntProperty property = + DynamicPropertyFactory.getInstance() + .getIntProperty("servicecomb.service.registry.instance.healthCheck.times", + ServiceRegistryConfig.DEFAULT_CHECK_TIMES); + int times = property.get(); + return times < 0 ? ServiceRegistryConfig.DEFAULT_CHECK_TIMES : times; + } + + public boolean isEmptyInstanceProtectionEnabled() { + DynamicBooleanProperty property = + DynamicPropertyFactory.getInstance() + .getBooleanProperty("servicecomb.service.registry.instance.empty.protection", + true); + return property.get(); + } + + public boolean isAlwaysOverrideSchema() { + DynamicBooleanProperty property = + DynamicPropertyFactory.getInstance() + .getBooleanProperty("servicecomb.service.registry.instance.alwaysOverrideSchema", + false); + return property.get(); + } + + public boolean isPreferIpAddress() { + DynamicBooleanProperty property = + DynamicPropertyFactory.getInstance() + .getBooleanProperty("servicecomb.service.registry.instance.preferIpAddress", + false); + return property.get(); + } + + public boolean isWatch() { + DynamicBooleanProperty property = + DynamicPropertyFactory.getInstance() + .getBooleanProperty("servicecomb.service.registry.instance.watch", + true); + return property.get(); + } + + public boolean isClientAuthEnabled() { + String isAuthEnabled = getProperty("false", ServiceRegistryConfig.AUTH_ENABLED); + return Boolean.parseBoolean(isAuthEnabled); + } + + public String getRegistryApiVersion() { + return getProperty("v4", ServiceRegistryConfig.REGISTRY_API_VERSION); + } + + public String getTenantName() { + return getProperty(ServiceRegistryConfig.NO_TENANT, ServiceRegistryConfig.TENANT_NAME); + } + + public String getDomainName() { + return getProperty(ServiceRegistryConfig.NO_DOMAIN, ServiceRegistryConfig.DOMAIN_NAME); + } + + public String getAccessKey() { + return getProperty(null, ServiceRegistryConfig.TENANT_ACCESS_KEY); + } + + public String getSecretKey() { + return getProperty(null, ServiceRegistryConfig.TENANT_SECRET_KEY); + } + + public Boolean isProxyEnable() { + String enable = getProperty("false", ServiceRegistryConfig.PROXY_ENABLE); + return Boolean.parseBoolean(enable); + } + + public String getProxyHost() { + return getProperty("127.0.0.1", ServiceRegistryConfig.PROXY_HOST); + } + + public int getProxyPort() { + String port = getProperty("8080", ServiceRegistryConfig.PROXY_PORT); + return Integer.parseInt(port); + } + + public String getProxyUsername() { + return getProperty(null, ServiceRegistryConfig.PROXY_USERNAME); + } + + public String getProxyPasswd() { + return getProperty(null, ServiceRegistryConfig.PROXY_PASSWD); + } + + public List getAuthHeaderProviders() { + return SPIServiceUtils.getAllService(AuthHeaderProvider.class); + } + + private String getProperty(String defaultValue, String... keys) { + String property = null; + for (String key : keys) { + property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get(); + if (property != null) { + break; + } + } + + if (property != null) { + return property; + } else { + return defaultValue; + } + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java index 24f4d6b3d6a..6cc2e50ce8f 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java @@ -20,30 +20,22 @@ import java.util.Map; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.foundation.common.event.EventManager; import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent; import com.google.common.eventbus.EventBus; public class AppManager { - private ServiceRegistry serviceRegistry; - // key: appId private Map apps = new ConcurrentHashMapEx<>(); - public AppManager(ServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; - + public AppManager() { getEventBus().register(this); } - public ServiceRegistry getServiceRegistry() { - return serviceRegistry; - } - public EventBus getEventBus() { - return serviceRegistry.getEventBus(); + return EventManager.getEventBus(); } public Map getApps() { diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java index d6953dbef02..03ae5feca31 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java @@ -21,6 +21,7 @@ import java.util.List; import org.apache.servicecomb.foundation.common.VendorExtensions; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.event.CreateMicroserviceVersionEvent; @@ -47,10 +48,7 @@ public class MicroserviceVersion { public MicroserviceVersion(MicroserviceVersions microserviceVersions, String microserviceId, String microserviceName, Collection instances) { - Microservice microservice = microserviceVersions - .getAppManager() - .getServiceRegistry() - .getAggregatedRemoteMicroservice(microserviceId); + Microservice microservice = RegistryUtils.getAggregatedRemoteMicroservice(microserviceId); if (microservice == null) { throw new IllegalStateException( String.format("failed to query by microserviceId '%s' from ServiceCenter.", microserviceId)); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java index 66b81f6a551..5dc1cec2abc 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java @@ -28,6 +28,7 @@ import org.apache.servicecomb.foundation.common.VendorExtensions; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.Const; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; @@ -35,9 +36,9 @@ import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser; -import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent; import org.apache.servicecomb.serviceregistry.event.CreateMicroserviceEvent; import org.apache.servicecomb.serviceregistry.event.DestroyMicroserviceEvent; +import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -165,7 +166,7 @@ public void pullInstances() { return; } - if (!microserviceInstances.isNeedRefresh()) { + if (null != revision && revision.equals(microserviceInstances.getRevision())) { return; } @@ -177,7 +178,7 @@ public void pullInstances() { } protected MicroserviceInstances findServiceInstances() { - return appManager.getServiceRegistry().findServiceInstances(appId, + return RegistryUtils.findServiceInstances(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL, revision); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java index 05e13232842..ca34f1c1585 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.UUID; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; @@ -48,7 +49,7 @@ public StaticMicroserviceVersions(AppManager appManager, String appId, String mi public StaticMicroserviceVersions init(Class schemaIntfCls, String version, List addedInstances) { this.schemaIntfCls = schemaIntfCls; - Swagger swagger = this.appManager.getServiceRegistry().getSwaggerLoader() + Swagger swagger = RegistryUtils.getSwaggerLoader() .registerSwagger(appId, shortName, shortName, schemaIntfCls); String swaggerContent = SwaggerUtils.swaggerToString(swagger); LOGGER.info("generate swagger for 3rd party service [{}]/[{}], swagger: {}", @@ -88,7 +89,7 @@ protected MicroserviceVersion createMicroserviceVersion(String microserviceId, L } private void createMicroservice(String version) { - String environment = appManager.getServiceRegistry().getMicroservice().getEnvironment(); + String environment = RegistryUtils.getMicroservice().getEnvironment(); microservice.setAppId(this.getAppId()); microservice.setServiceName(this.getShortName()); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java index b6dd6155c41..21e0a909b1e 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java @@ -20,6 +20,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.serviceregistry.registry.RemoteServiceRegistry; import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryTaskInitializer; @@ -86,7 +87,7 @@ public DynamicIntProperty getAutoCheckIntervalProperty() { @Override public void init(RemoteServiceRegistry remoteServiceRegistry) { - appManager = remoteServiceRegistry.getAppManager(); + appManager = RegistryUtils.getAppManager(); taskPool = remoteServiceRegistry.getTaskPool(); eventBus = remoteServiceRegistry.getEventBus(); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java index 7158913c3a1..3180da70a93 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java @@ -116,7 +116,6 @@ protected boolean isExpired(VersionedCache existing, VersionedCache inputCache) public DiscoveryTreeNode discovery(DiscoveryContext context, String appId, String microserviceName, String versionRule) { VersionedCache instanceVersionedCache = RegistryUtils - .getServiceRegistry() .getInstanceCacheManager() .getOrCreateVersionedCache(appId, microserviceName, versionRule); diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java index 70cd5a005b9..a8c4bc3103f 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java @@ -27,7 +27,9 @@ import java.util.Set; import java.util.concurrent.ExecutorService; +import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper; import org.apache.servicecomb.serviceregistry.Features; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.ServiceRegistry; import org.apache.servicecomb.serviceregistry.api.Const; import org.apache.servicecomb.serviceregistry.api.registry.BasePath; @@ -37,18 +39,18 @@ import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew; -import org.apache.servicecomb.serviceregistry.client.IpPortManager; import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; -import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager; import org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersions; import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser; -import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheRefreshedEvent; +import org.apache.servicecomb.serviceregistry.registry.cache.RefreshableServiceRegistryCache; +import org.apache.servicecomb.serviceregistry.registry.cache.ServiceRegistryCache; import org.apache.servicecomb.serviceregistry.task.MicroserviceServiceCenterTask; import org.apache.servicecomb.serviceregistry.task.ServiceCenterTask; import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent; @@ -74,24 +76,21 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry { protected Microservice microservice; - protected AppManager appManager; - - protected InstanceCacheManager instanceCacheManager; - - protected IpPortManager ipPortManager; - protected ServiceRegistryClient srClient; protected ServiceRegistryConfig serviceRegistryConfig; protected ServiceCenterTask serviceCenterTask; - protected SwaggerLoader swaggerLoader = new SwaggerLoader(this); - protected ExecutorService executorService = MoreExecutors.newDirectExecutorService(); + private String name; + + RefreshableServiceRegistryCache serviceRegistryCache; + public AbstractServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, MicroserviceDefinition microserviceDefinition) { + setName(serviceRegistryConfig.getRegistryName()); this.eventBus = eventBus; this.serviceRegistryConfig = serviceRegistryConfig; this.microserviceDefinition = microserviceDefinition; @@ -100,26 +99,22 @@ public AbstractServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceR @Override public void init() { - appManager = new AppManager(this); - instanceCacheManager = new InstanceCacheManagerNew(appManager); - ipPortManager = new IpPortManager(serviceRegistryConfig, instanceCacheManager); if (srClient == null) { srClient = createServiceRegistryClient(); + eventBus.register(srClient); } createServiceCenterTask(); eventBus.register(this); - } - @Override - public SwaggerLoader getSwaggerLoader() { - return swaggerLoader; + initCache(); } - @Override - public AppManager getAppManager() { - return appManager; + private void initCache() { + serviceRegistryCache = new RefreshableServiceRegistryCache(microservice, srClient); + serviceRegistryCache.setCacheRefreshedWatcher( + caches -> eventBus.post(new MicroserviceCacheRefreshedEvent(caches))); } @Override @@ -146,15 +141,6 @@ public void setServiceRegistryClient(ServiceRegistryClient serviceRegistryClient this.srClient = serviceRegistryClient; } - public IpPortManager getIpPortManager() { - return ipPortManager; - } - - @Override - public InstanceCacheManager getInstanceCacheManager() { - return instanceCacheManager; - } - @Override public String getAppId() { return microservice.getAppId(); @@ -228,44 +214,15 @@ public List findServiceInstance(String appId, String servi public MicroserviceInstances findServiceInstances(String appId, String serviceName, String versionRule, String revision) { - MicroserviceInstances microserviceInstances = srClient.findServiceInstances(microservice.getServiceId(), - appId, - serviceName, - versionRule, - revision); - - if (microserviceInstances == null) { - LOGGER.error("Can not find any instances from service center due to previous errors. service={}/{}/{}", - appId, - serviceName, - versionRule); - return null; - } - - if (microserviceInstances.isMicroserviceNotExist()) { - return microserviceInstances; - } - - if (!microserviceInstances.isNeedRefresh()) { - LOGGER.debug("instances revision is not changed, service={}/{}/{}", appId, serviceName, versionRule); - return microserviceInstances; - } + MicroserviceCache microserviceCache = serviceRegistryCache + .findServiceCache(MicroserviceCacheKey.builder() + .serviceName(serviceName).appId(appId).env(microservice.getEnvironment()).build()); + return RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache); + } - List instances = microserviceInstances.getInstancesResponse().getInstances(); - LOGGER.info("find instances[{}] from service center success. service={}/{}/{}, old revision={}, new revision={}", - instances.size(), - appId, - serviceName, - versionRule, - revision, - microserviceInstances.getRevision()); - for (MicroserviceInstance instance : instances) { - LOGGER.info("service id={}, instance id={}, endpoints={}", - instance.getServiceId(), - instance.getInstanceId(), - instance.getEndpoints()); - } - return microserviceInstances; + @Override + public MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) { + return serviceRegistryCache.findServiceCache(microserviceCacheKey); } @Override @@ -315,10 +272,12 @@ public void destroy() { public void registerMicroserviceMapping(String microserviceName, String version, List instances, Class schemaIntfCls) { MicroserviceNameParser parser = new MicroserviceNameParser(microservice.getAppId(), microserviceName); - MicroserviceManager microserviceManager = appManager.getOrCreateMicroserviceManager(parser.getAppId()); + MicroserviceManager microserviceManager = RegistryUtils.getAppManager() + .getOrCreateMicroserviceManager(parser.getAppId()); microserviceManager.getVersionsByName() .computeIfAbsent(microserviceName, - svcName -> new StaticMicroserviceVersions(this.appManager, parser.getAppId(), microserviceName) + svcName -> new StaticMicroserviceVersions(RegistryUtils.getAppManager(), parser.getAppId(), + microserviceName) .init(schemaIntfCls, version, instances) ); } @@ -336,6 +295,20 @@ public void registerMicroserviceMappingByEndpoints(String microserviceName, Stri registerMicroserviceMapping(microserviceName, version, microserviceInstances, schemaIntfCls); } + @Override + public String getName() { + return name; + } + + void setName(String name) { + RegistryUtils.validateRegistryName(name); + this.name = name; + } + + public ServiceRegistryCache getServiceRegistryCache() { + return serviceRegistryCache; + } + @Subscribe public void onShutdown(ShutdownEvent event) { LOGGER.info("service center task is shutdown."); @@ -345,17 +318,28 @@ public void onShutdown(ShutdownEvent event) { // post from watch eventloop, should refresh the exact microservice instances immediately @Subscribe public void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent changedEvent) { - executorService.execute(() -> appManager.onMicroserviceInstanceChanged(changedEvent)); + executorService.execute(new SuppressedRunnableWrapper( + () -> { + serviceRegistryCache.onMicroserviceInstanceChanged(changedEvent); + RegistryUtils.getAppManager().onMicroserviceInstanceChanged(changedEvent); + })); } // post from watch eventloop, should refresh all instances immediately @Subscribe public void serviceRegistryRecovery(RecoveryEvent event) { - executorService.execute(appManager::pullInstances); + executorService.execute(() -> { + serviceRegistryCache.forceRefreshCache(); + RegistryUtils.getAppManager().pullInstances(); + }); } @Subscribe public void onSafeModeChanged(SafeModeChangeEvent modeChangeEvent) { - executorService.execute(() -> appManager.onSafeModeChanged(modeChangeEvent)); + executorService.execute(() -> { + LOGGER.warn("receive SafeModeChangeEvent, current mode={}", modeChangeEvent.getCurrentMode()); + serviceRegistryCache.onSafeModeChanged(modeChangeEvent); + RegistryUtils.getAppManager().onSafeModeChanged(modeChangeEvent); + }); } } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java index 72bd2552a6f..d68a46eaeb5 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java @@ -24,16 +24,12 @@ import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; -import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl; import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition; -import org.apache.servicecomb.serviceregistry.task.HeartbeatResult; -import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceHeartbeatTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.eventbus.EventBus; -import com.google.common.eventbus.Subscribe; public class RemoteServiceRegistry extends AbstractServiceRegistry { private static final Logger LOGGER = LoggerFactory.getLogger(RemoteServiceRegistry.class); @@ -57,7 +53,8 @@ public void init() { @Override public Thread newThread(Runnable r) { - Thread thread = new Thread(r, "Service Center Task [" + (taskId++) + "]"); + Thread thread = new Thread(r, + RemoteServiceRegistry.super.getName() + " Service Center Task [" + (taskId++) + "]"); thread.setUncaughtExceptionHandler( (t, e) -> LOGGER.error("Service Center Task Thread is terminated! thread: [{}]", t, e)); return thread; @@ -70,7 +67,7 @@ public Thread newThread(Runnable r) { @Override protected ServiceRegistryClient createServiceRegistryClient() { - return new ServiceRegistryClientImpl(ipPortManager); + return serviceRegistryConfig.createServiceRegistryClient(this); } @Override @@ -83,7 +80,9 @@ public void run() { TimeUnit.SECONDS); taskPool.scheduleAtFixedRate( - new SuppressedRunnableWrapper(appManager::pullInstances), + new SuppressedRunnableWrapper(() -> { + serviceRegistryCache.refreshCache(); + }), serviceRegistryConfig.getInstancePullInterval(), serviceRegistryConfig.getInstancePullInterval(), TimeUnit.SECONDS); @@ -93,13 +92,6 @@ public void run() { } } - @Subscribe - public void onMicroserviceHeartbeatTask(MicroserviceInstanceHeartbeatTask event) { - if (HeartbeatResult.SUCCESS.equals(event.getHeartbeatResult())) { - ipPortManager.initAutoDiscovery(); - } - } - public ScheduledThreadPoolExecutor getTaskPool() { return this.taskPool; } diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java index ce44b79473a..a672bbfe00a 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java @@ -35,29 +35,9 @@ public final class ServiceRegistryFactory { private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryFactory.class); - private static final Object LOCK = new Object(); - - private static volatile ServiceRegistry serviceRegistry; - private ServiceRegistryFactory() { } - public static ServiceRegistry getServiceRegistry() { - return serviceRegistry; - } - - public static ServiceRegistry getOrCreate(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, - MicroserviceDefinition microserviceDefinition) { - if (serviceRegistry == null) { - synchronized (LOCK) { - if (serviceRegistry == null) { - serviceRegistry = create(eventBus, serviceRegistryConfig, microserviceDefinition); - } - } - } - return serviceRegistry; - } - public static ServiceRegistry createLocal() { return createLocal(System.getProperty(LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY)); } @@ -72,8 +52,16 @@ public static ServiceRegistry createLocal(String localFile) { return new LocalServiceRegistry(eventBus, serviceRegistryConfig, microserviceDefinition).localFile(localFile); } + public static ServiceRegistry create(ServiceRegistryConfig serviceRegistryConfig, + MicroserviceDefinition microserviceDefinition) { + return create(null, serviceRegistryConfig, microserviceDefinition); + } + public static ServiceRegistry create(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig, MicroserviceDefinition microserviceDefinition) { + if (null == eventBus) { + eventBus = new SimpleEventBus(); + } String localModeFile = System.getProperty(LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY); if (!StringUtils.isEmpty(localModeFile)) { LOGGER.info( diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCache.java new file mode 100644 index 00000000000..a0082f771de --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCache.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; + +public class AggregateMicroserviceCache implements MicroserviceCache { + private MicroserviceCacheKey key; + + Map caches; + + AtomicLong revisionCounter = new AtomicLong(); + + private String revisionId = revisionCounter.toString(); + + private MicroserviceCacheStatus status = MicroserviceCacheStatus.INIT; + + private List instances = new ArrayList<>(); + + Collection serviceRegistries; + + private final Object refreshLock = new Object(); + + public AggregateMicroserviceCache(MicroserviceCacheKey key, Collection serviceRegistries) { + this.key = key; + this.serviceRegistries = serviceRegistries; + + refresh(); + } + + @Override + public void refresh() { + refreshInnerState(false); + } + + private void refreshInnerState(boolean b) { + synchronized (refreshLock) { + fillInMicroserviceCaches(b); + fillInInstanceList(); + updateRevisionId(); + refreshStatus(); + } + } + + @Override + public void forceRefresh() { + refreshInnerState(true); + } + + private void fillInMicroserviceCaches(boolean isForce) { + HashMap cacheMap = new LinkedHashMap<>(); + for (ServiceRegistry serviceRegistry : serviceRegistries) { + MicroserviceCache microserviceCache = serviceRegistry.findMicroserviceCache(key); + if (!isValidMicroserviceCache(microserviceCache)) { + continue; + } + if (isForce) { + microserviceCache.forceRefresh(); + } + cacheMap.put(serviceRegistry.getName(), microserviceCache); + } + caches = cacheMap; + } + + private void fillInInstanceList() { + ArrayList instances = new ArrayList<>(); + for (Entry stringMicroserviceCacheEntry : caches.entrySet()) { + instances.addAll(stringMicroserviceCacheEntry.getValue().getInstances()); + } + this.instances = Collections.unmodifiableList(instances); + } + + private void updateRevisionId() { + revisionCounter.incrementAndGet(); + revisionId = revisionCounter.toString(); + } + + private void refreshStatus() { + if (caches.size() == 0) { + status = MicroserviceCacheStatus.SERVICE_NOT_FOUND; + } else { + status = MicroserviceCacheStatus.REFRESHED; + } + } + + private boolean isValidMicroserviceCache(MicroserviceCache microserviceCache) { + return !( + Objects.isNull(microserviceCache) + || MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(microserviceCache.getStatus()) + ); + } + + @Override + public MicroserviceCacheKey getKey() { + return key; + } + + @Override + public List getInstances() { + return instances; + } + + @Override + public String getRevisionId() { + return revisionId; + } + + @Override + public MicroserviceCacheStatus getStatus() { + return status; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCache.java new file mode 100644 index 00000000000..687cccc574d --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCache.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.Subscribe; + +public class AggregateServiceRegistryCache implements ServiceRegistryCache { + + private static final Logger LOGGER = LoggerFactory.getLogger(AggregateServiceRegistryCache.class); + + Collection serviceRegistries; + + final Map microserviceCache = new ConcurrentHashMapEx<>(); + + private Consumer> cacheRefreshedWatcher; + + public AggregateServiceRegistryCache(Collection serviceRegistries) { + this.serviceRegistries = serviceRegistries; + } + + @Override + public MicroserviceCache findServiceCache(MicroserviceCacheKey microserviceCacheKey) { + AggregateMicroserviceCache microserviceCache = this.microserviceCache.computeIfAbsent(microserviceCacheKey, + key -> new AggregateMicroserviceCache(key, serviceRegistries)); + removeMicroserviceCacheIfNotExist(microserviceCache); + return microserviceCache; + } + + @Override + public ServiceRegistryCache setCacheRefreshedWatcher(Consumer> cacheRefreshedWatcher) { + this.cacheRefreshedWatcher = cacheRefreshedWatcher; + return this; + } + + @Subscribe + public void onMicroserviceCacheRefreshed(MicroserviceCacheRefreshedEvent event) { + List microserviceCaches = event.getMicroserviceCaches(); + if (null == microserviceCaches || microserviceCaches.isEmpty()) { + return; + } + + List refreshedAggregateMicroserviceCaches = microserviceCaches.stream() + .map(cache -> this.microserviceCache.get(cache.getKey())) + .filter(Objects::nonNull) + .peek(AggregateMicroserviceCache::refresh) + .peek(this::removeMicroserviceCacheIfNotExist) + .collect(Collectors.toList()); + + LOGGER.info("[{}] caches get refreshed", refreshedAggregateMicroserviceCaches.size()); + refreshedAggregateMicroserviceCaches.forEach(cache -> { + LOGGER.info("[{}]: status={}, revisionId={}", cache.getKey(), cache.getStatus(), cache.getRevisionId()); + }); + + if (null != cacheRefreshedWatcher) { + cacheRefreshedWatcher.accept(refreshedAggregateMicroserviceCaches); + } + } + + private void removeMicroserviceCacheIfNotExist(MicroserviceCache cache) { + if (MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(cache.getStatus())) { + microserviceCache.remove(cache.getKey()); + LOGGER.info("microserviceCache[{}] got removed", cache.getKey()); + } + } + + @Override + public Map getMicroserviceCaches() { + return Collections.unmodifiableMap(microserviceCache); + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCache.java new file mode 100644 index 00000000000..d6a49c28891 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCache.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.List; + +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; + +public interface MicroserviceCache { + MicroserviceCacheKey getKey(); + + List getInstances(); + + String getRevisionId(); + + MicroserviceCacheStatus getStatus(); + + void refresh(); + + void forceRefresh(); + + enum MicroserviceCacheStatus { + /** + * init status, not pull instances from sc yet + */ + INIT, + /** + * unknown error + */ + UNKNOWN_ERROR, + /** + * error occurs while getting access to service center + */ + CLIENT_ERROR, + /** + * success to query the service center, but no target microservice found + */ + SERVICE_NOT_FOUND, + /** + * success to query the service center, but the target microservice instance list is not changed + */ + NO_CHANGE, + /** + * success to query the service center, and the target microservice instance list is changed. + * the cached instance list gets refreshed successfully. + */ + REFRESHED, + /** + * unknown error occurs while setting the pulled instances into this cache + */ + SETTING_CACHE_ERROR + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKey.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKey.java new file mode 100644 index 00000000000..103df5ac9a1 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKey.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.Objects; + +import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; +import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser; + +public class MicroserviceCacheKey { + private String env; + + private String appId; + + private String serviceName; + + private static final String VERSION_RULE = DefinitionConst.VERSION_RULE_ALL; + + public static MicroserviceCacheKeyBuilder builder() { + return new MicroserviceCacheKeyBuilder(); + } + + MicroserviceCacheKey() { + } + + public void validate() { + Objects.requireNonNull(this.env, "microserviceCacheKey.env is null"); + Objects.requireNonNull(this.appId, "microserviceCacheKey.appId is null"); + Objects.requireNonNull(this.serviceName, "microserviceCacheKey.serviceName is null"); + } + + public String getEnv() { + return env; + } + + public String getAppId() { + return appId; + } + + public String getServiceName() { + return serviceName; + } + + public String getVersionRule() { + return VERSION_RULE; + } + + public String plainKey() { + return serviceName + "@" + appId + "@" + env; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MicroserviceCacheKey that = (MicroserviceCacheKey) o; + return Objects.equals(env, that.env) && + Objects.equals(appId, that.appId) && + Objects.equals(serviceName, that.serviceName); + } + + @Override + public int hashCode() { + return Objects.hash(env, appId, serviceName); + } + + @Override + public String toString() { + return plainKey(); + } + + public static class MicroserviceCacheKeyBuilder { + private MicroserviceCacheKey microserviceCacheKey; + + public MicroserviceCacheKey build() { + microserviceCacheKey.validate(); + MicroserviceNameParser microserviceNameParser = + new MicroserviceNameParser(microserviceCacheKey.appId, microserviceCacheKey.serviceName); + microserviceCacheKey.appId = microserviceNameParser.getAppId(); + microserviceCacheKey.serviceName = microserviceNameParser.getShortName(); + return microserviceCacheKey; + } + + public MicroserviceCacheKeyBuilder env(String env) { + microserviceCacheKey.env = env; + return this; + } + + public MicroserviceCacheKeyBuilder appId(String appId) { + microserviceCacheKey.appId = appId; + return this; + } + + public MicroserviceCacheKeyBuilder serviceName(String serviceName) { + microserviceCacheKey.serviceName = serviceName; + return this; + } + + MicroserviceCacheKeyBuilder() { + microserviceCacheKey = new MicroserviceCacheKey(); + } + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheRefreshedEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheRefreshedEvent.java new file mode 100644 index 00000000000..2bfea4775a3 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheRefreshedEvent.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.List; + +public class MicroserviceCacheRefreshedEvent { + private final List microserviceCaches; + + public MicroserviceCacheRefreshedEvent(List microserviceCaches) { + this.microserviceCaches = microserviceCaches; + } + + public List getMicroserviceCaches() { + return microserviceCaches; + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCache.java new file mode 100644 index 00000000000..9a74cf03795 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCache.java @@ -0,0 +1,248 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; +import org.apache.servicecomb.serviceregistry.api.Const; +import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; +import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; +import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; +import org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing; +import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RefreshableMicroserviceCache implements MicroserviceCache { + private static final Logger LOGGER = LoggerFactory.getLogger(RefreshableMicroserviceCache.class); + + MicroserviceCacheKey key; + + List instances = Collections.unmodifiableList(new ArrayList<>()); + + Microservice consumerService; + + String revisionId; + + ServiceRegistryClient srClient; + + boolean safeMode; + + MicroserviceCacheStatus status = MicroserviceCacheStatus.INIT; + + private final Object SET_OPERATION_LOCK = new Object(); + + boolean emptyInstanceProtectionEnabled; + + MicroserviceInstancePing instancePing = SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class); + + RefreshableMicroserviceCache(Microservice consumerService, MicroserviceCacheKey key, ServiceRegistryClient srClient, + boolean emptyInstanceProtectionEnabled) { + this.key = key; + this.consumerService = consumerService; + this.srClient = srClient; + this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled; + } + + @Override + public void refresh() { + safePullInstance(revisionId); + } + + @Override + public void forceRefresh() { + safePullInstance(null); + } + + void safePullInstance(String revisionId) { + try { + pullInstance(revisionId); + } catch (Throwable e) { + LOGGER.error("unknown error occurs while pulling instances", e); + setStatus(MicroserviceCacheStatus.UNKNOWN_ERROR); + } + } + + void pullInstance(String revisionId) { + MicroserviceInstances serviceInstances = pullInstanceFromServiceCenter(revisionId); + + if (serviceInstances == null) { + LOGGER.error("Can not find any instances from service center due to previous errors. service={}/{}/{}", + key.getAppId(), + key.getServiceName(), + key.getVersionRule()); + setStatus(MicroserviceCacheStatus.CLIENT_ERROR); + return; + } + + if (serviceInstances.isMicroserviceNotExist()) { + setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND); + return; + } + + if (!serviceInstances.isNeedRefresh()) { + LOGGER.debug("instances revision is not changed, service={}/{}/{}", key.getAppId(), key.getServiceName(), + key.getVersionRule()); + setStatus(MicroserviceCacheStatus.NO_CHANGE); + return; + } + + List instances = serviceInstances.getInstancesResponse().getInstances(); + LOGGER.info("find instances[{}] from service center success. service={}/{}/{}, old revision={}, new revision={}", + instances.size(), + key.getAppId(), + key.getServiceName(), + key.getVersionRule(), + this.revisionId, + serviceInstances.getRevision()); + for (MicroserviceInstance instance : instances) { + LOGGER.info("service id={}, instance id={}, endpoints={}", + instance.getServiceId(), + instance.getInstanceId(), + instance.getEndpoints()); + } + safeSetInstances(instances, serviceInstances.getRevision()); + } + + MicroserviceInstances pullInstanceFromServiceCenter(String revisionId) { + return srClient.findServiceInstances(consumerService.getServiceId(), + key.getAppId(), key.getServiceName(), key.getVersionRule(), revisionId); + } + + private void safeSetInstances(List pulledInstances, String rev) { + try { + synchronized (SET_OPERATION_LOCK) { + setInstances(pulledInstances, rev); + setStatus(MicroserviceCacheStatus.REFRESHED); + } + } catch (Throwable e) { + setStatus(MicroserviceCacheStatus.SETTING_CACHE_ERROR); + LOGGER.error("Failed to setInstances, appId={}, microserviceName={}.", + key.getAppId(), + key.getServiceName(), + e); + } + } + + private void setInstances(List pulledInstances, String rev) { + Set mergedInstances = mergeInstances(pulledInstances); + LOGGER.debug("actually set instances[{}] for {}", mergedInstances.size(), key.plainKey()); + for (MicroserviceInstance mergedInstance : mergedInstances) { + LOGGER.debug("serviceId={}, instanceId={}, endpoints={}", + mergedInstance.getServiceId(), + mergedInstance.getInstanceId(), + mergedInstance.getEndpoints()); + } + instances = Collections.unmodifiableList(new ArrayList<>(mergedInstances)); + revisionId = rev; + } + + protected Set mergeInstances(List pulledInstances) { + Set mergedInstances = new LinkedHashSet<>(pulledInstances); + + if (safeMode) { + // in safe mode, instances will never be deleted + mergedInstances.addAll(instances); + return mergedInstances; + } + + if (!inEmptyPulledInstancesProtectionSituation(pulledInstances)) { + return mergedInstances; + } + + if (null == instancePing) { + LOGGER.info("no MicroserviceInstancePing implementation loaded, abandon the old instance list"); + return mergedInstances; + } + + instances.forEach(instance -> { + if (!mergedInstances.contains(instance)) { + if (instancePing.ping(instance)) { + mergedInstances.add(instance); + } + } + }); + return mergedInstances; + } + + private boolean inEmptyPulledInstancesProtectionSituation(List pulledInstances) { + return pulledInstances.isEmpty() + && instances != null + && !instances.isEmpty() + && isEmptyInstanceProtectionEnabled(); + } + + @Override + public MicroserviceCacheKey getKey() { + return key; + } + + @Override + public List getInstances() { + return instances; + } + + @Override + public String getRevisionId() { + return revisionId; + } + + @Override + public MicroserviceCacheStatus getStatus() { + return status; + } + + void setStatus(MicroserviceCacheStatus status) { + this.status = status; + } + + boolean isEmptyInstanceProtectionEnabled() { + return emptyInstanceProtectionEnabled; + } + + void setEmptyInstanceProtectionEnabled(boolean emptyInstanceProtectionEnabled) { + this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled; + } + + void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent event) { + if (!microserviceMatched(event)) { + return; + } + refresh(); + } + + void onSafeModeChanged(SafeModeChangeEvent modeChangeEvent) { + this.safeMode = modeChangeEvent.getCurrentMode(); + } + + private boolean microserviceMatched(MicroserviceInstanceChangedEvent event) { + return (key.getAppId().equals(event.getKey().getAppId())) // appId matched + && ( // microserviceName matched + key.getServiceName().equals(event.getKey().getServiceName()) + || key.getServiceName().equals( + event.getKey().getAppId() + Const.APP_SERVICE_SEPARATOR + event.getKey().getServiceName() + )); + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCache.java new file mode 100644 index 00000000000..7bd1a1b0c4a --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCache.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent; +import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Cache the pulled microservice instances. + */ +public class RefreshableServiceRegistryCache implements ServiceRegistryCache { + private static final Logger LOGGER = LoggerFactory.getLogger(RefreshableServiceRegistryCache.class); + + Map microserviceCache = new ConcurrentHashMapEx<>(); + + Microservice consumerService; + + ServiceRegistryClient srClient; + + boolean emptyInstanceProtectionEnabled = false; + + Consumer> cacheRefreshedWatcher; + + ReentrantLock refreshLock = new ReentrantLock(); + + public RefreshableServiceRegistryCache(Microservice consumerService, ServiceRegistryClient srClient) { + this.consumerService = consumerService; + this.srClient = srClient; + } + + public void refreshCache() { + if (!refreshLock.tryLock()) { + LOGGER.info("ignore concurrent refresh request"); + return; + } + + try { + List refreshedCaches = refreshInnerState(false); + notifyWatcher(refreshedCaches); + } catch (Exception e) { + LOGGER.error("failed to refresh caches", e); + } finally { + refreshLock.unlock(); + } + } + + public void forceRefreshCache() { + refreshLock.lock(); + try { + List refreshedCaches = refreshInnerState(true); + notifyWatcher(refreshedCaches); + } catch (Exception e) { + LOGGER.error("failed to refresh caches", e); + } finally { + refreshLock.unlock(); + } + } + + private List refreshInnerState(boolean isForced) { + return microserviceCache.values().stream() + .peek(cache -> { + if (isForced) { + cache.forceRefresh(); + } else { + cache.refresh(); + } + }) + .filter(this::isRefreshedMicroserviceCache) + .peek(this::removeCacheIfServiceNotFound) + .collect(Collectors.toList()); + } + + private boolean isRefreshedMicroserviceCache(MicroserviceCache microserviceCache) { + return MicroserviceCacheStatus.REFRESHED.equals(microserviceCache.getStatus()) + || MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(microserviceCache.getStatus()); + } + + private void notifyWatcher(List refreshedCaches) { + if (refreshedCaches.isEmpty() || null == cacheRefreshedWatcher) { + return; + } + cacheRefreshedWatcher.accept(refreshedCaches); + } + + @Override + public MicroserviceCache findServiceCache(MicroserviceCacheKey microserviceCacheKey) { + microserviceCacheKey.validate(); + RefreshableMicroserviceCache targetCache = microserviceCache + .computeIfAbsent(microserviceCacheKey, pk -> { + RefreshableMicroserviceCache microserviceCache = createMicroserviceCache(microserviceCacheKey); + microserviceCache.refresh(); + return microserviceCache; + }); + removeCacheIfServiceNotFound(targetCache); + return targetCache; + } + + private void removeCacheIfServiceNotFound(MicroserviceCache targetCache) { + if (MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(targetCache.getStatus())) { + microserviceCache.remove(targetCache.getKey()); + LOGGER.info("microserviceCache[{}] got removed", targetCache.getKey()); + } + } + + RefreshableMicroserviceCache createMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) { + return new RefreshableMicroserviceCache( + consumerService, + microserviceCacheKey, + srClient, + emptyInstanceProtectionEnabled); + } + + public RefreshableServiceRegistryCache setEmptyInstanceProtectionEnabled(boolean emptyInstanceProtectionEnabled) { + this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled; + return this; + } + + @Override + public ServiceRegistryCache setCacheRefreshedWatcher( + Consumer> cacheRefreshedWatcher) { + this.cacheRefreshedWatcher = cacheRefreshedWatcher; + return this; + } + + public void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent event) { + List refreshedCaches = + microserviceCache.entrySet().stream() + .peek(cacheEntry -> cacheEntry.getValue().onMicroserviceInstanceChanged(event)) + .filter(cacheEntry -> isRefreshedMicroserviceCache(cacheEntry.getValue())) + .map(Entry::getValue) + .collect(Collectors.toList()); + + notifyWatcher(refreshedCaches); + } + + public void onSafeModeChanged(SafeModeChangeEvent modeChangeEvent) { + for (Entry cacheEntry : microserviceCache.entrySet()) { + cacheEntry.getValue().onSafeModeChanged(modeChangeEvent); + } + } + + @Override + public Map getMicroserviceCaches() { + return Collections.unmodifiableMap(microserviceCache); + } +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/ServiceRegistryCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/ServiceRegistryCache.java new file mode 100644 index 00000000000..fdc27fe02a4 --- /dev/null +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/ServiceRegistryCache.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +public interface ServiceRegistryCache { + MicroserviceCache findServiceCache(MicroserviceCacheKey microserviceCacheKey); + + ServiceRegistryCache setCacheRefreshedWatcher(Consumer> cacheRefreshedWatcher); + + Map getMicroserviceCaches(); +} diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java index d04c23d6e3a..fb07b7e30fc 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java @@ -27,7 +27,7 @@ import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; import org.apache.servicecomb.foundation.common.utils.JvmUtils; import org.apache.servicecomb.foundation.common.utils.ResourceUtil; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser; import org.apache.servicecomb.swagger.SwaggerUtils; @@ -40,15 +40,12 @@ public class SwaggerLoader { private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerLoader.class); - private ServiceRegistry serviceRegistry; - // first key : appId // second key: microservice short name // third key : schemaId private Map>> apps = new ConcurrentHashMapEx<>(); - public SwaggerLoader(ServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; + public SwaggerLoader() { } /** @@ -67,7 +64,7 @@ public SwaggerLoader(ServiceRegistry serviceRegistry) { * @param swaggersLocation eg. "test/schemas", will load all test/schemas/*.yaml */ public void registerSwaggersInLocation(String swaggersLocation) { - String microserviceName = serviceRegistry.getMicroservice().getServiceName(); + String microserviceName = RegistryUtils.getMicroservice().getServiceName(); registerSwaggersInLocation(microserviceName, swaggersLocation); } @@ -93,7 +90,7 @@ public void registerSwaggersInLocation(String microserviceName, String swaggersL } public void registerSwagger(String schemaId, Swagger swagger) { - registerSwagger(serviceRegistry.getMicroservice().getServiceName(), schemaId, swagger); + registerSwagger(RegistryUtils.getMicroservice().getServiceName(), schemaId, swagger); } public void registerSwagger(String microserviceName, String schemaId, String swaggerContent) { @@ -108,7 +105,7 @@ public void registerSwagger(String microserviceName, String schemaId, String swa } public void registerSwagger(String microserviceName, String schemaId, Swagger swagger) { - MicroserviceNameParser parser = new MicroserviceNameParser(serviceRegistry.getAppId(), microserviceName); + MicroserviceNameParser parser = new MicroserviceNameParser(RegistryUtils.getAppId(), microserviceName); registerSwagger(parser.getAppId(), parser.getShortName(), schemaId, swagger); } @@ -160,7 +157,7 @@ Swagger loadFromMemory(String appId, String shortName, String schemaId) { } private Swagger loadFromResource(String appId, String shortName, String schemaId) { - if (appId.equals(serviceRegistry.getAppId())) { + if (appId.equals(RegistryUtils.getAppId())) { Swagger swagger = loadFromResource(String.format("microservices/%s/%s.yaml", shortName, schemaId)); if (swagger != null) { return swagger; @@ -181,7 +178,7 @@ private Swagger loadFromResource(String path) { } private Swagger loadFromRemote(Microservice microservice, String schemaId) { - String schemaContent = serviceRegistry.getServiceRegistryClient() + String schemaContent = RegistryUtils .getAggregatedSchema(microservice.getServiceId(), schemaId); if (schemaContent != null) { LOGGER.info( diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java index 629628d60d1..b7dc2625de2 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java @@ -24,17 +24,19 @@ import java.util.Map; import java.util.stream.Collectors; +import org.apache.servicecomb.foundation.common.event.EventManager; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; -import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; import org.apache.servicecomb.serviceregistry.version.Version; import org.hamcrest.Matchers; import org.junit.Assert; +import com.google.common.eventbus.EventBus; + import mockit.Mock; import mockit.MockUp; @@ -45,14 +47,21 @@ public class MockMicroserviceVersions extends MicroserviceVersions { private List mockedInstances = new ArrayList<>(); public MockMicroserviceVersions() { - super(new AppManager(ServiceRegistryFactory.createLocal()), "appId", "msName"); + super(new AppManager(), "appId", "msName"); - new MockUp(appManager.getServiceRegistry()) { + ServiceRegistry serviceRegistry = new MockUp() { @Mock Microservice getAggregatedRemoteMicroservice(String microserviceId) { return mockedMicroservices.get(microserviceId); } - }; + + @Mock + EventBus getEventBus() { + return EventManager.getEventBus(); + } + }.getMockInstance(); + + RegistryUtils.setServiceRegistry(serviceRegistry); addMock("1.0.0", 2); addMock("2.0.0", 2); diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/RegistryUtilsTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/RegistryUtilsTest.java new file mode 100644 index 00000000000..ab7efc528bd --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/RegistryUtilsTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry; + +import java.util.Collections; + +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.apache.servicecomb.serviceregistry.registry.cache.MockedMicroserviceCache; +import org.junit.Assert; +import org.junit.Test; + +public class RegistryUtilsTest { + @Test + public void convertCacheToMicroserviceInstances() { + MockedMicroserviceCache microserviceCache = new MockedMicroserviceCache(); + microserviceCache.setStatus(MicroserviceCacheStatus.CLIENT_ERROR); + MicroserviceInstances microserviceInstances = RegistryUtils + .convertCacheToMicroserviceInstances(microserviceCache); + Assert.assertNull(microserviceInstances); + + microserviceCache = new MockedMicroserviceCache(); + microserviceCache.setStatus(MicroserviceCacheStatus.SETTING_CACHE_ERROR); + microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache); + Assert.assertNull(microserviceInstances); + + microserviceCache = new MockedMicroserviceCache(); + microserviceCache.setStatus(MicroserviceCacheStatus.INIT); + microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache); + Assert.assertNull(microserviceInstances); + + microserviceCache = new MockedMicroserviceCache(); + microserviceCache.setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND); + microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache); + Assert.assertTrue(microserviceInstances.isMicroserviceNotExist()); + Assert.assertFalse(microserviceInstances.isNeedRefresh()); + Assert.assertEquals("", microserviceInstances.getRevision()); + Assert.assertNull(microserviceInstances.getInstancesResponse()); + + microserviceCache = new MockedMicroserviceCache(); + microserviceCache.setStatus(MicroserviceCacheStatus.REFRESHED); + microserviceCache.setRevisionId("0166f3c18702617d5e55cf911e4e412cc8760dab"); + MicroserviceInstance microserviceInstance = new MicroserviceInstance(); + microserviceCache.setInstances(Collections.singletonList(microserviceInstance)); + microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache); + Assert.assertFalse(microserviceInstances.isMicroserviceNotExist()); + Assert.assertTrue(microserviceInstances.isNeedRefresh()); + Assert.assertEquals("0166f3c18702617d5e55cf911e4e412cc8760dab", microserviceInstances.getRevision()); + Assert.assertEquals(1, microserviceInstances.getInstancesResponse().getInstances().size()); + Assert.assertSame(microserviceInstance, microserviceInstances.getInstancesResponse().getInstances().get(0)); + + microserviceCache = new MockedMicroserviceCache(); + microserviceCache.setStatus(MicroserviceCacheStatus.NO_CHANGE); + microserviceCache.setRevisionId("0166f3c18702617d5e55cf911e4e412cc8760dab"); + microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache); + Assert.assertFalse(microserviceInstances.isMicroserviceNotExist()); + Assert.assertFalse(microserviceInstances.isNeedRefresh()); + Assert.assertEquals("0166f3c18702617d5e55cf911e4e412cc8760dab", microserviceInstances.getRevision()); + Assert.assertNull(microserviceInstances.getInstancesResponse()); + } +} \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/ServiceRegistryTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/ServiceRegistryTest.java new file mode 100644 index 00000000000..3477fb6faa2 --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/ServiceRegistryTest.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.regex.Matcher; + +import org.junit.Test; + +public class ServiceRegistryTest { + @Test + public void testNameFormat() { + Matcher matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc"); + assertTrue(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc00"); + assertTrue(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ABC"); + assertTrue(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("A2BC"); + assertTrue(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc-ABC"); + assertTrue(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc_ABC"); + assertTrue(matcher.matches()); + + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher(""); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("-abc"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc-"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("_abc"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc_"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("0abc"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab.c"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab?c"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab#c"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab&c"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab*c"); + assertFalse(matcher.matches()); + matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab@c"); + assertFalse(matcher.matches()); + } +} \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java index 737e47d5f67..0aead31b8c1 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java @@ -71,23 +71,6 @@ public void watchDeleteEvent() { MicroserviceInstanceChangedEvent event = new MicroserviceInstanceChangedEvent(); event.setKey(key); - // not match - key.setAppId(appId + "1"); - key.setServiceName(serviceName + "1"); - eventBus.post(event); - Assert.assertEquals(1, microserviceManager.getVersionsByName().size()); - - key.setAppId(appId + "1"); - key.setServiceName(serviceName); - eventBus.post(event); - Assert.assertEquals(1, microserviceManager.getVersionsByName().size()); - - key.setAppId(appId); - key.setServiceName(serviceName + "1"); - eventBus.post(event); - Assert.assertEquals(1, microserviceManager.getVersionsByName().size()); - - // match key.setAppId(appId); key.setServiceName(serviceName); eventBus.post(event); @@ -109,9 +92,9 @@ public void deleteThenRecovery() { @Test public void deleteWhenCreateMicroserviceVersion() { - new Expectations(appManager.getServiceRegistry()) { + new Expectations(RegistryUtils.getServiceRegistry()) { { - appManager.getServiceRegistry().getAggregatedRemoteMicroservice(serviceId); + RegistryUtils.getServiceRegistry().getAggregatedRemoteMicroservice(serviceId); result = null; } }; diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java index cd6ad0423c3..af713bc5398 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java @@ -22,7 +22,7 @@ import java.net.InetAddress; import java.net.URI; import java.nio.charset.StandardCharsets; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -79,6 +79,7 @@ public void setUp() throws Exception { inMemoryConfig.clear(); } + @SuppressWarnings("deprecation") @Test public void testDelegate() { ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal(); @@ -89,7 +90,6 @@ public void testDelegate() { Assert.assertEquals(serviceRegistry, RegistryUtils.getServiceRegistry()); Assert.assertEquals(serviceRegistry.getServiceRegistryClient(), RegistryUtils.getServiceRegistryClient()); - Assert.assertEquals(serviceRegistry.getInstanceCacheManager(), RegistryUtils.getInstanceCacheManager()); Microservice microservice = RegistryUtils.getMicroservice(); Assert.assertEquals(serviceRegistry.getMicroservice(), microservice); @@ -100,7 +100,7 @@ public void testDelegate() { Assert.assertEquals(RegistryUtils.getMicroservice().getServiceId(), instanceList.get(0).getServiceId()); instanceList = RegistryUtils.findServiceInstance("default", "notExists", "0.0.1"); - Assert.assertEquals(null, instanceList); + Assert.assertNull(instanceList); MicroserviceInstances microserviceInstances = RegistryUtils.findServiceInstances("default", "default", "0.0.1", "0"); @@ -194,7 +194,7 @@ public void testGetRealListenAddress() throws Exception { }; Assert.assertEquals("rest://172.0.0.0:8080", RegistryUtils.getPublishAddress("rest", "172.0.0.0:8080")); - Assert.assertEquals(null, RegistryUtils.getPublishAddress("rest", null)); + Assert.assertNull(RegistryUtils.getPublishAddress("rest", null)); URI uri = new URI(RegistryUtils.getPublishAddress("rest", "0.0.0.0:8080")); Assert.assertEquals("1.1.1.1:8080", uri.getAuthority()); @@ -225,7 +225,7 @@ public String get() { }; } }; - String query = URLEncodedUtils.format(Arrays.asList(new BasicNameValuePair("country", "中 国")), + String query = URLEncodedUtils.format(Collections.singletonList(new BasicNameValuePair("country", "中 国")), StandardCharsets.UTF_8.name()); Assert.assertEquals("rest://1.1.1.1:8080?" + query, RegistryUtils.getPublishAddress("rest", "172.0.0.0:8080?" + query)); diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java index 3a6ac2fb50e..88f63e2a9a9 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java @@ -22,14 +22,15 @@ import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager; -import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory; import org.junit.AfterClass; import org.junit.Before; import com.google.common.eventbus.EventBus; -import mockit.Expectations; +import mockit.Deencapsulation; +import mockit.Mock; +import mockit.MockUp; public class TestRegistryBase { protected ServiceRegistry serviceRegistry; @@ -66,11 +67,12 @@ public void setup() { serviceRegistry = ServiceRegistryFactory.createLocal("registry.yaml"); serviceRegistry.init(); - appManager = serviceRegistry.getAppManager(); + Deencapsulation.setField(RegistryUtils.class, "appManager", new AppManager()); + appManager = RegistryUtils.getAppManager(); microserviceManager = appManager.getOrCreateMicroserviceManager(appId); eventBus = serviceRegistry.getEventBus(); - serviceRegistry.getSwaggerLoader().registerSwagger(appId, serviceName, schemaId, Hello.class); + RegistryUtils.getSwaggerLoader().registerSwagger(appId, serviceName, schemaId, Hello.class); RegistryUtils.setServiceRegistry(serviceRegistry); @@ -86,21 +88,21 @@ public static void classTeardown() { protected void mockNotExist() { MicroserviceInstances microserviceInstances = new MicroserviceInstances(); microserviceInstances.setMicroserviceNotExist(true); - new Expectations(appManager.getServiceRegistry()) { - { - appManager.getServiceRegistry() - .findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, anyString); - result = microserviceInstances; + new MockUp() { + @Mock + MicroserviceInstances findServiceInstances(String appId, String serviceName, + String versionRule, String revision) { + return microserviceInstances; } }; } protected void mockDisconnect() { - new Expectations(appManager.getServiceRegistry()) { - { - appManager.getServiceRegistry() - .findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, anyString); - result = null; + new MockUp() { + @Mock + MicroserviceInstances findServiceInstances(String appId, String serviceName, + String versionRule, String revision) { + return null; } }; } diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java index 85da7fb0541..0e31341f3f5 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java @@ -18,6 +18,7 @@ package org.apache.servicecomb.serviceregistry.cache; import org.apache.servicecomb.serviceregistry.RegistryUtils; +import org.apache.servicecomb.serviceregistry.ServiceRegistry; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; @@ -25,20 +26,25 @@ import org.junit.Test; import mockit.Expectations; +import mockit.Mock; +import mockit.MockUp; import mockit.Mocked; public class TestMicroserviceInstanceCache { @Test - public void testGetOrCreateMicroservice(@Mocked RegistryUtils utils, @Mocked ServiceRegistryClient client, + public void testGetOrCreateMicroservice(@Mocked ServiceRegistry serviceRegistry, + @Mocked ServiceRegistryClient client, @Mocked Microservice microservice) { - new Expectations() { - { - RegistryUtils.getServiceRegistryClient(); - result = client; - client.getAggregatedMicroservice("forkedid"); - result = microservice; - client.getAggregatedMicroservice("forkedidNull"); - result = null; + new MockUp() { + @Mock + Microservice getAggregatedRemoteMicroservice(String microserviceId) { + if ("forkedid".equals(microserviceId)) { + return microservice; + } + if ("forkedidNull".equals(microserviceId)) { + return null; + } + throw new IllegalArgumentException("unrecognized param"); } }; Microservice cachedService = MicroserviceInstanceCache.getOrCreate("forkedid"); @@ -50,11 +56,18 @@ public void testGetOrCreateMicroservice(@Mocked RegistryUtils utils, @Mocked Ser } @Test - public void testGetOrCreateMicroserviceInstance(@Mocked RegistryUtils utils, @Mocked ServiceRegistryClient client, + public void testGetOrCreateMicroserviceInstance(@Mocked ServiceRegistry serviceRegistry, + @Mocked ServiceRegistryClient client, @Mocked MicroserviceInstance instance) { + new MockUp() { + @Mock + ServiceRegistry getServiceRegistry() { + return serviceRegistry; + } + }; new Expectations() { { - RegistryUtils.getServiceRegistryClient(); + serviceRegistry.getServiceRegistryClient(); result = client; client.findServiceInstance("forkedserviceid", "forkedinstanceid"); result = instance; diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java index a1f0f034c21..375f29932ad 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java @@ -17,11 +17,14 @@ package org.apache.servicecomb.serviceregistry.client; +import static org.junit.Assert.fail; + import java.io.InputStream; import java.util.List; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus; import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo; import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse; import org.apache.servicecomb.serviceregistry.client.http.Holder; @@ -196,5 +199,68 @@ public void testLoadSchemaIdsFromRegistryFile() { Assert.assertThat(microservice.getSchemas().size(), Is.is(1)); Assert.assertTrue(microservice.getSchemas().contains("hello")); } + + @SuppressWarnings("deprecation") + @Test + public void undateMicroserviceInstanceStatus() { + List m = registryClient + .findServiceInstance("", "default", "ms2", DefinitionConst.VERSION_RULE_ALL); + MicroserviceInstance instance = m.get(0); + Assert.assertEquals(MicroserviceInstanceStatus.UP, instance.getStatus()); + + boolean updateOperationResult = registryClient + .undateMicroserviceInstanceStatus(instance.getServiceId(), instance.getInstanceId(), "TESTING"); + Assert.assertTrue(updateOperationResult); + + m = registryClient + .findServiceInstance("", "default", "ms2", DefinitionConst.VERSION_RULE_ALL); + instance = m.get(0); + Assert.assertEquals(MicroserviceInstanceStatus.TESTING, instance.getStatus()); + } + + @SuppressWarnings("deprecation") + @Test + public void undateMicroserviceInstanceStatus_instance_not_found() { + try { + registryClient.undateMicroserviceInstanceStatus("msIdNotExist", "", "UP"); + shouldThrowException(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("Invalid serviceId, serviceId=msIdNotExist", e.getMessage()); + } + + try { + registryClient.undateMicroserviceInstanceStatus("002", "instanceIdNotExist", "UP"); + shouldThrowException(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("Invalid argument. microserviceId=002, instanceId=instanceIdNotExist.", + e.getMessage()); + } + } + + @SuppressWarnings("deprecation") + @Test + public void undateMicroserviceInstanceStatus_illegal_status() { + List m = registryClient + .findServiceInstance("", "default", "ms2", DefinitionConst.VERSION_RULE_ALL); + MicroserviceInstance instance = m.get(0); + + try { + registryClient.undateMicroserviceInstanceStatus(instance.getServiceId(), instance.getInstanceId(), null); + shouldThrowException(); + } catch (NullPointerException e) { + Assert.assertEquals("Name is null", e.getMessage()); + } + try { + registryClient + .undateMicroserviceInstanceStatus(instance.getServiceId(), instance.getInstanceId(), "IllegalStatus"); + shouldThrowException(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("Invalid status: IllegalStatus", e.getMessage()); + } + } + + private void shouldThrowException() { + fail("an exception is expected"); + } } diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java index f3a747b063e..595673edb0c 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java @@ -48,16 +48,12 @@ public class TestIpPortManager { AbstractServiceRegistry serviceRegistry; - IpPortManager manager; - @Before public void setup() { ConfigUtil.createLocalConfig(); serviceRegistry = (AbstractServiceRegistry) ServiceRegistryFactory.createLocal(); serviceRegistry.setServiceRegistryClient(srClient); serviceRegistry.init(); - - manager = serviceRegistry.getIpPortManager(); } @Test @@ -79,7 +75,8 @@ public void testGetAvailableAddress(@Injectable ServiceRegistryConfig config, } }; - IpPortManager manager = new IpPortManager(config, cacheManager); + IpPortManager manager = new IpPortManager(config); + manager.instanceCacheManager = cacheManager; IpPort address1 = manager.getAvailableAddress(); if (address1.getPort() == 9980) { diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java index ad72502a162..336a80509dd 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java @@ -28,6 +28,7 @@ import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +@SuppressWarnings("deprecation") public class RestUtilsTest { @Test public void defaultHeadersContainServiceRegistryAndAuthentication() throws Exception { diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java index b58088d72e6..bea5c613627 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java @@ -24,7 +24,6 @@ import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory; -import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; import org.apache.servicecomb.serviceregistry.client.Endpoints; import org.apache.servicecomb.serviceregistry.client.IpPortManager; import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; @@ -63,53 +62,58 @@ Microservice getMicroservice() { public void await() throws InterruptedException { } }; - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { } }; - - new MockUp() { + new MockUp() { @Mock void open(IpPort ipPort, String url, Handler onOpen, Handler onClose, Handler onMessage, Handler onException, Handler onConnectFailed) { } }; + // mock up this two client pool, since this UT case doesn't require the client pool actually boot up. + new MockUp() { + @Mock + void create() { + } + }; + new MockUp() { + @Mock + void create() { + } + }; MicroserviceFactory microserviceFactory = new MicroserviceFactory(); Microservice microservice = microserviceFactory.create("app", "ms"); - ServiceRegistryClientImpl oClient = new ServiceRegistryClientImpl(manager); + ServiceRegistryClientImpl oClient = new ServiceRegistryClientImpl(ServiceRegistryConfig.INSTANCE); oClient.init(); oClient.registerMicroservice(microservice); oClient.registerMicroserviceInstance(microservice.getInstance()); - Assert.assertEquals(null, oClient.getMicroservice(microservice.getServiceId())); - Assert.assertEquals(null, oClient.getMicroserviceInstance("testConsumerID", "testproviderID")); - Assert.assertEquals(null, - oClient.findServiceInstance(microservice.getServiceId(), - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion())); - Assert.assertEquals(null, - oClient.findServiceInstances(microservice.getServiceId(), - microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - "0")); - Assert.assertEquals(null, - oClient.getMicroserviceId(microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment())); - Assert.assertEquals(null, - oClient.heartbeat(microservice.getServiceId(), - microservice.getInstance().getInstanceId())); + Assert.assertNull(oClient.getMicroservice(microservice.getServiceId())); + Assert.assertNull(oClient.getMicroserviceInstance("testConsumerID", "testproviderID")); + Assert.assertNull(oClient.findServiceInstance(microservice.getServiceId(), + microservice.getAppId(), + microservice.getServiceName(), + microservice.getVersion())); + Assert.assertNull(oClient.findServiceInstances(microservice.getServiceId(), + microservice.getAppId(), + microservice.getServiceName(), + microservice.getVersion(), + "0")); + Assert.assertNull(oClient.getMicroserviceId(microservice.getAppId(), + microservice.getServiceName(), + microservice.getVersion(), + microservice.getEnvironment())); + Assert.assertNull(oClient.heartbeat(microservice.getServiceId(), + microservice.getInstance().getInstanceId())); oClient.watch("", Mockito.mock(AsyncResultCallback.class)); - Assert.assertEquals(false, - oClient.unregisterMicroserviceInstance(microservice.getServiceId(), - microservice.getInstance().getInstanceId())); + Assert.assertFalse(oClient.unregisterMicroserviceInstance(microservice.getServiceId(), + microservice.getInstance().getInstanceId())); } @Test @@ -123,12 +127,12 @@ public void testRequestContext() { Assert.assertEquals("//test", oContext.getUri()); Assert.assertEquals(io.vertx.core.http.HttpMethod.POST, oContext.getMethod()); Assert.assertEquals(8080, oContext.getIpPort().getPort()); - Assert.assertEquals(null, oContext.getParams()); + Assert.assertNull(oContext.getParams()); RestResponse oResponse = new RestResponse(null, null); oResponse.setRequestContext(oContext); Assert.assertEquals(oContext, oResponse.getRequestContext()); - Assert.assertEquals(null, oResponse.getResponse()); + Assert.assertNull(oResponse.getResponse()); } @Test @@ -140,24 +144,24 @@ public void testRequestParam() { oParam.addHeader("testKey", "testValue"); oParam.addQueryParam("testParam", "ValueParam"); oParam.addQueryParam("testParam1", "ValueParam"); - Assert.assertEquals(null, oParam.getCookies()); - Assert.assertEquals(null, oParam.getBody()); + Assert.assertNull(oParam.getCookies()); + Assert.assertNull(oParam.getBody()); Assert.assertNotEquals(null, oParam.getHeaders()); Assert.assertNotEquals(null, oParam.getQueryParams()); oParam.setQueryParams(null); Assert.assertEquals("", oParam.getQueryParams()); oParam.setFormFields(null); - Assert.assertEquals(null, oParam.getFormFields()); + Assert.assertNull(oParam.getFormFields()); Endpoints oEndpoints = new Endpoints(); oEndpoints.setInstances(null); oEndpoints.setVersion("1.0"); - Assert.assertEquals(null, oEndpoints.getInstances()); + Assert.assertNull(oEndpoints.getInstances()); Assert.assertEquals("1.0", oEndpoints.getVersion()); } @Test - public void testIpPortManager(@Mocked InstanceCacheManager instanceCacheManager) throws Exception { - IpPortManager oManager = new IpPortManager(ServiceRegistryConfig.INSTANCE, instanceCacheManager); + public void testIpPortManager() { + IpPortManager oManager = new IpPortManager(ServiceRegistryConfig.INSTANCE); IpPort oIPPort = oManager.getNextAvailableAddress(new IpPort("", 33)); Assert.assertEquals(oIPPort.getHostOrIp(), oManager.getAvailableAddress().getHostOrIp()); } diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java index 1947141ec16..4b57d618f4e 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java @@ -46,7 +46,12 @@ public void createHttpClientOptions_proxy() { ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_USERNAME, "user"); ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_PASSWD, "pass"); - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); + HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) { + @Override + public void create() { + } + }.getHttpClientOptionsFromConfigurations( + ServiceRegistryConfig.buildFromConfiguration()); Assert.assertEquals( "{" @@ -63,7 +68,12 @@ public void createHttpClientOptions_proxy() { public void createHttpClientOptions_noProxy() { ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_ENABLE, "false"); - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); + HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) { + @Override + public void create() { + } + }.getHttpClientOptionsFromConfigurations( + ServiceRegistryConfig.buildFromConfiguration()); Assert.assertNull(httpClientOptions.getProxyOptions()); } @@ -72,7 +82,12 @@ public void createHttpClientOptions_noProxy() { public void createHttpClientOptions_http2() { ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name()); - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); + HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) { + @Override + public void create() { + } + }.getHttpClientOptionsFromConfigurations( + ServiceRegistryConfig.buildFromConfiguration()); Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion()); Assert.assertFalse(httpClientOptions.isHttp2ClearTextUpgrade()); @@ -80,7 +95,12 @@ public void createHttpClientOptions_http2() { @Test public void createHttpClientOptions_notHttp2() { - HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions(); + HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) { + @Override + public void create() { + } + }.getHttpClientOptionsFromConfigurations( + ServiceRegistryConfig.buildFromConfiguration()); Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion()); Assert.assertTrue(httpClientOptions.isHttp2ClearTextUpgrade()); diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java index d1c855b7b62..61c179d7ce6 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java @@ -18,6 +18,7 @@ package org.apache.servicecomb.serviceregistry.client.http; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.HashMap; @@ -42,8 +43,8 @@ import org.apache.servicecomb.serviceregistry.api.response.GetSchemasResponse; import org.apache.servicecomb.serviceregistry.api.response.GetServiceResponse; import org.apache.servicecomb.serviceregistry.client.ClientException; -import org.apache.servicecomb.serviceregistry.client.IpPortManager; import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.ResponseWrapper; +import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; import org.junit.After; import org.junit.Assert; @@ -59,7 +60,6 @@ import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpClientResponse; -import io.vertx.core.http.HttpMethod; import io.vertx.core.json.Json; import mockit.Deencapsulation; import mockit.Expectations; @@ -68,22 +68,13 @@ import mockit.Mocked; public class TestServiceRegistryClientImpl { - @Mocked - private IpPortManager ipPortManager; - private ServiceRegistryClientImpl oClient = null; private Microservice microservice = new Microservice(); @Before public void setUp() throws Exception { - oClient = new ServiceRegistryClientImpl(ipPortManager); - - new MockUp() { - @Mock - void httpDo(RequestContext requestContext, Handler responseHandler) { - } - }; + oClient = new ServiceRegistryClientImpl(ServiceRegistryConfig.buildFromConfiguration()); new MockUp() { @Mock @@ -124,25 +115,21 @@ public void testPrivateMethodCreateHttpClientOptions() { public void testException() { MicroserviceFactory microserviceFactory = new MicroserviceFactory(); Microservice microservice = microserviceFactory.create("app", "ms"); - Assert.assertEquals(null, oClient.registerMicroservice(microservice)); - Assert.assertEquals(null, oClient.registerMicroserviceInstance(microservice.getInstance())); + Assert.assertNull(oClient.registerMicroservice(microservice)); + Assert.assertNull(oClient.registerMicroserviceInstance(microservice.getInstance())); oClient.init(); - Assert.assertEquals(null, - oClient.getMicroserviceId(microservice.getAppId(), - microservice.getServiceName(), - microservice.getVersion(), - microservice.getEnvironment())); + Assert.assertNull(oClient.getMicroserviceId(microservice.getAppId(), + microservice.getServiceName(), + microservice.getVersion(), + microservice.getEnvironment())); Assert.assertThat(oClient.getAllMicroservices().isEmpty(), is(true)); - Assert.assertEquals(null, oClient.registerMicroservice(microservice)); - Assert.assertEquals(null, oClient.getMicroservice("microserviceId")); - Assert.assertEquals(null, oClient.getMicroserviceInstance("consumerId", "providerId")); - Assert.assertEquals(false, - oClient.unregisterMicroserviceInstance("microserviceId", "microserviceInstanceId")); - Assert.assertEquals(null, oClient.heartbeat("microserviceId", "microserviceInstanceId")); - Assert.assertEquals(null, - oClient.findServiceInstance("selfMicroserviceId", "appId", "serviceName", "versionRule")); - Assert.assertEquals(null, - oClient.findServiceInstances("selfMicroserviceId", "appId", "serviceName", "versionRule", "0")); + Assert.assertNull(oClient.registerMicroservice(microservice)); + Assert.assertNull(oClient.getMicroservice("microserviceId")); + Assert.assertNull(oClient.getMicroserviceInstance("consumerId", "providerId")); + Assert.assertFalse(oClient.unregisterMicroserviceInstance("microserviceId", "microserviceInstanceId")); + Assert.assertNull(oClient.heartbeat("microserviceId", "microserviceInstanceId")); + Assert.assertNull(oClient.findServiceInstance("selfMicroserviceId", "appId", "serviceName", "versionRule")); + Assert.assertNull(oClient.findServiceInstances("selfMicroserviceId", "appId", "serviceName", "versionRule", "0")); Assert.assertEquals("a", new ClientException("a").getMessage()); } @@ -170,6 +157,14 @@ public void doAppend(LoggingEvent event) { @Test public void testRegisterSchemaNoResponse() { + new MockUp() { + @Mock + void put(IpPort ipPort, String uri, RequestParam requestParam, + Handler responseHandler) { + // do nothing to mock null response + } + }; + new RegisterSchemaTester() { void doRun(java.util.List events) { oClient.registerSchema("msid", "schemaId", "content"); @@ -219,7 +214,7 @@ Handler syncHandlerEx(CountDownLatch countDownLatch, Holder() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { responseHandler.handle(null); @@ -251,7 +246,7 @@ Handler syncHandlerEx(CountDownLatch countDownLatch, Holder() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { responseHandler.handle(null); @@ -307,7 +302,7 @@ public void isSchemaExist() { String microserviceId = "msId"; String schemaId = "schemaId"; - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); @@ -320,18 +315,17 @@ void httpDo(RequestContext requestContext, Handler responseHandler @Test public void getAggregatedMicroservice() { String microserviceId = "msId"; - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - GetServiceResponse serviceResp = Json + holder.value = Json .decodeValue( "{\"service\":{\"serviceId\":\"serviceId\",\"framework\":null" + ",\"registerBy\":null,\"environment\":null,\"appId\":\"appId\",\"serviceName\":null," + "\"alias\":null,\"version\":null,\"description\":null,\"level\":null,\"schemas\":[]," + "\"paths\":[],\"status\":\"UP\",\"properties\":{},\"intance\":null}}", GetServiceResponse.class); - holder.value = serviceResp; RequestParam requestParam = requestContext.getParams(); Assert.assertEquals("global=true", requestParam.getQueryParams()); } @@ -346,16 +340,15 @@ public void getAggregatedSchema() { String microserviceId = "msId"; String schemaId = "schemaId"; - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); - GetSchemaResponse schemasResp = Json + holder.value = Json .decodeValue( "{ \"schema\": \"schema\", \"schemaId\":\"metricsEndpoint\",\"summary\":\"c1188d709631a9038874f9efc6eb894f\"}", GetSchemaResponse.class); - holder.value = schemasResp; RequestParam requestParam = requestContext.getParams(); Assert.assertEquals("global=true", requestParam.getQueryParams()); } @@ -381,7 +374,7 @@ public Map load(String key) { public void getSchemas() { String microserviceId = "msId"; - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); @@ -404,7 +397,7 @@ void httpDo(RequestContext requestContext, Handler responseHandler public void getSchemasForNew() { String microserviceId = "msId"; - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); @@ -427,7 +420,7 @@ void httpDo(RequestContext requestContext, Handler responseHandler public void getSchemasFailed() { String microserviceId = "msId"; - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); @@ -442,7 +435,7 @@ void httpDo(RequestContext requestContext, Handler responseHandler @Test public void testFindServiceInstance() { - new MockUp() { + new MockUp() { @Mock void get(IpPort ipPort, String uri, RequestParam requestParam, Handler responseHandler) { @@ -454,7 +447,7 @@ void get(IpPort ipPort, String uri, RequestParam requestParam, @Test public void findServiceInstance_consumerId_null() { - new MockUp() { + new MockUp() { @Mock void get(IpPort ipPort, String uri, RequestParam requestParam, Handler responseHandler) { @@ -466,7 +459,7 @@ void get(IpPort ipPort, String uri, RequestParam requestParam, } @Test - public void findServiceInstances_microserviceNotExist(@Mocked RequestContext requestContext) { + public void findServiceInstances_microserviceNotExist() { HttpClientResponse response = new MockUp() { @Mock int statusCode() { @@ -480,18 +473,13 @@ HttpClientResponse bodyHandler(Handler bodyHandler) { return null; } }.getMockInstance(); - RestResponse restResponse = new RestResponse(requestContext, response); - new MockUp() { - @Mock - void get(IpPort ipPort, String uri, RequestParam requestParam, - Handler responseHandler) { - Assert.assertEquals("appId=appId&global=true&serviceName=serviceName&version=0.0.0.0%2B", - requestParam.getQueryParams()); - httpDo(RestUtils.createRequestContext(HttpMethod.GET, ipPort, uri, requestParam), responseHandler); - } - + RestResponse restResponse = new RestResponse(null, response); + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { + Assert.assertEquals("appId=appId&global=true&serviceName=serviceName&version=0.0.0.0%2B", + requestContext.getParams().getQueryParams()); + restResponse.setRequestContext(requestContext); responseHandler.handle(restResponse); } }; @@ -511,7 +499,7 @@ public void testGetServiceCenterInfoSuccess() { serviceCenterInfo.setApiVersion("x.x.x"); serviceCenterInfo.setConfig(new ServiceCenterConfig()); - new MockUp() { + new MockUp() { @Mock void httpDo(RequestContext requestContext, Handler responseHandler) { Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); @@ -545,4 +533,68 @@ void doRun(java.util.List events) { } }.run(); } + + @SuppressWarnings("deprecation") + @Test + public void undateMicroserviceInstanceStatus() { + HttpClientResponse httpClientResponse = new MockUp() { + @Mock + int statusCode() { + return 200; + } + }.getMockInstance(); + new MockUp() { + @Mock + void put(IpPort ipPort, String uri, RequestParam requestParam, Handler responseHandler) { + Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); + holder.value = httpClientResponse; + } + }; + + boolean result = oClient.undateMicroserviceInstanceStatus("svcId", "instanceId", "UP"); + Assert.assertTrue(result); + } + + @SuppressWarnings("deprecation") + @Test + public void undateMicroserviceInstanceStatus_response_failure() { + HttpClientResponse httpClientResponse = new MockUp() { + @Mock + int statusCode() { + return 400; + } + }.getMockInstance(); + new MockUp() { + @Mock + void put(IpPort ipPort, String uri, RequestParam requestParam, Handler responseHandler) { + Holder holder = Deencapsulation.getField(responseHandler, "arg$4"); + holder.value = httpClientResponse; + } + }; + + boolean result = oClient.undateMicroserviceInstanceStatus("svcId", "instanceId", "UP"); + Assert.assertFalse(result); + } + + @SuppressWarnings("deprecation") + @Test + public void undateMicroserviceInstanceStatus_illegal_status() { + try { + oClient.undateMicroserviceInstanceStatus("svcId", "instanceId", null); + shouldThrowException(); + } catch (NullPointerException e) { + Assert.assertEquals("Name is null", e.getMessage()); + } + try { + oClient + .undateMicroserviceInstanceStatus("svcId", "instanceId", "IllegalStatus"); + shouldThrowException(); + } catch (IllegalArgumentException e) { + Assert.assertEquals("Invalid status: IllegalStatus", e.getMessage()); + } + } + + private void shouldThrowException() { + fail("an exception is expected"); + } } diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java index 1badce34f6b..93c0453e8a2 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.serviceregistry.client.http; import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; +import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -40,7 +41,12 @@ public void teardown() { public void createHttpClientOptions_http2() { ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name()); - HttpClientOptions httpClientOptions = WebsocketClientPool.INSTANCE.createHttpClientOptions(); + HttpClientOptions httpClientOptions = new WebsocketClientPool(ServiceRegistryConfig.buildFromConfiguration()) { + @Override + public void create() { + } + }.getHttpClientOptionsFromConfigurations( + ServiceRegistryConfig.buildFromConfiguration()); Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion()); Assert.assertFalse(httpClientOptions.isHttp2ClearTextUpgrade()); @@ -48,7 +54,12 @@ public void createHttpClientOptions_http2() { @Test public void createHttpClientOptions_notHttp2() { - HttpClientOptions httpClientOptions = WebsocketClientPool.INSTANCE.createHttpClientOptions(); + HttpClientOptions httpClientOptions = new WebsocketClientPool(ServiceRegistryConfig.buildFromConfiguration()) { + @Override + public void create() { + } + }.getHttpClientOptionsFromConfigurations( + ServiceRegistryConfig.buildFromConfiguration()); Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion()); Assert.assertTrue(httpClientOptions.isHttp2ClearTextUpgrade()); diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java index fc3be5a50a7..f26d337e140 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java @@ -43,7 +43,7 @@ public static void teardownClass() { @Test public void testServiceRegistryConfig() { - ServiceRegistryConfig oConfig = ServiceRegistryConfig.INSTANCE; + ServiceRegistryConfig oConfig = new ServiceRegistryConfigBuilder().build(); Assert.assertNull(oConfig.getAccessKey()); Assert.assertEquals(30000, oConfig.getConnectionTimeout()); Assert.assertNotEquals(null, oConfig.getHeartbeatInterval()); @@ -62,10 +62,10 @@ public void testServiceRegistryConfig() { List ipPorts = oConfig.getIpPort(); Assert.assertEquals("127.0.0.1:80", ipPorts.get(0).toString()); Assert.assertEquals("127.0.0.1:443", ipPorts.get(1).toString()); - Assert.assertFalse(ServiceRegistryConfig.INSTANCE.isProxyEnable()); - Assert.assertEquals("127.0.0.1", ServiceRegistryConfig.INSTANCE.getProxyHost()); - Assert.assertEquals(8080, ServiceRegistryConfig.INSTANCE.getProxyPort()); - Assert.assertNull(ServiceRegistryConfig.INSTANCE.getProxyUsername()); - Assert.assertNull(ServiceRegistryConfig.INSTANCE.getProxyPasswd()); + Assert.assertFalse(oConfig.isProxyEnable()); + Assert.assertEquals("127.0.0.1", oConfig.getProxyHost()); + Assert.assertEquals(8080, oConfig.getProxyPort()); + Assert.assertNull(oConfig.getProxyUsername()); + Assert.assertNull(oConfig.getProxyPasswd()); } } diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java index 66bb06ae77a..cafae798b49 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java @@ -27,6 +27,7 @@ import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; +import org.apache.servicecomb.serviceregistry.consumer.AppManager; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule; import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions; import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; @@ -38,6 +39,7 @@ import org.junit.Test; import io.vertx.core.json.Json; +import mockit.Deencapsulation; import mockit.Mock; import mockit.MockUp; @@ -54,10 +56,12 @@ public class TestInstanceCacheChecker { @Before public void setUp() throws Exception { + Deencapsulation.setField(RegistryUtils.class, "appManager", new AppManager()); + serviceRegistry.init(); RegistryUtils.setServiceRegistry(serviceRegistry); - checker = new InstanceCacheChecker(serviceRegistry.getAppManager()); + checker = new InstanceCacheChecker(RegistryUtils.getAppManager()); checker.clock = new MockClock(new Holder<>(1L)); expectedSummary.setStatus(Status.NORMAL); expectedSummary.setTimestamp(1); @@ -78,7 +82,7 @@ public void check_appManager_empty() { @Test public void check_microserviceManager_empty() { appId = "notExist"; - serviceRegistry.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName); + RegistryUtils.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName); InstanceCacheSummary instanceCacheSummary = checker.check(); Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary)); } @@ -119,7 +123,7 @@ MicroserviceInstances findServiceInstances(String appId, String serviceName, registerMicroservice(appId, microserviceName); - serviceRegistry.getAppManager() + RegistryUtils.getAppManager() .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); findHolder.value = null; @@ -151,7 +155,7 @@ MicroserviceInstances findServiceInstances(String appId, String serviceName, registerMicroservice(appId, microserviceName); - serviceRegistry.getAppManager() + RegistryUtils.getAppManager() .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); findHolder.value.setMicroserviceNotExist(true); @@ -173,7 +177,7 @@ MicroserviceInstances findServiceInstances(String appId, String serviceName, public void check_findInstances_revisionNotMatch() { Holder findHolder = createFindServiceInstancesResult(); - new MockUp(serviceRegistry) { + new MockUp() { @Mock MicroserviceInstances findServiceInstances(String appId, String serviceName, String versionRule, String revision) { @@ -183,7 +187,7 @@ MicroserviceInstances findServiceInstances(String appId, String serviceName, registerMicroservice(appId, microserviceName); - serviceRegistry.getAppManager() + RegistryUtils.getAppManager() .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); findHolder.value.setRevision("second"); @@ -216,7 +220,7 @@ MicroserviceInstances findServiceInstances(String appId, String serviceName, registerMicroservice(appId, microserviceName); - MicroserviceVersions microserviceVersions = serviceRegistry.getAppManager() + MicroserviceVersions microserviceVersions = RegistryUtils.getAppManager() .getOrCreateMicroserviceVersions(appId, microserviceName); microserviceVersions.setRevision("first"); microserviceVersions.getOrCreateMicroserviceVersionRule(DefinitionConst.VERSION_RULE_ALL); @@ -248,7 +252,7 @@ public void check_StaticMicroservice() { Arrays.asList("rest://localhost:8080"), ThirdPartyServiceForUT.class); - MicroserviceVersionRule microserviceVersionRule = serviceRegistry.getAppManager() + MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getAppManager() .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL); Assert.assertEquals(microserviceName, microserviceVersionRule.getLatestMicroserviceVersion().getMicroserviceName()); diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java index 640285810d5..094027091c9 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java @@ -24,7 +24,6 @@ import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.serviceregistry.RegistryUtils; -import org.apache.servicecomb.serviceregistry.ServiceRegistry; import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager; import org.hamcrest.Matchers; import org.junit.Assert; @@ -125,7 +124,7 @@ public void isExpired_no() { Assert.assertFalse(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(0), parent)); } - class DiscoveryFilterForTest implements DiscoveryFilter { + static class DiscoveryFilterForTest implements DiscoveryFilter { protected String groupName; public DiscoveryFilterForTest(String groupName) { @@ -167,13 +166,10 @@ public void filterNormal() { } @Test - public void easyDiscovery(@Mocked ServiceRegistry serviceRegistry, - @Mocked InstanceCacheManager instanceCacheManager) { + public void easyDiscovery(@Mocked InstanceCacheManager instanceCacheManager) { new Expectations(RegistryUtils.class) { { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getInstanceCacheManager(); + RegistryUtils.getInstanceCacheManager(); result = instanceCacheManager; instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString); result = parent; @@ -186,13 +182,10 @@ public void easyDiscovery(@Mocked ServiceRegistry serviceRegistry, } @Test - public void discovery_filterReturnNull(@Mocked ServiceRegistry serviceRegistry, - @Mocked InstanceCacheManager instanceCacheManager) { + public void discovery_filterReturnNull(@Mocked InstanceCacheManager instanceCacheManager) { new Expectations(RegistryUtils.class) { { - RegistryUtils.getServiceRegistry(); - result = serviceRegistry; - serviceRegistry.getInstanceCacheManager(); + RegistryUtils.getInstanceCacheManager(); result = instanceCacheManager; instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString); result = parent; diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/EmptyMockServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/EmptyMockServiceRegistry.java new file mode 100644 index 00000000000..d14532e04ba --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/EmptyMockServiceRegistry.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.servicecomb.serviceregistry.Features; +import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; +import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey; + +import com.google.common.eventbus.EventBus; + +public class EmptyMockServiceRegistry implements ServiceRegistry { + @Override + public String getName() { + return null; + } + + @Override + public void init() { + + } + + @Override + public void run() { + + } + + @Override + public void destroy() { + + } + + @Override + public EventBus getEventBus() { + return null; + } + + @Override + public Set getCombinedMicroserviceNames() { + return null; + } + + @Override + public String getAppId() { + return null; + } + + @Override + public Microservice getMicroservice() { + return null; + } + + @Override + public MicroserviceInstance getMicroserviceInstance() { + return null; + } + + @Override + public ServiceRegistryClient getServiceRegistryClient() { + return null; + } + + @Override + public List findServiceInstance(String appId, String microserviceName, + String microserviceVersionRule) { + return null; + } + + @Override + public MicroserviceInstances findServiceInstances(String appId, String microserviceName, + String microserviceVersionRule, String revision) { + return null; + } + + @Override + public MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) { + return null; + } + + @Override + public boolean updateMicroserviceProperties(Map properties) { + return false; + } + + @Override + public boolean updateInstanceProperties(Map instanceProperties) { + return false; + } + + @Override + public Microservice getRemoteMicroservice(String microserviceId) { + return null; + } + + @Override + public Microservice getAggregatedRemoteMicroservice(String microserviceId) { + return null; + } + + @Override + public Features getFeatures() { + return null; + } + + @Override + public void registerMicroserviceMapping(String microserviceName, String version, List instances, + Class schemaIntfCls) { + + } + + @Override + public void registerMicroserviceMappingByEndpoints(String microserviceName, String version, List endpoints, + Class schemaIntfCls) { + + } +} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java index d82fc75459f..b562c29b34c 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java @@ -78,18 +78,12 @@ void init(RemoteServiceRegistry remoteServiceRegistry) { { definition.getConfiguration(); result = ConfigUtil.createLocalConfig(); - config.getIpPort(); - result = ipPortList; - config.getTransport(); - result = "rest"; - config.isRegistryAutoDiscovery(); - result = true; config.getHeartbeatInterval(); result = 30; config.getInstancePullInterval(); result = 30; - config.isWatch(); - result = false; + config.getRegistryName(); + result = "TestRegistry"; SPIServiceUtils.getOrLoadSortedService(ServiceRegistryTaskInitializer.class); result = Arrays.asList(initializer); } diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java index 07f7e08f2ab..77e8aa4deff 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java @@ -30,7 +30,6 @@ import com.google.common.eventbus.EventBus; -import mockit.Deencapsulation; import mockit.Mocked; /** @@ -52,20 +51,17 @@ public void testGetRemoteRegistryClient(@Mocked ServiceRegistryClientImpl regist ServiceRegistryClient client = serviceRegistry.getServiceRegistryClient(); Assert.assertTrue(client instanceof ServiceRegistryClientImpl); - serviceRegistry = ServiceRegistryFactory.getOrCreate(eventBus, + serviceRegistry = ServiceRegistryFactory.create(eventBus, serviceRegistryConfig, microserviceDefinition); Assert.assertTrue(serviceRegistry instanceof RemoteServiceRegistry); - Assert.assertEquals(serviceRegistry, ServiceRegistryFactory.getServiceRegistry()); - - Deencapsulation.setField(ServiceRegistryFactory.class, "serviceRegistry", null); System.setProperty("local.registry.file", "/tmp/test.yaml"); serviceRegistry = ServiceRegistryFactory.create(eventBus, serviceRegistryConfig, microserviceDefinition); serviceRegistry.init(); client = serviceRegistry.getServiceRegistryClient(); Assert.assertTrue(client instanceof LocalServiceRegistryClientImpl); - Assert.assertTrue(ServiceRegistryFactory.getOrCreate(eventBus, + Assert.assertTrue(ServiceRegistryFactory.create(eventBus, serviceRegistryConfig, microserviceDefinition) instanceof LocalServiceRegistry); System.clearProperty("local.registry.file"); diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCacheTest.java new file mode 100644 index 00000000000..9de57c80ec5 --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCacheTest.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.serviceregistry.ServiceRegistry; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.registry.EmptyMockServiceRegistry; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.junit.Assert; +import org.junit.Test; + +public class AggregateMicroserviceCacheTest { + + @Test + public void refresh() { + MicroserviceCacheKey microserviceCacheKey = + MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("production").build(); + + MockMicroserviceCache mockMicroserviceCache0 = new MockMicroserviceCache(microserviceCacheKey, + MicroserviceCacheStatus.NO_CHANGE); + MockMicroserviceCache mockMicroserviceCache2 = new MockMicroserviceCache(microserviceCacheKey, + MicroserviceCacheStatus.REFRESHED); + mockMicroserviceCache2.instances = Arrays.asList(new MicroserviceInstance(), new MicroserviceInstance()); + MockMicroserviceCache mockMicroserviceCache3 = new MockMicroserviceCache(microserviceCacheKey, + MicroserviceCacheStatus.SERVICE_NOT_FOUND); + + MockServiceRegistry mockServiceRegistry0 = new MockServiceRegistry().setName("s0") + .addCache(mockMicroserviceCache0) + .addCache(new MockMicroserviceCache( + MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("production").build(), + MicroserviceCacheStatus.REFRESHED)); + MockServiceRegistry mockServiceRegistry1 = new MockServiceRegistry().setName("s1"); + MockServiceRegistry mockServiceRegistry2 = new MockServiceRegistry().setName("s2") + .addCache(mockMicroserviceCache2); + MockServiceRegistry mockServiceRegistry3 = new MockServiceRegistry().setName("s3") + .addCache(mockMicroserviceCache3); + + List serviceRegistries = Arrays.asList( + mockServiceRegistry0, + mockServiceRegistry1, + mockServiceRegistry2, + mockServiceRegistry3 + ); + + AggregateMicroserviceCache compositeMicroserviceCache = new AggregateMicroserviceCache( + microserviceCacheKey, + serviceRegistries); + + // Test initialization + // key + Assert.assertSame(microserviceCacheKey, compositeMicroserviceCache.getKey()); + // status + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, compositeMicroserviceCache.getStatus()); + // revision + Assert.assertEquals("1", compositeMicroserviceCache.getRevisionId()); + Assert.assertEquals(1L, compositeMicroserviceCache.revisionCounter.get()); + // MicroserviceCache map + Assert.assertEquals(2, compositeMicroserviceCache.caches.size()); + Assert.assertSame(mockMicroserviceCache0, compositeMicroserviceCache.caches.get("s0")); + Assert.assertSame(mockMicroserviceCache2, compositeMicroserviceCache.caches.get("s2")); + // ServiceRegistry collection + Assert.assertEquals(serviceRegistries.size(), compositeMicroserviceCache.serviceRegistries.size()); + Iterator serviceRegistryIterator = compositeMicroserviceCache.serviceRegistries.iterator(); + Assert.assertSame(serviceRegistries.get(0), serviceRegistryIterator.next()); + Assert.assertSame(serviceRegistries.get(1), serviceRegistryIterator.next()); + Assert.assertSame(serviceRegistries.get(2), serviceRegistryIterator.next()); + Assert.assertSame(serviceRegistries.get(3), serviceRegistryIterator.next()); + // cached instances + Assert.assertEquals(2, compositeMicroserviceCache.getInstances().size()); + Assert.assertSame(mockMicroserviceCache2.instances.get(0), compositeMicroserviceCache.getInstances().get(0)); + Assert.assertSame(mockMicroserviceCache2.instances.get(1), compositeMicroserviceCache.getInstances().get(1)); + + // Test refresh() + mockMicroserviceCache0.instances = Collections.singletonList(new MicroserviceInstance()); + mockMicroserviceCache2.instances = Collections.singletonList(new MicroserviceInstance()); + compositeMicroserviceCache.refresh(); + // status + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, compositeMicroserviceCache.getStatus()); + // revision + Assert.assertEquals("2", compositeMicroserviceCache.getRevisionId()); + Assert.assertEquals(2L, compositeMicroserviceCache.revisionCounter.get()); + // cached instances + Assert.assertEquals(2, compositeMicroserviceCache.getInstances().size()); + Assert.assertSame(mockMicroserviceCache0.instances.get(0), compositeMicroserviceCache.getInstances().get(0)); + Assert.assertSame(mockMicroserviceCache2.instances.get(0), compositeMicroserviceCache.getInstances().get(1)); + + // Test refresh() + // microservice deleted and registered + mockMicroserviceCache0.status = MicroserviceCacheStatus.SERVICE_NOT_FOUND; + mockMicroserviceCache3.status = MicroserviceCacheStatus.REFRESHED; + compositeMicroserviceCache.refresh(); + // status + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, compositeMicroserviceCache.getStatus()); + // revision + Assert.assertEquals("3", compositeMicroserviceCache.getRevisionId()); + Assert.assertEquals(3L, compositeMicroserviceCache.revisionCounter.get()); + // ServiceRegistries + Assert.assertNotNull(compositeMicroserviceCache.caches.get("s2")); + Assert.assertNotNull(compositeMicroserviceCache.caches.get("s3")); + // cached instances + Assert.assertEquals(1, compositeMicroserviceCache.getInstances().size()); + Assert.assertSame(mockMicroserviceCache2.instances.get(0), compositeMicroserviceCache.getInstances().get(0)); + } + + public static class MockServiceRegistry extends EmptyMockServiceRegistry { + String name; + + Map cacheMap = new HashMap<>(); + + public MockServiceRegistry setName(String name) { + this.name = name; + return this; + } + + public MockServiceRegistry addCache(MicroserviceCache microserviceCache) { + cacheMap.put(microserviceCache.getKey(), microserviceCache); + return this; + } + + @Override + public String getName() { + return name; + } + + @Override + public MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) { + return cacheMap.get(microserviceCacheKey); + } + } + + public static class MockMicroserviceCache extends RefreshableMicroserviceCache { + public MockMicroserviceCache(MicroserviceCacheKey key, MicroserviceCacheStatus microserviceCacheStatus) { + super(null, key, null, false); + setStatus(microserviceCacheStatus); + } + } +} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCacheTest.java new file mode 100644 index 00000000000..3ce08f5dd60 --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCacheTest.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +import org.apache.servicecomb.serviceregistry.registry.cache.AggregateMicroserviceCacheTest.MockMicroserviceCache; +import org.apache.servicecomb.serviceregistry.registry.cache.AggregateMicroserviceCacheTest.MockServiceRegistry; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.junit.Before; +import org.junit.Test; + +public class AggregateServiceRegistryCacheTest { + + private MicroserviceCacheKey microserviceCacheKey; + + private MockServiceRegistry mockServiceRegistry0; + + private MockServiceRegistry mockServiceRegistry1; + + private MockServiceRegistry mockServiceRegistry2; + + private AggregateServiceRegistryCache aggregateServiceRegistryCache; + + @Before + public void before() { + microserviceCacheKey = MicroserviceCacheKey.builder() + .serviceName("svc").appId("app").env("env").build(); + + mockServiceRegistry0 = new MockServiceRegistry() + .setName("s0") + .addCache(new MockMicroserviceCache( + microserviceCacheKey, + MicroserviceCacheStatus.NO_CHANGE)); + mockServiceRegistry1 = new MockServiceRegistry() + .setName("s1") + .addCache(new MockMicroserviceCache( + microserviceCacheKey, + MicroserviceCacheStatus.REFRESHED)) + .addCache(new MockMicroserviceCache( + MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build(), + MicroserviceCacheStatus.NO_CHANGE)); + mockServiceRegistry2 = new MockServiceRegistry() + .setName("s2") + .addCache(new MockMicroserviceCache( + microserviceCacheKey, + MicroserviceCacheStatus.SERVICE_NOT_FOUND)); + + aggregateServiceRegistryCache = new AggregateServiceRegistryCache( + Arrays.asList(mockServiceRegistry0, mockServiceRegistry1, mockServiceRegistry2)); + } + + @Test + public void findServiceCache() { + MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache( + MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build() + ); + + assertTrue(serviceCache instanceof AggregateMicroserviceCache); + AggregateMicroserviceCache aggregateMicroserviceCache = (AggregateMicroserviceCache) serviceCache; + assertEquals(2, aggregateMicroserviceCache.caches.size()); + assertSame(mockServiceRegistry0.findMicroserviceCache(microserviceCacheKey), + aggregateMicroserviceCache.caches.get(mockServiceRegistry0.getName())); + assertSame(mockServiceRegistry1.findMicroserviceCache(microserviceCacheKey), + aggregateMicroserviceCache.caches.get(mockServiceRegistry1.getName())); + // aggregateMicroserviceCache holds the cache of svc + assertEquals(1, aggregateServiceRegistryCache.microserviceCache.size()); + assertNotNull(aggregateServiceRegistryCache.microserviceCache.get(microserviceCacheKey)); + + MicroserviceCache serviceCache2 = aggregateServiceRegistryCache.findServiceCache( + MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build() + ); + + assertTrue(serviceCache2 instanceof AggregateMicroserviceCache); + AggregateMicroserviceCache aggregateMicroserviceCache2 = (AggregateMicroserviceCache) serviceCache2; + assertEquals(1, aggregateMicroserviceCache2.caches.size()); + assertSame( + mockServiceRegistry1.findMicroserviceCache( + MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build()), + aggregateMicroserviceCache2.caches.get(mockServiceRegistry1.getName())); + assertEquals(2, aggregateServiceRegistryCache.microserviceCache.size()); + assertNotNull(aggregateServiceRegistryCache.microserviceCache.get( + MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build() + )); + } + + @Test + public void findServiceCache_not_found() { + MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache( + MicroserviceCacheKey.builder().serviceName("svc-not-exist").appId("app").env("env").build() + ); + + assertTrue(serviceCache instanceof AggregateMicroserviceCache); + assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, serviceCache.getStatus()); + AggregateMicroserviceCache aggregateMicroserviceCache = (AggregateMicroserviceCache) serviceCache; + assertEquals(0, aggregateMicroserviceCache.caches.size()); + assertEquals(3, aggregateMicroserviceCache.serviceRegistries.size()); + // should remove the cache of not existing microservice + assertEquals(0, aggregateServiceRegistryCache.microserviceCache.size()); + } + + @Test + public void onMicroserviceCacheRefreshed() { + MicroserviceCacheKey microserviceCacheKey = + MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build(); + MicroserviceCacheKey microserviceCacheKey2 = + MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build(); + aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent( + Collections.singletonList( + new MockMicroserviceCache( + microserviceCacheKey, + MicroserviceCacheStatus.REFRESHED + ) + ) + )); + + assertTrue(aggregateServiceRegistryCache.microserviceCache.isEmpty()); + + MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache(microserviceCacheKey); + MicroserviceCache serviceCache2 = aggregateServiceRegistryCache.findServiceCache(microserviceCacheKey2); + + assertEquals("1", serviceCache.getRevisionId()); + assertEquals("1", serviceCache2.getRevisionId()); + + aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent( + Collections.singletonList( + new MockMicroserviceCache( + microserviceCacheKey, + MicroserviceCacheStatus.REFRESHED + ) + ) + )); + + assertEquals("2", serviceCache.getRevisionId()); + assertEquals("1", serviceCache2.getRevisionId()); + + // test watcher + ArrayList refreshedCaches = new ArrayList<>(); + aggregateServiceRegistryCache.setCacheRefreshedWatcher(refreshedCaches::addAll); + + aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent( + Arrays.asList( + new MockMicroserviceCache( + microserviceCacheKey, + MicroserviceCacheStatus.REFRESHED + ), + new MockMicroserviceCache( + microserviceCacheKey2, + MicroserviceCacheStatus.REFRESHED + ) + ) + )); + + assertEquals("3", serviceCache.getRevisionId()); + assertEquals("2", serviceCache2.getRevisionId()); + assertEquals(2, refreshedCaches.size()); + assertSame(serviceCache, refreshedCaches.get(0)); + assertSame(serviceCache2, refreshedCaches.get(1)); + + refreshedCaches.clear(); + + // test removing not existing service cache + ((MockMicroserviceCache) mockServiceRegistry0.findMicroserviceCache(microserviceCacheKey)) + .setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND); + ((MockMicroserviceCache) mockServiceRegistry1.findMicroserviceCache(microserviceCacheKey)) + .setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND); + aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent( + Arrays.asList( + new MockMicroserviceCache( + microserviceCacheKey, + MicroserviceCacheStatus.REFRESHED + ), + new MockMicroserviceCache( + microserviceCacheKey2, + MicroserviceCacheStatus.REFRESHED + ) + ) + )); + + assertEquals("4", serviceCache.getRevisionId()); + assertEquals("3", serviceCache2.getRevisionId()); + assertEquals(2, refreshedCaches.size()); + assertSame(serviceCache, refreshedCaches.get(0)); + assertSame(serviceCache2, refreshedCaches.get(1)); + assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, serviceCache.getStatus()); + // not existing service cache removed, only serviceCache2 is left + assertEquals(1, aggregateServiceRegistryCache.microserviceCache.size()); + assertSame(serviceCache2, aggregateServiceRegistryCache.microserviceCache.get(microserviceCacheKey2)); + } +} \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKeyTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKeyTest.java new file mode 100644 index 00000000000..b38f83ebf4f --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKeyTest.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import static org.junit.Assert.fail; + +import org.junit.Assert; +import org.junit.Test; + +public class MicroserviceCacheKeyTest { + + @Test + public void constructors() { + checkConstructorException(null, "appId", "svc", "microserviceCacheKey.env is null"); + checkConstructorException("env", null, "svc", "microserviceCacheKey.appId is null"); + checkConstructorException("env", "appId", null, "microserviceCacheKey.serviceName is null"); + + MicroserviceCacheKey microserviceCacheKey = + MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build(); + Assert.assertEquals("svc", microserviceCacheKey.getServiceName()); + Assert.assertEquals("app", microserviceCacheKey.getAppId()); + Assert.assertEquals("env", microserviceCacheKey.getEnv()); + Assert.assertEquals("svc@app@env", microserviceCacheKey.toString()); + + microserviceCacheKey = + MicroserviceCacheKey.builder().serviceName("app:svc").appId("app").env("env").build(); + Assert.assertEquals("svc", microserviceCacheKey.getServiceName()); + Assert.assertEquals("app", microserviceCacheKey.getAppId()); + Assert.assertEquals("env", microserviceCacheKey.getEnv()); + + microserviceCacheKey = + MicroserviceCacheKey.builder().serviceName("app2:svc").appId("app").env("env").build(); + Assert.assertEquals("svc", microserviceCacheKey.getServiceName()); + Assert.assertEquals("app2", microserviceCacheKey.getAppId()); + Assert.assertEquals("env", microserviceCacheKey.getEnv()); + } + + private void checkConstructorException(String env, String appId, String svc, String expectedMessage) { + try { + MicroserviceCacheKey.builder().env(env).appId(appId).serviceName(svc).build(); + fail("an Exception is expected!"); + } catch (Exception e) { + Assert.assertEquals(expectedMessage, e.getMessage()); + } + } + + @Test + public void equals_and_hashcode() { + MicroserviceCacheKey microserviceCacheKey = + MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(); + MicroserviceCacheKey microserviceCacheKey2 = + MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(); + Assert.assertEquals(microserviceCacheKey, microserviceCacheKey2); + Assert.assertEquals(microserviceCacheKey.hashCode(), microserviceCacheKey2.hashCode()); + + microserviceCacheKey2 = + MicroserviceCacheKey.builder().env("env1").appId("app").serviceName("svc").build(); + Assert.assertNotEquals(microserviceCacheKey, microserviceCacheKey2); + microserviceCacheKey2 = + MicroserviceCacheKey.builder().env("env").appId("app1").serviceName("svc").build(); + Assert.assertNotEquals(microserviceCacheKey, microserviceCacheKey2); + microserviceCacheKey2 = + MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc1").build(); + Assert.assertNotEquals(microserviceCacheKey, microserviceCacheKey2); + } + + @Test + public void plainKey() { + MicroserviceCacheKey microserviceCacheKey = + MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(); + Assert.assertEquals("svc@app@env", microserviceCacheKey.plainKey()); + } +} \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MockedMicroserviceCache.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MockedMicroserviceCache.java new file mode 100644 index 00000000000..4d40731fa19 --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MockedMicroserviceCache.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.List; + +import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; + +public class MockedMicroserviceCache extends RefreshableMicroserviceCache { + public MockedMicroserviceCache() { + super(null, null, null, false); + } + + public MockedMicroserviceCache(Microservice consumerService, MicroserviceCacheKey key, + ServiceRegistryClient srClient, + boolean emptyInstanceProtectionEnabled) { + super(consumerService, key, srClient, emptyInstanceProtectionEnabled); + } + + @Override + public void setStatus(MicroserviceCacheStatus status) { + super.setStatus(status); + } + + public void setInstances(List instances) { + this.instances = instances; + } + + public void setRevisionId(String revisionId) { + this.revisionId = revisionId; + } +} diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCacheTest.java new file mode 100644 index 00000000000..0486e009b67 --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCacheTest.java @@ -0,0 +1,367 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +import org.apache.servicecomb.foundation.common.Holder; +import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; +import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; +import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; +import org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import mockit.Mock; +import mockit.MockUp; + +public class RefreshableMicroserviceCacheTest { + + private Holder> findServiceInstancesOprHolder = new Holder<>(); + + private ServiceRegistryClient srClient; + + private RefreshableMicroserviceCache microserviceCache; + + private List pulledInstances = new ArrayList<>(); + + private Microservice consumerService; + + @Before + public void setUp() throws Exception { + srClient = new MockUp() { + @Mock + MicroserviceInstances findServiceInstances(String consumerId, String appId, String serviceName, + String versionRule, String revision) { + return findServiceInstancesOprHolder.value + .apply(new Object[] {consumerId, appId, serviceName, versionRule, revision}); + } + }.getMockInstance(); + consumerService = new Microservice(); + consumerService.setServiceId("consumerId"); + microserviceCache = new RefreshableMicroserviceCache( + consumerService, + MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(), + srClient, + false); + + findServiceInstancesOprHolder.value = params -> { + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + microserviceInstances.setNeedRefresh(true); + microserviceInstances.setRevision("rev0"); + microserviceInstances.setMicroserviceNotExist(false); + + FindInstancesResponse instancesResponse = new FindInstancesResponse(); + instancesResponse.setInstances(pulledInstances); + microserviceInstances.setInstancesResponse(instancesResponse); + + return microserviceInstances; + }; + } + + @Test + public void forceRefresh() { + MicroserviceInstance microserviceInstance = new MicroserviceInstance(); + microserviceInstance.setInstanceId("instanceId00"); + ArrayList instances = new ArrayList<>(); + instances.add(microserviceInstance); + findServiceInstancesOprHolder.value = params -> { + Assert.assertEquals("consumerId", params[0]); + Assert.assertEquals("app", params[1]); + Assert.assertEquals("svc", params[2]); + Assert.assertEquals("0.0.0.0+", params[3]); + Assert.assertNull(params[4]); + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + microserviceInstances.setNeedRefresh(true); + microserviceInstances.setRevision("rev2"); + microserviceInstances.setMicroserviceNotExist(false); + + FindInstancesResponse instancesResponse = new FindInstancesResponse(); + instancesResponse.setInstances(instances); + + microserviceInstances.setInstancesResponse(instancesResponse); + return microserviceInstances; + }; + + microserviceCache.revisionId = "rev"; + microserviceCache.forceRefresh(); + + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + List cachedInstances = microserviceCache.getInstances(); + Assert.assertEquals(1, cachedInstances.size()); + MicroserviceInstance instance = cachedInstances.iterator().next(); + Assert.assertEquals("instanceId00", instance.getInstanceId()); + Assert.assertEquals("rev2", microserviceCache.getRevisionId()); + } + + @Test + public void refresh() { + ArrayList instances = new ArrayList<>(); + findServiceInstancesOprHolder.value = params -> { + Assert.assertEquals("consumerId", params[0]); + Assert.assertEquals("app", params[1]); + Assert.assertEquals("svc", params[2]); + Assert.assertEquals("0.0.0.0+", params[3]); + Assert.assertNull(params[4]); + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + microserviceInstances.setNeedRefresh(true); + microserviceInstances.setRevision("rev0"); + microserviceInstances.setMicroserviceNotExist(false); + + FindInstancesResponse instancesResponse = new FindInstancesResponse(); + instancesResponse.setInstances(instances); + + microserviceInstances.setInstancesResponse(instancesResponse); + return microserviceInstances; + }; + + // at the beginning, no instances in cache + List cachedInstances = microserviceCache.getInstances(); + Assert.assertEquals(0, cachedInstances.size()); + Assert.assertNull(microserviceCache.getRevisionId()); + + // find 1 instance from sc + MicroserviceInstance microserviceInstance = new MicroserviceInstance(); + instances.add(microserviceInstance); + microserviceInstance.setInstanceId("instanceId00"); + + microserviceCache.refresh(); + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + + cachedInstances = microserviceCache.getInstances(); + Assert.assertEquals(1, cachedInstances.size()); + MicroserviceInstance instance = cachedInstances.iterator().next(); + Assert.assertEquals("instanceId00", instance.getInstanceId()); + Assert.assertEquals("rev0", microserviceCache.getRevisionId()); + + // 2nd time, find 2 instances, one of them is the old instance + MicroserviceInstance microserviceInstance1 = new MicroserviceInstance(); + instances.add(microserviceInstance1); + microserviceInstance1.setInstanceId("instanceId01"); + + findServiceInstancesOprHolder.value = params -> { + Assert.assertEquals("consumerId", params[0]); + Assert.assertEquals("app", params[1]); + Assert.assertEquals("svc", params[2]); + Assert.assertEquals("0.0.0.0+", params[3]); + Assert.assertEquals("rev0", params[4]); + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + microserviceInstances.setNeedRefresh(true); + microserviceInstances.setRevision("rev1"); + microserviceInstances.setMicroserviceNotExist(false); + + FindInstancesResponse instancesResponse = new FindInstancesResponse(); + instancesResponse.setInstances(instances); + + microserviceInstances.setInstancesResponse(instancesResponse); + return microserviceInstances; + }; + + microserviceCache.refresh(); + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + cachedInstances = microserviceCache.getInstances(); + Assert.assertEquals(2, cachedInstances.size()); + Assert.assertEquals("instanceId00", cachedInstances.get(0).getInstanceId()); + Assert.assertEquals("instanceId01", cachedInstances.get(1).getInstanceId()); + } + + @Test + public void refresh_service_error() { + findServiceInstancesOprHolder.value = params -> null; + + List oldInstanceList = microserviceCache.getInstances(); + + microserviceCache.refresh(); + Assert.assertEquals(MicroserviceCacheStatus.CLIENT_ERROR, microserviceCache.getStatus()); + Assert.assertSame(oldInstanceList, microserviceCache.getInstances()); + } + + @Test + public void refresh_service_not_exist() { + findServiceInstancesOprHolder.value = params -> { + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + microserviceInstances.setMicroserviceNotExist(true); + return microserviceInstances; + }; + + List oldInstanceList = microserviceCache.getInstances(); + + microserviceCache.refresh(); + Assert.assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, microserviceCache.getStatus()); + Assert.assertSame(oldInstanceList, microserviceCache.getInstances()); + } + + @Test + public void refresh_service_no_change() { + findServiceInstancesOprHolder.value = params -> { + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + microserviceInstances.setMicroserviceNotExist(false); + microserviceInstances.setNeedRefresh(false); + return microserviceInstances; + }; + + List oldInstanceList = microserviceCache.getInstances(); + + microserviceCache.refresh(); + Assert.assertEquals(MicroserviceCacheStatus.NO_CHANGE, microserviceCache.getStatus()); + Assert.assertSame(oldInstanceList, microserviceCache.getInstances()); + } + + @Test + public void refresh_error_in_setInstances() { + microserviceCache = new RefreshableMicroserviceCache( + consumerService, + MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(), + srClient, + false) { + @Override + protected Set mergeInstances(List pulledInstances) { + throw new IllegalStateException("a mock exception"); + } + }; + + List oldInstanceList = microserviceCache.getInstances(); + Assert.assertEquals(MicroserviceCacheStatus.INIT, microserviceCache.getStatus()); + + microserviceCache.refresh(); + + Assert.assertEquals(MicroserviceCacheStatus.SETTING_CACHE_ERROR, microserviceCache.getStatus()); + List newInstanceList = microserviceCache.getInstances(); + Assert.assertEquals(0, newInstanceList.size()); + Assert.assertSame(oldInstanceList, newInstanceList); + } + + @Test + public void refresh_safe_mode() { + microserviceCache.instances = new ArrayList<>(); + MicroserviceInstance instance0 = new MicroserviceInstance(); + instance0.setInstanceId("instanceId0"); + microserviceCache.instances.add(instance0); + + pulledInstances = new ArrayList<>(); + MicroserviceInstance instance1 = new MicroserviceInstance(); + instance1.setInstanceId("instanceId1"); + pulledInstances.add(instance1); + + microserviceCache.refresh(); + + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + Assert.assertEquals(1, microserviceCache.getInstances().size()); + Assert.assertEquals("instanceId1", microserviceCache.getInstances().get(0).getInstanceId()); + + // enter safe mode + microserviceCache.onSafeModeChanged(new SafeModeChangeEvent(true)); + + pulledInstances = new ArrayList<>(); + MicroserviceInstance instance2 = new MicroserviceInstance(); + instance2.setInstanceId("instanceId2"); + pulledInstances.add(instance2); + + microserviceCache.refresh(); + + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + Assert.assertEquals(2, microserviceCache.getInstances().size()); + Assert.assertEquals("instanceId2", microserviceCache.getInstances().get(0).getInstanceId()); + Assert.assertEquals("instanceId1", microserviceCache.getInstances().get(1).getInstanceId()); + + // exit safe mode + microserviceCache.onSafeModeChanged(new SafeModeChangeEvent(false)); + + pulledInstances = new ArrayList<>(); + MicroserviceInstance instance3 = new MicroserviceInstance(); + instance3.setInstanceId("instanceId3"); + pulledInstances.add(instance3); + + microserviceCache.refresh(); + + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + Assert.assertEquals(1, microserviceCache.getInstances().size()); + Assert.assertEquals("instanceId3", microserviceCache.getInstances().get(0).getInstanceId()); + } + + @Test + public void refresh_empty_instance_protection_disabled() { + microserviceCache.instances = new ArrayList<>(); + MicroserviceInstance instance0 = new MicroserviceInstance(); + instance0.setInstanceId("instanceId0"); + microserviceCache.instances.add(instance0); + + pulledInstances = new ArrayList<>(); + microserviceCache.refresh(); + + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + Assert.assertEquals(0, microserviceCache.getInstances().size()); + } + + @Test + public void refresh_empty_instance_protection_enabled() { + microserviceCache.setEmptyInstanceProtectionEnabled(true); + microserviceCache.instancePing = new MicroserviceInstancePing() { + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean ping(MicroserviceInstance instance) { + return true; + } + }; + microserviceCache.instances = new ArrayList<>(); + MicroserviceInstance instance0 = new MicroserviceInstance(); + instance0.setInstanceId("instanceId0"); + microserviceCache.instances.add(instance0); + + pulledInstances = new ArrayList<>(); + microserviceCache.refresh(); + + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + Assert.assertEquals(1, microserviceCache.getInstances().size()); + Assert.assertEquals("instanceId0", microserviceCache.getInstances().get(0).getInstanceId()); + } + + @Test + public void set_consumer_service_id() { + Holder assertCounter = new Holder<>(0); + Function preservedLogic = findServiceInstancesOprHolder.value; + findServiceInstancesOprHolder.value = params -> { + Assert.assertEquals("consumerId", params[0]); + assertCounter.value++; + return preservedLogic.apply(params); + }; + microserviceCache.refresh(); + + consumerService.setServiceId("consumerId2"); + + findServiceInstancesOprHolder.value = params -> { + Assert.assertEquals("consumerId2", params[0]); + assertCounter.value++; + return preservedLogic.apply(params); + }; + microserviceCache.refresh(); + Assert.assertEquals(Integer.valueOf(2), assertCounter.value); + } +} \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCacheTest.java new file mode 100644 index 00000000000..af6e9d335d9 --- /dev/null +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCacheTest.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.serviceregistry.registry.cache; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.function.Function; + +import org.apache.servicecomb.foundation.common.Holder; +import org.apache.servicecomb.serviceregistry.api.registry.Microservice; +import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse; +import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances; +import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class RefreshableServiceRegistryCacheTest { + + private Holder> pullInstanceFromServiceCenterLogic = new Holder<>( + rev -> { + MicroserviceInstances microserviceInstances = new MicroserviceInstances(); + microserviceInstances.setMicroserviceNotExist(false); + microserviceInstances.setNeedRefresh(true); + microserviceInstances.setRevision(rev); + FindInstancesResponse instancesResponse = new FindInstancesResponse(); + instancesResponse.setInstances(new ArrayList<>()); + microserviceInstances.setInstancesResponse(instancesResponse); + return microserviceInstances; + } + ); + + private RefreshableServiceRegistryCache serviceRegistryCache; + + private Microservice consumerService; + + @Before + public void setUp() throws Exception { + serviceRegistryCache = new RefreshableServiceRegistryCache(consumerService, null) { + @Override + RefreshableMicroserviceCache createMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) { + return new RefreshableMicroserviceCache(consumerService, microserviceCacheKey, null, false) { + @Override + MicroserviceInstances pullInstanceFromServiceCenter(String revisionId) { + return pullInstanceFromServiceCenterLogic.value.apply(revisionId); + } + }; + } + }; + consumerService = new Microservice(); + consumerService.setServiceId("testConsumer"); + } + + @Test + public void find_service_instances() { + MicroserviceCache microserviceCache = serviceRegistryCache + .findServiceCache(MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build()); + + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus()); + Assert.assertEquals(0, microserviceCache.getInstances().size()); + Assert.assertEquals(1, serviceRegistryCache.microserviceCache.size()); + Entry cacheEntry = + serviceRegistryCache.microserviceCache.entrySet().iterator().next(); + Assert.assertEquals(MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build(), + cacheEntry.getKey()); + } + + @Test + public void refreshCache() { + RefreshableMicroserviceCache microserviceCache = new RefreshableMicroserviceCache( + consumerService, + MicroserviceCacheKey.builder().serviceName("svc").appId("appId").env("env").build(), + null, false) { + @Override + public void refresh() { + this.status = MicroserviceCacheStatus.REFRESHED; + } + }; + RefreshableMicroserviceCache microserviceCache2 = new RefreshableMicroserviceCache( + consumerService, + MicroserviceCacheKey.builder().serviceName("svc2").appId("appId").env("env").build(), + null, false); + RefreshableMicroserviceCache microserviceCache3 = new RefreshableMicroserviceCache( + consumerService, + MicroserviceCacheKey.builder().serviceName("svc3").appId("appId").env("env").build(), + null, false) { + @Override + public void refresh() { + this.status = MicroserviceCacheStatus.SERVICE_NOT_FOUND; + } + }; + + serviceRegistryCache.microserviceCache.put(microserviceCache.getKey(), microserviceCache); + serviceRegistryCache.microserviceCache.put(microserviceCache2.getKey(), microserviceCache2); + serviceRegistryCache.microserviceCache.put(microserviceCache3.getKey(), microserviceCache3); + + List refreshedCaches = new ArrayList<>(); + serviceRegistryCache.setCacheRefreshedWatcher(refreshedCaches::addAll); + + serviceRegistryCache.refreshCache(); + + Assert.assertEquals(2, refreshedCaches.size()); + Assert.assertSame(microserviceCache.getKey(), refreshedCaches.get(0).getKey()); + Assert.assertSame(microserviceCache3.getKey(), refreshedCaches.get(1).getKey()); + Assert.assertEquals(2, serviceRegistryCache.microserviceCache.size()); + Assert.assertSame(microserviceCache, serviceRegistryCache.microserviceCache.get(microserviceCache.getKey())); + Assert.assertSame(microserviceCache2, serviceRegistryCache.microserviceCache.get(microserviceCache2.getKey())); + } + + @Test + public void forceRefreshCache() { + RefreshableMicroserviceCache microserviceCache = new RefreshableMicroserviceCache( + consumerService, + MicroserviceCacheKey.builder().serviceName("svc").appId("appId").env("env").build(), + null, false) { + @Override + public void forceRefresh() { + this.status = MicroserviceCacheStatus.REFRESHED; + } + }; + + serviceRegistryCache.microserviceCache.put(microserviceCache.getKey(), microserviceCache); + + List refreshedCaches = new ArrayList<>(); + serviceRegistryCache.setCacheRefreshedWatcher(refreshedCaches::addAll); + + serviceRegistryCache.forceRefreshCache(); + + Assert.assertEquals(1, refreshedCaches.size()); + Assert.assertSame(microserviceCache.getKey(), refreshedCaches.get(0).getKey()); + } + + @Test + public void findServiceCache_normal() { + mockServiceRegistryHolder().value = MicroserviceCacheStatus.REFRESHED; + + MicroserviceCacheKey cacheKey = MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build(); + MicroserviceCache serviceCache = serviceRegistryCache.findServiceCache(cacheKey); + + Assert.assertSame(cacheKey, serviceCache.getKey()); + Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, serviceCache.getStatus()); + Assert.assertEquals(1, serviceRegistryCache.microserviceCache.size()); + Assert.assertSame(serviceCache, serviceRegistryCache.microserviceCache.get(cacheKey)); + } + + @Test + public void findServiceCache_client_error() { + mockServiceRegistryHolder().value = MicroserviceCacheStatus.CLIENT_ERROR; + + MicroserviceCacheKey cacheKey = MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build(); + MicroserviceCache serviceCache = serviceRegistryCache.findServiceCache(cacheKey); + + Assert.assertSame(cacheKey, serviceCache.getKey()); + Assert.assertEquals(MicroserviceCacheStatus.CLIENT_ERROR, serviceCache.getStatus()); + Assert.assertEquals(1, serviceRegistryCache.microserviceCache.size()); + Assert.assertSame(serviceCache, serviceRegistryCache.microserviceCache.get(cacheKey)); + } + + @Test + public void findServiceCache_service_not_found() { + mockServiceRegistryHolder().value = MicroserviceCacheStatus.SERVICE_NOT_FOUND; + + MicroserviceCacheKey cacheKey = MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build(); + MicroserviceCache serviceCache = serviceRegistryCache.findServiceCache(cacheKey); + + Assert.assertSame(cacheKey, serviceCache.getKey()); + Assert.assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, serviceCache.getStatus()); + Assert.assertTrue(serviceRegistryCache.microserviceCache.isEmpty()); + } + + private Holder mockServiceRegistryHolder() { + Holder statusHolder = new Holder<>(); + serviceRegistryCache = new RefreshableServiceRegistryCache(consumerService, null) { + @Override + RefreshableMicroserviceCache createMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) { + return new RefreshableMicroserviceCache( + consumerService, + microserviceCacheKey, + null, false) { + @Override + public void refresh() { + this.status = statusHolder.value; + } + }; + } + }; + return statusHolder; + } +} \ No newline at end of file diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java index e4b8752ae8b..48623f042a4 100644 --- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java +++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java @@ -40,6 +40,7 @@ import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException; import org.apache.servicecomb.foundation.common.utils.JvmUtils; import org.apache.servicecomb.foundation.common.utils.ResourceUtil; +import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.TestRegistryBase; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; import org.apache.servicecomb.swagger.SwaggerUtils; @@ -62,11 +63,11 @@ public class TestSwaggerLoader extends TestRegistryBase { @Test public void registerSwagger() { Swagger swagger = SwaggerGenerator.generate(Hello.class); - serviceRegistry.getSwaggerLoader().registerSwagger("default:ms2", schemaId, swagger); + RegistryUtils.getSwaggerLoader().registerSwagger("default:ms2", schemaId, swagger); Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName) .getVersions().values().iterator().next().getMicroservice(); - Assert.assertSame(swagger, serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId)); + Assert.assertSame(swagger, RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId)); } @Test @@ -79,11 +80,11 @@ public void loadFromRemote() { } }; - serviceRegistry.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId); + RegistryUtils.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId); Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName) .getVersions().values().iterator().next().getMicroservice(); - Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId); + Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId); Assert.assertNotSame(swagger, loadedSwagger); Assert.assertEquals(swagger, loadedSwagger); } @@ -93,11 +94,11 @@ public void loadFromResource_sameApp_dirWithoutApp() { Swagger swagger = SwaggerGenerator.generate(Hello.class); mockLocalResource(swagger, String.format("microservices/%s/%s.yaml", serviceName, schemaId)); - serviceRegistry.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId); + RegistryUtils.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId); Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName) .getVersions().values().iterator().next().getMicroservice(); - Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId); + Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId); Assert.assertNotSame(swagger, loadedSwagger); Assert.assertEquals(swagger, loadedSwagger); } @@ -107,11 +108,11 @@ public void loadFromResource_sameApp_dirWithApp() { Swagger swagger = SwaggerGenerator.generate(Hello.class); mockLocalResource(swagger, String.format("applications/%s/%s/%s.yaml", appId, serviceName, schemaId)); - serviceRegistry.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId); + RegistryUtils.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId); Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName) .getVersions().values().iterator().next().getMicroservice(); - Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId); + Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId); Assert.assertNotSame(swagger, loadedSwagger); Assert.assertEquals(swagger, loadedSwagger); } @@ -127,7 +128,7 @@ public void loadFromResource_diffApp_dirWithoutApp() { expectedException.expect(IllegalStateException.class); expectedException.expectMessage( "no schema in local, and can not get schema from service center, appId=other, microserviceName=ms3, version=1.0, serviceId=003, schemaId=hello."); - serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId); + RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId); } @Test @@ -137,7 +138,7 @@ public void loadFromResource_diffApp_dirWithApp() { Microservice microservice = appManager.getOrCreateMicroserviceVersions("other", "ms3") .getVersions().values().iterator().next().getMicroservice(); - Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId); + Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId); Assert.assertNotSame(swagger, loadedSwagger); Assert.assertEquals(swagger, loadedSwagger); } @@ -195,16 +196,16 @@ String toString(URL url, Charset encoding) { @Test public void should_ignore_not_exist_location_when_register_swagger_in_location() { - Map apps = Deencapsulation.getField(serviceRegistry.getSwaggerLoader(), "apps"); + Map apps = Deencapsulation.getField(RegistryUtils.getSwaggerLoader(), "apps"); apps.clear(); - serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("notExistPath"); + RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("notExistPath"); assertThat(apps).isEmpty(); } @Test public void should_ignore_non_yaml_file_when_register_swagger_in_location() { - serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("swagger-del"); - assertThat(serviceRegistry.getSwaggerLoader().loadFromMemory(appId, serviceName, "other")).isNull(); + RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("swagger-del"); + assertThat(RegistryUtils.getSwaggerLoader().loadFromMemory(appId, serviceName, "other")).isNull(); } @Test @@ -248,12 +249,12 @@ String toString(final URL url, final Charset encoding) { } }; - serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("location"); + RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("location"); } @Test public void should_correct_register_swagger_in_location() { - serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("swagger-del"); - assertThat(serviceRegistry.getSwaggerLoader().loadFromMemory(appId, serviceName, "hello")).isNotNull(); + RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("swagger-del"); + assertThat(RegistryUtils.getSwaggerLoader().loadFromMemory(appId, serviceName, "hello")).isNotNull(); } } diff --git a/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java b/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java index f114439c757..77b0daad048 100644 --- a/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java +++ b/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java @@ -17,14 +17,15 @@ package org.apache.servicecomb.springboot.common; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.servicecomb.foundation.common.cache.VersionedCache; import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; import org.apache.servicecomb.serviceregistry.RegistryUtils; import org.apache.servicecomb.serviceregistry.api.registry.Microservice; -import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient; import org.apache.servicecomb.serviceregistry.definition.DefinitionConst; import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext; import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter; @@ -33,9 +34,10 @@ public abstract class AbstractDiscoveryClient { private Map discoveryTrees = new ConcurrentHashMapEx<>(); - private DiscoveryFilter filter = null; - public AbstractDiscoveryClient(DiscoveryFilter filter){ + private DiscoveryFilter filter; + + public AbstractDiscoveryClient(DiscoveryFilter filter) { this.filter = filter; } @@ -44,7 +46,7 @@ public List doGetInstances(final String serviceId) { context.setInputParameters(serviceId); DiscoveryTree discoveryTree = discoveryTrees.computeIfAbsent(serviceId, key -> { - DiscoveryTree tree = new DiscoveryTree(); + DiscoveryTree tree = new DiscoveryTree(); tree.addFilter(filter); return tree; }); @@ -58,14 +60,14 @@ public List doGetInstances(final String serviceId) { } public List getServices() { - ServiceRegistryClient client = RegistryUtils.getServiceRegistryClient(); - List services = client.getAllMicroservices(); - List serviceIDList = new ArrayList<>(); - if (null != services && !services.isEmpty()) { - for (Microservice service : services) { - serviceIDList.add(service.getServiceName()); + Set uniqueServiceNames = new LinkedHashSet<>(); + RegistryUtils.executeOnEachServiceRegistry(sr -> { + List allMicroservices = sr.getServiceRegistryClient().getAllMicroservices(); + if (null == allMicroservices || allMicroservices.isEmpty()) { + return; } - } - return serviceIDList; + allMicroservices.forEach(ms -> uniqueServiceNames.add(ms.getServiceName())); + }); + return new ArrayList<>(uniqueServiceNames); } }