From a9e0e3c21d4fe628b414603a4f897d216a08eb64 Mon Sep 17 00:00:00 2001 From: Anilople Date: Sun, 2 Oct 2022 21:41:00 +0800 Subject: [PATCH 01/31] feat: support use database as a registry less dependency, config, startup fail, more reliability, --- .../controller/RegistryController.java | 39 +++++ .../application-database-discovery.properties | 20 +++ .../framework/apollo/biz/entity/Registry.java | 136 ++++++++++++++++++ .../biz/registry/DatabaseDiscoveryClient.java | 30 ++++ .../registry/DatabaseDiscoveryClientImpl.java | 127 ++++++++++++++++ .../biz/registry/DatabaseServiceRegistry.java | 33 +++++ .../registry/DatabaseServiceRegistryImpl.java | 46 ++++++ .../apollo/biz/registry/ServiceInstance.java | 52 +++++++ .../ApolloRegistryAutoConfiguration.java | 29 ++++ ...ApolloRegistryClientAutoConfiguration.java | 58 ++++++++ ...lloRegistryDiscoveryAutoConfiguration.java | 60 ++++++++ .../ApolloRegistryClearApplicationRunner.java | 75 ++++++++++ ...ApolloRegistryClientApplicationRunner.java | 100 +++++++++++++ .../ApolloRegistryClientProperties.java | 120 ++++++++++++++++ .../ApolloRegistryDiscoveryProperties.java | 75 ++++++++++ .../apollo/biz/registry/package-info.java | 22 +++ .../biz/repository/RegistryRepository.java | 47 ++++++ .../apollo/biz/service/RegistryService.java | 63 ++++++++ .../main/resources/META-INF/spring.factories | 2 + .../DatabaseDiscoveryClientImplTest.java | 104 ++++++++++++++ ...gistryAutoConfigurationNotEnabledTest.java | 31 ++++ apollo-biz/src/test/resources/sql/clean.sql | 1 + .../controller/HomePageController.java | 9 +- .../service/DatabaseDiscoveryService.java | 64 +++++++++ .../service/DefaultDiscoveryService.java | 9 +- .../application-database-discovery.properties | 27 ++++ scripts/sql/apolloconfigdb.sql | 19 +++ .../v210-v220/apolloconfigdb-v210-v220.sql | 30 ++++ 28 files changed, 1426 insertions(+), 2 deletions(-) create mode 100644 apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java create mode 100644 apollo-adminservice/src/main/resources/application-database-discovery.properties create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Registry.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistry.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryClientAutoConfiguration.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryDiscoveryAutoConfiguration.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClearApplicationRunner.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientApplicationRunner.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientProperties.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/package-info.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/RegistryRepository.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/RegistryService.java create mode 100644 apollo-biz/src/main/resources/META-INF/spring.factories create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfigurationNotEnabledTest.java create mode 100644 apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DatabaseDiscoveryService.java create mode 100644 apollo-configservice/src/main/resources/application-database-discovery.properties create mode 100644 scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java new file mode 100644 index 00000000000..6e363475723 --- /dev/null +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java @@ -0,0 +1,39 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.adminservice.controller; + +import com.ctrip.framework.apollo.biz.entity.Registry; +import com.ctrip.framework.apollo.biz.service.RegistryService; +import java.time.Duration; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/registry") +public class RegistryController { + + @Autowired + private RegistryService registryService; + + @PostMapping("/clear/instances") + public List clearInstances() { + return this.registryService.deleteTimeBefore(Duration.ofMinutes(10)); + } +} diff --git a/apollo-adminservice/src/main/resources/application-database-discovery.properties b/apollo-adminservice/src/main/resources/application-database-discovery.properties new file mode 100644 index 00000000000..96a41080a65 --- /dev/null +++ b/apollo-adminservice/src/main/resources/application-database-discovery.properties @@ -0,0 +1,20 @@ +# +# Copyright 2022 Apollo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +eureka.client.enabled=false + +apollo.registry.client.enabled=true +apollo.registry.client.label=default + diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Registry.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Registry.java new file mode 100644 index 00000000000..221fa893690 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Registry.java @@ -0,0 +1,136 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.entity; + +import com.ctrip.framework.apollo.biz.registry.ServiceInstance; +import java.time.LocalDateTime; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.PrePersist; +import javax.persistence.Table; + +/** + * use database as a registry instead of eureka, zookeeper, consul etc. + *

+ * persist {@link ServiceInstance} + */ +@Entity +@Table(name = "Registry") +public class Registry { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "Id") + private long id; + + @Column(name = "ServiceName", nullable = false) + private String serviceName; + + /** + * @see ServiceInstance#getUri() + */ + @Column(name = "Uri", nullable = false) + private String uri; + + /** + * @see ServiceInstance#getLabel() + */ + @Column(name = "Label", nullable = false) + private String label; + + @Column(name = "DataChange_CreatedTime", nullable = false) + private LocalDateTime dataChangeCreatedTime; + + /** + * modify by heartbeat + */ + @Column(name = "DataChange_LastTime", nullable = false) + private LocalDateTime dataChangeLastModifiedTime; + + @PrePersist + protected void prePersist() { + if (this.dataChangeCreatedTime == null) { + dataChangeCreatedTime = LocalDateTime.now(); + } + if (this.dataChangeLastModifiedTime == null) { + dataChangeLastModifiedTime = dataChangeCreatedTime; + } + } + + @Override + public String toString() { + return "Registry{" + + "id=" + id + + ", serviceName='" + serviceName + '\'' + + ", uri='" + uri + '\'' + + ", label='" + label + '\'' + + ", dataChangeCreatedTime=" + dataChangeCreatedTime + + ", dataChangeLastModifiedTime=" + dataChangeLastModifiedTime + + '}'; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public LocalDateTime getDataChangeCreatedTime() { + return dataChangeCreatedTime; + } + + public void setDataChangeCreatedTime(LocalDateTime dataChangeCreatedTime) { + this.dataChangeCreatedTime = dataChangeCreatedTime; + } + + public LocalDateTime getDataChangeLastModifiedTime() { + return dataChangeLastModifiedTime; + } + + public void setDataChangeLastModifiedTime(LocalDateTime dataChangeLastModifiedTime) { + this.dataChangeLastModifiedTime = dataChangeLastModifiedTime; + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java new file mode 100644 index 00000000000..9c33ba66b53 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientProperties; +import java.util.List; + +public interface DatabaseDiscoveryClient { + + /** + * find by {@link ApolloRegistryClientProperties#getServiceName()}, + * then filter by label if {@link ApolloRegistryDiscoveryProperties#isFilterByLabel()} is true. + */ + List getInstances(String serviceName); +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java new file mode 100644 index 00000000000..c8faa46e942 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java @@ -0,0 +1,127 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import com.ctrip.framework.apollo.biz.entity.Registry; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientProperties; +import com.ctrip.framework.apollo.biz.service.RegistryService; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DatabaseDiscoveryClientImpl implements DatabaseDiscoveryClient { + + private static final Logger log = LoggerFactory.getLogger(DatabaseDiscoveryClientImpl.class); + + private final RegistryService registryService; + + private final ApolloRegistryDiscoveryProperties discoveryProperties; + + private final ServiceInstance self; + + public DatabaseDiscoveryClientImpl( + RegistryService registryService, + ApolloRegistryDiscoveryProperties discoveryProperties, + ServiceInstance self) { + this.registryService = registryService; + this.discoveryProperties = discoveryProperties; + this.self = self; + } + + /** + * find by {@link ApolloRegistryClientProperties#getServiceName()} + */ + @Override + public List getInstances(String serviceName) { + final List filterByLabel; + { + List all = this.registryService.findByServiceName(serviceName); + if (this.discoveryProperties.isFilterByLabel()) { + filterByLabel = filterByLabel(all, this.self.getLabel()); + } else { + // get all + filterByLabel = all; + } + } + LocalDateTime healthCheckTime = this.registryService.getTimeBeforeSeconds( + this.discoveryProperties.getHealthCheckInterval() + ); + final List filterByHealthCheck = filterByHealthCheck(filterByLabel, healthCheckTime, serviceName); + + // convert + List registrationList = new ArrayList<>(filterByHealthCheck.size()); + for (Registry registry : filterByHealthCheck) { + ApolloRegistryClientProperties registration = convert(registry); + registrationList.add(registration); + } + return registrationList; + } + + static ApolloRegistryClientProperties convert(Registry registry) { + ApolloRegistryClientProperties registration = new ApolloRegistryClientProperties(); + registration.setServiceName(registry.getServiceName()); + registration.setUri(registry.getUri()); + registration.setLabel(registry.getLabel()); + return registration; + } + + static List filterByLabel(List list, String label) { + if (list.isEmpty()) { + return Collections.emptyList(); + } + List listAfterFilter = new ArrayList<>(8); + for (Registry registry : list) { + if (Objects.equals(label, registry.getLabel())) { + listAfterFilter.add(registry); + } + } + return listAfterFilter; + } + + static List filterByHealthCheck( + List list, + LocalDateTime healthCheckTime, + String serviceName + ) { + if (list.isEmpty()) { + return Collections.emptyList(); + } + List listAfterFilter = new ArrayList<>(8); + for (Registry registry : list) { + LocalDateTime lastModifiedTime = registry.getDataChangeLastModifiedTime(); + if (lastModifiedTime.isAfter(healthCheckTime)) { + listAfterFilter.add(registry); + } + } + + if (listAfterFilter.isEmpty()) { + log.error( + "there is no healthy instance of '{}'. And there are {} unhealthy instances", + serviceName, + list.size() + ); + } + + return listAfterFilter; + } + +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistry.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistry.java new file mode 100644 index 00000000000..02c1ef919ff --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistry.java @@ -0,0 +1,33 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +/** + * @see org.springframework.cloud.client.serviceregistry.ServiceRegistry + */ +public interface DatabaseServiceRegistry { + + /** + * register an instance to database + */ + void register(ServiceInstance instance); + + /** + * remove an instance from database + */ + void deregister(ServiceInstance instance); +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java new file mode 100644 index 00000000000..78732e38200 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import com.ctrip.framework.apollo.biz.entity.Registry; +import com.ctrip.framework.apollo.biz.service.RegistryService; + +public class DatabaseServiceRegistryImpl implements DatabaseServiceRegistry { + + private final RegistryService registryService; + + public DatabaseServiceRegistryImpl( + RegistryService registryService) { + this.registryService = registryService; + } + + public void register(ServiceInstance instance) { + Registry registry = new Registry(); + registry.setServiceName(instance.getServiceName()); + registry.setUri(instance.getUri().toString()); + registry.setLabel(instance.getLabel()); + this.registryService.saveIfNotExistByServiceNameAndUri(registry); + } + + public void deregister(ServiceInstance instance) { + Registry registry = new Registry(); + registry.setServiceName(instance.getServiceName()); + registry.setUri(instance.getUri().toString()); + registry.setLabel(instance.getLabel()); + this.registryService.delete(registry); + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java new file mode 100644 index 00000000000..cae5d635d57 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import java.net.URI; + +/** + * @see org.springframework.cloud.client.ServiceInstance + */ +public interface ServiceInstance { + + /** + * @return The service ID as registered. + */ + String getServiceName(); + + /** + * get the uri of a service instance, for example: + *

+ * @return The service URI address. + */ + URI getUri(); + + /** + * Tag a service instance for service discovery. + *

+ * It's a little hard to persist the key / value pair metadata to database, + * so use a string 'label' instead of metadata. + * + * @see org.springframework.cloud.client.ServiceInstance#getMetadata() + * @return The label of the service instance. + */ + String getLabel(); +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java new file mode 100644 index 00000000000..38f3bceb751 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ImportAutoConfiguration(classes = { + ApolloRegistryClientAutoConfiguration.class, + ApolloRegistryDiscoveryAutoConfiguration.class, +}) +public class ApolloRegistryAutoConfiguration { + +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryClientAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryClientAutoConfiguration.java new file mode 100644 index 00000000000..ad693ff749e --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryClientAutoConfiguration.java @@ -0,0 +1,58 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration; + +import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistry; +import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistryImpl; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientApplicationRunner; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientProperties; +import com.ctrip.framework.apollo.biz.repository.RegistryRepository; +import com.ctrip.framework.apollo.biz.service.RegistryService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(prefix = ApolloRegistryClientProperties.PREFIX, value = "enabled") +@EnableConfigurationProperties(ApolloRegistryClientProperties.class) +public class ApolloRegistryClientAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public RegistryService registryService(RegistryRepository repository) { + return new RegistryService(repository); + } + + @Bean + @ConditionalOnMissingBean + public DatabaseServiceRegistry databaseServiceRegistry( + RegistryService registryService + ) { + return new DatabaseServiceRegistryImpl(registryService); + } + + @Bean + @ConditionalOnMissingBean + public ApolloRegistryClientApplicationRunner apolloRegistryClientApplicationRunner( + ApolloRegistryClientProperties registration, + DatabaseServiceRegistry serviceRegistry + ) { + return new ApolloRegistryClientApplicationRunner(registration, serviceRegistry); + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryDiscoveryAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryDiscoveryAutoConfiguration.java new file mode 100644 index 00000000000..13ea6ee06b9 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryDiscoveryAutoConfiguration.java @@ -0,0 +1,60 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration; + +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClient; +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClientImpl; +import com.ctrip.framework.apollo.biz.registry.ServiceInstance; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClearApplicationRunner; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; +import com.ctrip.framework.apollo.biz.service.RegistryService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty( + prefix = ApolloRegistryDiscoveryProperties.PREFIX, + value = "enabled" +) +@EnableConfigurationProperties({ + ApolloRegistryDiscoveryProperties.class, +}) +public class ApolloRegistryDiscoveryAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public DatabaseDiscoveryClient databaseDiscoveryClient( + ApolloRegistryDiscoveryProperties discoveryProperties, + ServiceInstance selfServiceInstance, + RegistryService registryService + ) { + return new DatabaseDiscoveryClientImpl( + registryService, discoveryProperties, selfServiceInstance + ); + } + + @Bean + @ConditionalOnMissingBean + public ApolloRegistryClearApplicationRunner apolloRegistryClearApplicationRunner( + RegistryService registryService + ) { + return new ApolloRegistryClearApplicationRunner(registryService); + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClearApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClearApplicationRunner.java new file mode 100644 index 00000000000..694514efcc6 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClearApplicationRunner.java @@ -0,0 +1,75 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration.support; + +import com.ctrip.framework.apollo.biz.entity.Registry; +import com.ctrip.framework.apollo.biz.service.RegistryService; +import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; + +/** + * clear the unhealthy instances. + */ +public class ApolloRegistryClearApplicationRunner + implements ApplicationRunner { + + private static final Logger log = LoggerFactory.getLogger(ApolloRegistryClearApplicationRunner.class); + + /** + * for {@link #clearUnhealthyInstances()} + */ + private final ScheduledExecutorService instanceClearScheduledExecutorService; + + + private final RegistryService registryService; + + public ApolloRegistryClearApplicationRunner( + RegistryService registryService) { + this.registryService = registryService; + this.instanceClearScheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + ApolloThreadFactory.create("ApolloRegistryServerClearInstances", true) + ); + } + + /** + * clear instance + */ + private void clearUnhealthyInstances() { + try { + List registryListDeleted = + this.registryService.deleteTimeBefore(Duration.ofMinutes(10)); + if (registryListDeleted != null && !registryListDeleted.isEmpty()) { + log.info("clear {} unhealthy instances by scheduled task", registryListDeleted.size()); + } + } catch (Exception e) { + log.error("fail to clear unhealthy instances by scheduled task", e); + } + } + + @Override + public void run(ApplicationArguments args) throws Exception { + this.instanceClearScheduledExecutorService.scheduleAtFixedRate(this::clearUnhealthyInstances, 0, 60, TimeUnit.SECONDS); + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientApplicationRunner.java new file mode 100644 index 00000000000..6663251de4b --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientApplicationRunner.java @@ -0,0 +1,100 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration.support; + +import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistry; +import com.ctrip.framework.apollo.biz.registry.ServiceInstance; +import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.annotation.PreDestroy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; + +public class ApolloRegistryClientApplicationRunner + implements ApplicationRunner { + + private static final Logger log = LoggerFactory + .getLogger(ApolloRegistryClientApplicationRunner.class); + + private final ServiceInstance registration; + + private final DatabaseServiceRegistry serviceRegistry; + + /** + * for {@link #heartbeat()} + */ + private final ScheduledExecutorService heartbeatScheduledExecutorService; + + public ApolloRegistryClientApplicationRunner( + ServiceInstance registration, + DatabaseServiceRegistry serviceRegistry + ) { + this.registration = registration; + this.serviceRegistry = serviceRegistry; + this.heartbeatScheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + ApolloThreadFactory.create("ApolloRegistryClientHeartBeat", true) + ); + } + + @Override + public void run(ApplicationArguments args) throws Exception { + // register + log.info( + "register to database. '{}': uri '{}', label '{}' ", + this.registration.getServiceName(), + this.registration.getUri(), + this.registration.getLabel() + ); + // heartbeat as same as register + this.heartbeatScheduledExecutorService + .scheduleAtFixedRate(this::heartbeat, 0, 10, TimeUnit.SECONDS); + } + + @PreDestroy + private void deregister() { + try { + this.serviceRegistry.deregister(this.registration); + log.info( + "deregister success, '{}' uri '{}', label '{}'", + this.registration.getServiceName(), + this.registration.getUri(), + this.registration.getLabel() + ); + } catch (Exception e) { + log.error( + "deregister fail, '{}' uri '{}', label '{}'", + this.registration.getServiceName(), + this.registration.getUri(), + this.registration.getLabel(), + e + ); + } + } + + private void heartbeat() { + try { + this.serviceRegistry.register(this.registration); + } catch (Exception e) { + log.error("fail to send heartbeat by scheduled task", e); + } + } + +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientProperties.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientProperties.java new file mode 100644 index 00000000000..42110e42a25 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientProperties.java @@ -0,0 +1,120 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration.support; + +import com.ctrip.framework.apollo.biz.registry.ServiceInstance; +import java.net.URI; +import javax.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.core.env.PropertyResolver; + +/** + * config of register. + * + * @see com.ctrip.framework.apollo.core.dto.ServiceDTO + * @see org.springframework.cloud.netflix.eureka.EurekaClientConfigBean + * @see org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean + */ +@ConfigurationProperties(prefix = ApolloRegistryClientProperties.PREFIX) +public class ApolloRegistryClientProperties implements ServiceInstance { + + public static final String PREFIX = "apollo.registry.client"; + + /** + * register self to registry or not + */ + private boolean enabled; + + /** + * @see com.ctrip.framework.apollo.core.ServiceNameConsts#APOLLO_CONFIGSERVICE + * @see com.ctrip.framework.apollo.core.ServiceNameConsts#APOLLO_ADMINSERVICE + */ + private String serviceName; + + /** + * @see ServiceInstance#getUri() + */ + private URI uri; + + /** + * @see ServiceInstance#getLabel() + */ + private String label; + + @Autowired + private PropertyResolver propertyResolver; + + @Autowired + private InetUtils inetUtils; + + /** + * if user doesn't config, then resolve them on the runtime. + */ + @PostConstruct + public void postConstruct() { + if (this.serviceName == null) { + this.serviceName = propertyResolver.getRequiredProperty("spring.application.name"); + } + + if (this.uri == null) { + String host = this.inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + Integer port = propertyResolver.getRequiredProperty("server.port", Integer.class); + String uriString = "http://" + host + ":" + port + "/"; + this.uri = URI.create(uriString); + } + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getServiceName() { + return serviceName; + } + + @Override + public URI getUri() { + return this.uri; + } + + /** + * custom the uri + * @see ServiceInstance#getUri() + */ + public void setUri(String uri) { + this.uri = URI.create(uri); + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + @Override + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java new file mode 100644 index 00000000000..885528b2abe --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java @@ -0,0 +1,75 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration.support; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @see org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties + * @see org.springframework.cloud.consul.ConsulProperties + * @see org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean + */ +@ConfigurationProperties(prefix = ApolloRegistryDiscoveryProperties.PREFIX) +public class ApolloRegistryDiscoveryProperties { + + public static final String PREFIX = "apollo.registry.discovery"; + + /** + * enable discovery of registry or not + */ + private boolean enabled = false; + + /** + * true mean only return instances which have same label as self. + * false mean return all instances without filter by label. + */ + private boolean filterByLabel = true; + + /** + * health check interval. + *

+ * if current time - the last time of instance's heartbeat < healthCheckInterval, + *

+ * then this instance is healthy. + */ + private long healthCheckInterval = 61; + + public boolean isFilterByLabel() { + return filterByLabel; + } + + public void setFilterByLabel(boolean filterByLabel) { + this.filterByLabel = filterByLabel; + } + + public long getHealthCheckInterval() { + return healthCheckInterval; + } + + public void setHealthCheckInterval(long healthCheckInterval) { + this.healthCheckInterval = healthCheckInterval; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/package-info.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/package-info.java new file mode 100644 index 00000000000..7d8257c5f4b --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/** + * Use database as a registry without spring cloud. + *

+ * Maybe drop spring cloud in the feature. + */ +package com.ctrip.framework.apollo.biz.registry; \ No newline at end of file diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/RegistryRepository.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/RegistryRepository.java new file mode 100644 index 00000000000..c4f192ba603 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/RegistryRepository.java @@ -0,0 +1,47 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.repository; + +import com.ctrip.framework.apollo.biz.entity.Registry; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; +import javax.transaction.Transactional; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.PagingAndSortingRepository; + +public interface RegistryRepository extends PagingAndSortingRepository { + + List findByServiceName(String serviceName); + + Registry findByServiceNameAndUri(String serviceName, String uri); + + @Modifying + @Transactional + List deleteByDataChangeLastModifiedTimeLessThan(LocalDateTime localDateTime); + + @Modifying + @Transactional + int deleteByServiceNameAndUri(String serviceName, String uri); + + /** + * use time in database instead of JVM + */ + @Query(value = "SELECT CURRENT_TIMESTAMP", nativeQuery = true) + LocalDateTime currentTimestamp(); +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/RegistryService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/RegistryService.java new file mode 100644 index 00000000000..9b22b8ff4a0 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/RegistryService.java @@ -0,0 +1,63 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.service; + +import com.ctrip.framework.apollo.biz.entity.Registry; +import com.ctrip.framework.apollo.biz.repository.RegistryRepository; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.List; + +public class RegistryService { + + private final RegistryRepository repository; + + public RegistryService(RegistryRepository repository) { + this.repository = repository; + } + + public Registry saveIfNotExistByServiceNameAndUri(Registry registry) { + Registry registrySaved = this.repository.findByServiceNameAndUri(registry.getServiceName(), registry.getUri()); + if (null == registrySaved) { + registrySaved = registry; + } else { + // update + registrySaved.setLabel(registry.getLabel()); + registrySaved.setDataChangeLastModifiedTime(LocalDateTime.now()); + } + return this.repository.save(registrySaved); + } + + public void delete(Registry registry) { + this.repository.deleteByServiceNameAndUri( + registry.getServiceName(), registry.getUri() + ); + } + + public List findByServiceName(String serviceName) { + return this.repository.findByServiceName(serviceName); + } + + public LocalDateTime getTimeBeforeSeconds(long seconds) { + return this.repository.currentTimestamp().minusSeconds(seconds); + } + + public List deleteTimeBefore(Duration duration) { + LocalDateTime time = this.repository.currentTimestamp().minus(duration); + return this.repository.deleteByDataChangeLastModifiedTimeLessThan(time); + } +} diff --git a/apollo-biz/src/main/resources/META-INF/spring.factories b/apollo-biz/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000000..bf60789dce4 --- /dev/null +++ b/apollo-biz/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.ctrip.framework.apollo.biz.registry.configuration.ApolloRegistryAutoConfiguration diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java new file mode 100644 index 00000000000..a885fa4b12a --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java @@ -0,0 +1,104 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyLong; + +import com.ctrip.framework.apollo.biz.entity.Registry; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; +import com.ctrip.framework.apollo.biz.service.RegistryService; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class DatabaseDiscoveryClientImplTest { + + static Registry newRegistry(String serviceName, String uri, String label) { + Registry registry = new Registry(); + registry.setServiceName(serviceName); + registry.setUri(uri); + registry.setLabel(label); + registry.setDataChangeCreatedTime(LocalDateTime.now()); + registry.setDataChangeLastModifiedTime(LocalDateTime.now()); + return registry; + } + + @Test + void getInstancesWithoutLabel() { + final String serviceName = "a-service"; + RegistryService registryService = Mockito.mock(RegistryService.class); + { + List registryList = Arrays.asList( + newRegistry(serviceName, "http://localhost:8081/", "label1"), + newRegistry(serviceName, "http://localhost:8082/", "label2") + ); + Mockito.when(registryService.findByServiceName(serviceName)) + .thenReturn(registryList); + Mockito.when(registryService.getTimeBeforeSeconds(anyLong())) + .thenReturn(LocalDateTime.now().minusMinutes(1)); + } + + ApolloRegistryDiscoveryProperties properties = new ApolloRegistryDiscoveryProperties(); + properties.setFilterByLabel(false); + + DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( + registryService, + properties, + null + ); + + List serviceInstances = discoveryClient.getInstances(serviceName); + assertEquals(2, serviceInstances.size()); + serviceInstances.forEach( + serviceInstance -> assertEquals(serviceName, serviceInstance.getServiceName()) + ); + } + + + @Test + void getInstancesWithLabel() { + final String serviceName = "a-service"; + RegistryService registryService = Mockito.mock(RegistryService.class); + { + List registryList = Arrays.asList( + newRegistry(serviceName, "http://localhost:8081/", "label1"), + newRegistry("b-service", "http://localhost:8082/", "label2"), + newRegistry("c-service", "http://localhost:8082/", "label3") + ); + Mockito.when(registryService.findByServiceName(serviceName)) + .thenReturn(registryList); + Mockito.when(registryService.getTimeBeforeSeconds(anyLong())) + .thenReturn(LocalDateTime.now().minusMinutes(1)); + } + + ServiceInstance serviceInstance = Mockito.mock(ServiceInstance.class); + Mockito.when(serviceInstance.getLabel()).thenReturn("label1"); + DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( + registryService, + new ApolloRegistryDiscoveryProperties(), + serviceInstance + ); + + List serviceInstances = discoveryClient.getInstances(serviceName); + assertEquals(1, serviceInstances.size()); + assertEquals(serviceName, serviceInstances.get(0).getServiceName()); + assertEquals("label1", serviceInstances.get(0).getLabel()); + } +} \ No newline at end of file diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfigurationNotEnabledTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfigurationNotEnabledTest.java new file mode 100644 index 00000000000..a4092f789bf --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfigurationNotEnabledTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = ApolloRegistryAutoConfiguration.class) +class ApolloRegistryAutoConfigurationNotEnabledTest { + + @Test + void load() { + // do nothing + } +} \ No newline at end of file diff --git a/apollo-biz/src/test/resources/sql/clean.sql b/apollo-biz/src/test/resources/sql/clean.sql index 57e3344fdc3..edbb682a2ae 100644 --- a/apollo-biz/src/test/resources/sql/clean.sql +++ b/apollo-biz/src/test/resources/sql/clean.sql @@ -25,3 +25,4 @@ DELETE FROM releasemessage; DELETE FROM releasehistory; DELETE FROM namespacelock; DELETE FROM `commit`; +DELETE FROM `Registry`; diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java index 3b88941a02d..1dbd4dddcf9 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/controller/HomePageController.java @@ -29,7 +29,14 @@ /** * For non-eureka discovery services such as kubernetes and nacos, there is no eureka home page, so we need to add a default one */ -@Profile({"kubernetes", "nacos-discovery", "consul-discovery", "zookeeper-discovery"}) +@Profile({ + "kubernetes", + "nacos-discovery", + "consul-discovery", + "zookeeper-discovery", + "custom-defined-discovery", + "database-discovery", +}) @RestController public class HomePageController { private final DiscoveryService discoveryService; diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DatabaseDiscoveryService.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DatabaseDiscoveryService.java new file mode 100644 index 00000000000..394e1a4b03b --- /dev/null +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DatabaseDiscoveryService.java @@ -0,0 +1,64 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.metaservice.service; + +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClient; +import com.ctrip.framework.apollo.biz.registry.ServiceInstance; +import com.ctrip.framework.apollo.core.dto.ServiceDTO; +import java.util.ArrayList; +import java.util.List; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +/** + * use database as a registry + */ +@Service +@Profile("database-discovery") +public class DatabaseDiscoveryService implements DiscoveryService { + + private final DatabaseDiscoveryClient discoveryClient; + + public DatabaseDiscoveryService( + DatabaseDiscoveryClient discoveryClient) { + this.discoveryClient = discoveryClient; + } + + @Override + public List getServiceInstances(String serviceId) { + List serviceInstanceList = this.discoveryClient.getInstances(serviceId); + return convert(serviceInstanceList); + } + + static List convert(List list) { + List serviceDTOList = new ArrayList<>(list.size()); + for (ServiceInstance serviceInstance : list) { + ServiceDTO serviceDTO = convert(serviceInstance); + serviceDTOList.add(serviceDTO); + } + return serviceDTOList; + } + + static ServiceDTO convert(ServiceInstance serviceInstance) { + ServiceDTO serviceDTO = new ServiceDTO(); + serviceDTO.setAppName(serviceInstance.getServiceName()); + String homePageUrl = serviceInstance.getUri().toString(); + serviceDTO.setInstanceId(homePageUrl); + serviceDTO.setHomepageUrl(homePageUrl); + return serviceDTO; + } +} diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java index ed10ce6b387..73582cfc514 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/metaservice/service/DefaultDiscoveryService.java @@ -33,7 +33,14 @@ * Default discovery service for Eureka */ @Service -@ConditionalOnMissingProfile({"kubernetes", "nacos-discovery", "consul-discovery", "zookeeper-discovery", "custom-defined-discovery"}) +@ConditionalOnMissingProfile({ + "kubernetes", + "nacos-discovery", + "consul-discovery", + "zookeeper-discovery", + "custom-defined-discovery", + "database-discovery", +}) public class DefaultDiscoveryService implements DiscoveryService { private final EurekaClient eurekaClient; diff --git a/apollo-configservice/src/main/resources/application-database-discovery.properties b/apollo-configservice/src/main/resources/application-database-discovery.properties new file mode 100644 index 00000000000..5720ce62573 --- /dev/null +++ b/apollo-configservice/src/main/resources/application-database-discovery.properties @@ -0,0 +1,27 @@ +# +# Copyright 2022 Apollo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apollo.eureka.server.enabled=false +eureka.client.enabled=false + +apollo.registry.client.enabled=true +apollo.registry.client.label=default + +apollo.registry.discovery.enabled=true +# only do discovery with same label or not, +# if set to false, return all service instances without label filter +apollo.registry.discovery.filterByLabel=true +# health check by heartbeat, heartbeat time before 61s ago will be tag as unhealthy +apollo.registry.discovery.healthCheckInterval = 61 diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index 05076dfaf09..20009c70653 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -410,6 +410,25 @@ CREATE TABLE `AccessKey` ( KEY `DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + +# Dump of table registry +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Registry`; + +CREATE TABLE `Registry` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` varchar(64) NOT NULL COMMENT '服务名', + `Uri` varchar(64) NOT NULL COMMENT '服务地址', + `Label` varchar(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`ServiceName`,`Uri`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + + # Config # ------------------------------------------------------------ INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) diff --git a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql new file mode 100644 index 00000000000..1d78d6e543b --- /dev/null +++ b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -0,0 +1,30 @@ +-- +-- Copyright 2022 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +# delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 + +Use ApolloConfigDB; + +CREATE TABLE `Registry` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` varchar(64) NOT NULL COMMENT '服务名', + `Uri` varchar(64) NOT NULL COMMENT '服务地址', + `Label` varchar(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`ServiceName`,`Uri`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; \ No newline at end of file From 46df1c0c965ef59c968254c08c3053d5bbe4e14a Mon Sep 17 00:00:00 2001 From: Anilople Date: Sun, 2 Oct 2022 22:43:59 +0800 Subject: [PATCH 02/31] fix: test fail when missing bean RegistryService --- .../apollo/adminservice/controller/RegistryController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java index 6e363475723..2a3ed0c2df2 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java @@ -21,12 +21,14 @@ import java.time.Duration; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/registry") +@ConditionalOnBean(RegistryService.class) public class RegistryController { @Autowired From 4a06884ddec57428f3832d56f0b63c5b34cbdde5 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:19:43 +0800 Subject: [PATCH 03/31] Delete RegistryController.java --- .../controller/RegistryController.java | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java deleted file mode 100644 index 2a3ed0c2df2..00000000000 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/RegistryController.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2022 Apollo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.ctrip.framework.apollo.adminservice.controller; - -import com.ctrip.framework.apollo.biz.entity.Registry; -import com.ctrip.framework.apollo.biz.service.RegistryService; -import java.time.Duration; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/registry") -@ConditionalOnBean(RegistryService.class) -public class RegistryController { - - @Autowired - private RegistryService registryService; - - @PostMapping("/clear/instances") - public List clearInstances() { - return this.registryService.deleteTimeBefore(Duration.ofMinutes(10)); - } -} From 5615639468c8eab642c829e3a8e7ffd6e62f5a02 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:19:52 +0800 Subject: [PATCH 04/31] feat: add spring.cloud.discovery.enabled=false --- .../src/main/resources/application-database-discovery.properties | 1 + .../src/main/resources/application-database-discovery.properties | 1 + 2 files changed, 2 insertions(+) diff --git a/apollo-adminservice/src/main/resources/application-database-discovery.properties b/apollo-adminservice/src/main/resources/application-database-discovery.properties index 96a41080a65..fe96a2479b8 100644 --- a/apollo-adminservice/src/main/resources/application-database-discovery.properties +++ b/apollo-adminservice/src/main/resources/application-database-discovery.properties @@ -14,6 +14,7 @@ # limitations under the License. # eureka.client.enabled=false +spring.cloud.discovery.enabled=false apollo.registry.client.enabled=true apollo.registry.client.label=default diff --git a/apollo-configservice/src/main/resources/application-database-discovery.properties b/apollo-configservice/src/main/resources/application-database-discovery.properties index 5720ce62573..b824910565a 100644 --- a/apollo-configservice/src/main/resources/application-database-discovery.properties +++ b/apollo-configservice/src/main/resources/application-database-discovery.properties @@ -15,6 +15,7 @@ # apollo.eureka.server.enabled=false eureka.client.enabled=false +spring.cloud.discovery.enabled=false apollo.registry.client.enabled=true apollo.registry.client.label=default From c84a4b5169bde1f1e5aa357683c2484e80279c89 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:21:01 +0800 Subject: [PATCH 05/31] refactor: healthCheckInterval -> healthCheckIntervalInSecond --- .../biz/registry/DatabaseDiscoveryClientImpl.java | 2 +- .../support/ApolloRegistryDiscoveryProperties.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java index c8faa46e942..ceb52b89c89 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java @@ -63,7 +63,7 @@ public List getInstances(String serviceName) { } } LocalDateTime healthCheckTime = this.registryService.getTimeBeforeSeconds( - this.discoveryProperties.getHealthCheckInterval() + this.discoveryProperties.getHealthCheckIntervalInSecond() ); final List filterByHealthCheck = filterByHealthCheck(filterByLabel, healthCheckTime, serviceName); diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java index 885528b2abe..674017222c6 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java @@ -46,7 +46,7 @@ public class ApolloRegistryDiscoveryProperties { *

* then this instance is healthy. */ - private long healthCheckInterval = 61; + private long healthCheckIntervalInSecond = 61; public boolean isFilterByLabel() { return filterByLabel; @@ -56,12 +56,12 @@ public void setFilterByLabel(boolean filterByLabel) { this.filterByLabel = filterByLabel; } - public long getHealthCheckInterval() { - return healthCheckInterval; + public long getHealthCheckIntervalInSecond() { + return healthCheckIntervalInSecond; } - public void setHealthCheckInterval(long healthCheckInterval) { - this.healthCheckInterval = healthCheckInterval; + public void setHealthCheckIntervalInSecond(long healthCheckIntervalInSecond) { + this.healthCheckIntervalInSecond = healthCheckIntervalInSecond; } public boolean isEnabled() { From aa61c4c85af380ba99d92314febd646f13f115b9 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:27:27 +0800 Subject: [PATCH 06/31] fix: 'com.ctrip.framework.apollo.biz.repository.RegistryRepository' that could not be found --- .../ApolloRegistryAutoConfiguration.java | 29 ------------------- .../main/resources/META-INF/spring.factories | 2 -- 2 files changed, 31 deletions(-) delete mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java delete mode 100644 apollo-biz/src/main/resources/META-INF/spring.factories diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java deleted file mode 100644 index 38f3bceb751..00000000000 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2022 Apollo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.ctrip.framework.apollo.biz.registry.configuration; - -import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ImportAutoConfiguration(classes = { - ApolloRegistryClientAutoConfiguration.class, - ApolloRegistryDiscoveryAutoConfiguration.class, -}) -public class ApolloRegistryAutoConfiguration { - -} diff --git a/apollo-biz/src/main/resources/META-INF/spring.factories b/apollo-biz/src/main/resources/META-INF/spring.factories deleted file mode 100644 index bf60789dce4..00000000000 --- a/apollo-biz/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -com.ctrip.framework.apollo.biz.registry.configuration.ApolloRegistryAutoConfiguration From c2be03df4872e2307b2ad80b1ab792e7234d4316 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 20:11:45 +0800 Subject: [PATCH 07/31] refactor: Registry -> ServiceRegistry. change all config prefix to apollo.service --- .../application-database-discovery.properties | 4 +- .../{Registry.java => ServiceRegistry.java} | 20 +++--- .../biz/registry/DatabaseDiscoveryClient.java | 10 +-- .../registry/DatabaseDiscoveryClientImpl.java | 71 +++++++++---------- .../registry/DatabaseServiceRegistryImpl.java | 30 ++++---- .../apollo/biz/registry/ServiceInstance.java | 12 ++-- ...lloServiceDiscoveryAutoConfiguration.java} | 24 +++---- ...olloServiceRegistryAutoConfiguration.java} | 28 ++++---- ... => ApolloServiceDiscoveryProperties.java} | 20 +----- ...olloServiceRegistryApplicationRunner.java} | 12 ++-- ...erviceRegistryClearApplicationRunner.java} | 25 +++---- ...a => ApolloServiceRegistryProperties.java} | 18 ++--- ...ry.java => ServiceRegistryRepository.java} | 11 ++- ...rvice.java => ServiceRegistryService.java} | 32 ++++----- .../DatabaseDiscoveryClientImplTest.java | 54 +++++++------- ...istryAutoConfigurationNotEnabledTest.java} | 7 +- .../application-database-discovery.properties | 13 ++-- scripts/sql/apolloconfigdb.sql | 20 +++--- .../v210-v220/apolloconfigdb-v210-v220.sql | 20 +++--- 19 files changed, 207 insertions(+), 224 deletions(-) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/{Registry.java => ServiceRegistry.java} (90%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/{ApolloRegistryDiscoveryAutoConfiguration.java => ApolloServiceDiscoveryAutoConfiguration.java} (69%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/{ApolloRegistryClientAutoConfiguration.java => ApolloServiceRegistryAutoConfiguration.java} (62%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/{ApolloRegistryDiscoveryProperties.java => ApolloServiceDiscoveryProperties.java} (75%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/{ApolloRegistryClientApplicationRunner.java => ApolloServiceRegistryApplicationRunner.java} (91%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/{ApolloRegistryClearApplicationRunner.java => ApolloServiceRegistryClearApplicationRunner.java} (70%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/{ApolloRegistryClientProperties.java => ApolloServiceRegistryProperties.java} (87%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/{RegistryRepository.java => ServiceRegistryRepository.java} (75%) rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/{RegistryService.java => ServiceRegistryService.java} (52%) rename apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/{ApolloRegistryAutoConfigurationNotEnabledTest.java => ApolloServiceRegistryAutoConfigurationNotEnabledTest.java} (81%) diff --git a/apollo-adminservice/src/main/resources/application-database-discovery.properties b/apollo-adminservice/src/main/resources/application-database-discovery.properties index fe96a2479b8..9f19228da69 100644 --- a/apollo-adminservice/src/main/resources/application-database-discovery.properties +++ b/apollo-adminservice/src/main/resources/application-database-discovery.properties @@ -16,6 +16,6 @@ eureka.client.enabled=false spring.cloud.discovery.enabled=false -apollo.registry.client.enabled=true -apollo.registry.client.label=default +apollo.service.registry.enabled=true +apollo.service.registry.cluster=default diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Registry.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/ServiceRegistry.java similarity index 90% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Registry.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/ServiceRegistry.java index 221fa893690..74482c3c844 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/Registry.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/ServiceRegistry.java @@ -32,8 +32,8 @@ * persist {@link ServiceInstance} */ @Entity -@Table(name = "Registry") -public class Registry { +@Table(name = "ServiceRegistry") +public class ServiceRegistry { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -50,10 +50,10 @@ public class Registry { private String uri; /** - * @see ServiceInstance#getLabel() + * @see ServiceInstance#getCluster() */ - @Column(name = "Label", nullable = false) - private String label; + @Column(name = "Cluster", nullable = false) + private String cluster; @Column(name = "DataChange_CreatedTime", nullable = false) private LocalDateTime dataChangeCreatedTime; @@ -80,7 +80,7 @@ public String toString() { "id=" + id + ", serviceName='" + serviceName + '\'' + ", uri='" + uri + '\'' + - ", label='" + label + '\'' + + ", cluster='" + cluster + '\'' + ", dataChangeCreatedTime=" + dataChangeCreatedTime + ", dataChangeLastModifiedTime=" + dataChangeLastModifiedTime + '}'; @@ -110,12 +110,12 @@ public void setUri(String uri) { this.uri = uri; } - public String getLabel() { - return label; + public String getCluster() { + return cluster; } - public void setLabel(String label) { - this.label = label; + public void setCluster(String cluster) { + this.cluster = cluster; } public LocalDateTime getDataChangeCreatedTime() { diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java index 9c33ba66b53..7ae6e2f5406 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java @@ -16,15 +16,17 @@ */ package com.ctrip.framework.apollo.biz.registry; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientProperties; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; import java.util.List; +/** + * @see org.springframework.cloud.client.discovery.DiscoveryClient + */ public interface DatabaseDiscoveryClient { /** - * find by {@link ApolloRegistryClientProperties#getServiceName()}, - * then filter by label if {@link ApolloRegistryDiscoveryProperties#isFilterByLabel()} is true. + * find by {@link ApolloServiceRegistryProperties#getServiceName()}, + * then filter by {@link ApolloServiceRegistryProperties#getCluster()} */ List getInstances(String serviceName); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java index ceb52b89c89..b68b936bcfc 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java @@ -16,10 +16,10 @@ */ package com.ctrip.framework.apollo.biz.registry; -import com.ctrip.framework.apollo.biz.entity.Registry; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientProperties; -import com.ctrip.framework.apollo.biz.service.RegistryService; +import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; @@ -32,84 +32,79 @@ public class DatabaseDiscoveryClientImpl implements DatabaseDiscoveryClient { private static final Logger log = LoggerFactory.getLogger(DatabaseDiscoveryClientImpl.class); - private final RegistryService registryService; + private final ServiceRegistryService serviceRegistryService; - private final ApolloRegistryDiscoveryProperties discoveryProperties; + private final ApolloServiceDiscoveryProperties discoveryProperties; private final ServiceInstance self; public DatabaseDiscoveryClientImpl( - RegistryService registryService, - ApolloRegistryDiscoveryProperties discoveryProperties, + ServiceRegistryService serviceRegistryService, + ApolloServiceDiscoveryProperties discoveryProperties, ServiceInstance self) { - this.registryService = registryService; + this.serviceRegistryService = serviceRegistryService; this.discoveryProperties = discoveryProperties; this.self = self; } /** - * find by {@link ApolloRegistryClientProperties#getServiceName()} + * find by {@link ApolloServiceRegistryProperties#getServiceName()} */ @Override public List getInstances(String serviceName) { - final List filterByLabel; + final List serviceRegistryListFiltered; { - List all = this.registryService.findByServiceName(serviceName); - if (this.discoveryProperties.isFilterByLabel()) { - filterByLabel = filterByLabel(all, this.self.getLabel()); - } else { - // get all - filterByLabel = all; - } + List all = this.serviceRegistryService.findByServiceName(serviceName); + serviceRegistryListFiltered = filterByCluster(all, this.self.getCluster()); } - LocalDateTime healthCheckTime = this.registryService.getTimeBeforeSeconds( + LocalDateTime healthCheckTime = this.serviceRegistryService.getTimeBeforeSeconds( this.discoveryProperties.getHealthCheckIntervalInSecond() ); - final List filterByHealthCheck = filterByHealthCheck(filterByLabel, healthCheckTime, serviceName); + final List filterByHealthCheck = filterByHealthCheck(serviceRegistryListFiltered, healthCheckTime, serviceName); // convert List registrationList = new ArrayList<>(filterByHealthCheck.size()); - for (Registry registry : filterByHealthCheck) { - ApolloRegistryClientProperties registration = convert(registry); + for (ServiceRegistry serviceRegistry : filterByHealthCheck) { + ApolloServiceRegistryProperties registration = convert(serviceRegistry); registrationList.add(registration); } return registrationList; } - static ApolloRegistryClientProperties convert(Registry registry) { - ApolloRegistryClientProperties registration = new ApolloRegistryClientProperties(); - registration.setServiceName(registry.getServiceName()); - registration.setUri(registry.getUri()); - registration.setLabel(registry.getLabel()); + static ApolloServiceRegistryProperties convert(ServiceRegistry serviceRegistry) { + ApolloServiceRegistryProperties registration = new ApolloServiceRegistryProperties(); + registration.setServiceName(serviceRegistry.getServiceName()); + registration.setUri(serviceRegistry.getUri()); + registration.setCluster(serviceRegistry.getCluster()); return registration; } - static List filterByLabel(List list, String label) { + static List filterByCluster(List list, String cluster) { if (list.isEmpty()) { return Collections.emptyList(); } - List listAfterFilter = new ArrayList<>(8); - for (Registry registry : list) { - if (Objects.equals(label, registry.getLabel())) { - listAfterFilter.add(registry); + List listAfterFilter = new ArrayList<>(8); + for (ServiceRegistry serviceRegistry : list) { + if (Objects.equals(cluster, serviceRegistry.getCluster())) { + listAfterFilter.add(serviceRegistry); } } return listAfterFilter; } - static List filterByHealthCheck( - List list, + static List filterByHealthCheck( + List list, LocalDateTime healthCheckTime, String serviceName ) { if (list.isEmpty()) { return Collections.emptyList(); } - List listAfterFilter = new ArrayList<>(8); - for (Registry registry : list) { - LocalDateTime lastModifiedTime = registry.getDataChangeLastModifiedTime(); + List listAfterFilter = new ArrayList<>(8); + for (ServiceRegistry serviceRegistry : list) { + LocalDateTime lastModifiedTime = serviceRegistry.getDataChangeLastModifiedTime(); if (lastModifiedTime.isAfter(healthCheckTime)) { - listAfterFilter.add(registry); + listAfterFilter.add(serviceRegistry); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java index 78732e38200..87f9088e365 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java @@ -16,31 +16,31 @@ */ package com.ctrip.framework.apollo.biz.registry; -import com.ctrip.framework.apollo.biz.entity.Registry; -import com.ctrip.framework.apollo.biz.service.RegistryService; +import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; public class DatabaseServiceRegistryImpl implements DatabaseServiceRegistry { - private final RegistryService registryService; + private final ServiceRegistryService serviceRegistryService; public DatabaseServiceRegistryImpl( - RegistryService registryService) { - this.registryService = registryService; + ServiceRegistryService serviceRegistryService) { + this.serviceRegistryService = serviceRegistryService; } public void register(ServiceInstance instance) { - Registry registry = new Registry(); - registry.setServiceName(instance.getServiceName()); - registry.setUri(instance.getUri().toString()); - registry.setLabel(instance.getLabel()); - this.registryService.saveIfNotExistByServiceNameAndUri(registry); + ServiceRegistry serviceRegistry = new ServiceRegistry(); + serviceRegistry.setServiceName(instance.getServiceName()); + serviceRegistry.setUri(instance.getUri().toString()); + serviceRegistry.setCluster(instance.getCluster()); + this.serviceRegistryService.saveIfNotExistByServiceNameAndUri(serviceRegistry); } public void deregister(ServiceInstance instance) { - Registry registry = new Registry(); - registry.setServiceName(instance.getServiceName()); - registry.setUri(instance.getUri().toString()); - registry.setLabel(instance.getLabel()); - this.registryService.delete(registry); + ServiceRegistry serviceRegistry = new ServiceRegistry(); + serviceRegistry.setServiceName(instance.getServiceName()); + serviceRegistry.setUri(instance.getUri().toString()); + serviceRegistry.setCluster(instance.getCluster()); + this.serviceRegistryService.delete(serviceRegistry); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java index cae5d635d57..f02c185e0ca 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java @@ -31,9 +31,9 @@ public interface ServiceInstance { /** * get the uri of a service instance, for example: *

* @return The service URI address. */ @@ -43,10 +43,10 @@ public interface ServiceInstance { * Tag a service instance for service discovery. *

* It's a little hard to persist the key / value pair metadata to database, - * so use a string 'label' instead of metadata. + * so use cluster instead of metadata for service discovery. * * @see org.springframework.cloud.client.ServiceInstance#getMetadata() - * @return The label of the service instance. + * @return The cluster of the service instance. */ - String getLabel(); + String getCluster(); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryDiscoveryAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java similarity index 69% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryDiscoveryAutoConfiguration.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java index 13ea6ee06b9..c3f7a3eb615 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryDiscoveryAutoConfiguration.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java @@ -19,9 +19,9 @@ import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClient; import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClientImpl; import com.ctrip.framework.apollo.biz.registry.ServiceInstance; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClearApplicationRunner; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; -import com.ctrip.framework.apollo.biz.service.RegistryService; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryClearApplicationRunner; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -30,31 +30,31 @@ @Configuration @ConditionalOnProperty( - prefix = ApolloRegistryDiscoveryProperties.PREFIX, + prefix = ApolloServiceDiscoveryProperties.PREFIX, value = "enabled" ) @EnableConfigurationProperties({ - ApolloRegistryDiscoveryProperties.class, + ApolloServiceDiscoveryProperties.class, }) -public class ApolloRegistryDiscoveryAutoConfiguration { +public class ApolloServiceDiscoveryAutoConfiguration { @Bean @ConditionalOnMissingBean public DatabaseDiscoveryClient databaseDiscoveryClient( - ApolloRegistryDiscoveryProperties discoveryProperties, + ApolloServiceDiscoveryProperties discoveryProperties, ServiceInstance selfServiceInstance, - RegistryService registryService + ServiceRegistryService serviceRegistryService ) { return new DatabaseDiscoveryClientImpl( - registryService, discoveryProperties, selfServiceInstance + serviceRegistryService, discoveryProperties, selfServiceInstance ); } @Bean @ConditionalOnMissingBean - public ApolloRegistryClearApplicationRunner apolloRegistryClearApplicationRunner( - RegistryService registryService + public ApolloServiceRegistryClearApplicationRunner apolloServiceRegistryClearApplicationRunner( + ServiceRegistryService serviceRegistryService ) { - return new ApolloRegistryClearApplicationRunner(registryService); + return new ApolloServiceRegistryClearApplicationRunner(serviceRegistryService); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryClientAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfiguration.java similarity index 62% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryClientAutoConfiguration.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfiguration.java index ad693ff749e..b3445b18aa2 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryClientAutoConfiguration.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfiguration.java @@ -18,10 +18,10 @@ import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistry; import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistryImpl; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientApplicationRunner; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryClientProperties; -import com.ctrip.framework.apollo.biz.repository.RegistryRepository; -import com.ctrip.framework.apollo.biz.service.RegistryService; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryApplicationRunner; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; +import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -29,30 +29,30 @@ import org.springframework.context.annotation.Configuration; @Configuration -@ConditionalOnProperty(prefix = ApolloRegistryClientProperties.PREFIX, value = "enabled") -@EnableConfigurationProperties(ApolloRegistryClientProperties.class) -public class ApolloRegistryClientAutoConfiguration { +@ConditionalOnProperty(prefix = ApolloServiceRegistryProperties.PREFIX, value = "enabled") +@EnableConfigurationProperties(ApolloServiceRegistryProperties.class) +public class ApolloServiceRegistryAutoConfiguration { @Bean @ConditionalOnMissingBean - public RegistryService registryService(RegistryRepository repository) { - return new RegistryService(repository); + public ServiceRegistryService registryService(ServiceRegistryRepository repository) { + return new ServiceRegistryService(repository); } @Bean @ConditionalOnMissingBean public DatabaseServiceRegistry databaseServiceRegistry( - RegistryService registryService + ServiceRegistryService serviceRegistryService ) { - return new DatabaseServiceRegistryImpl(registryService); + return new DatabaseServiceRegistryImpl(serviceRegistryService); } @Bean @ConditionalOnMissingBean - public ApolloRegistryClientApplicationRunner apolloRegistryClientApplicationRunner( - ApolloRegistryClientProperties registration, + public ApolloServiceRegistryApplicationRunner apolloServiceRegistryApplicationRunner( + ApolloServiceRegistryProperties registration, DatabaseServiceRegistry serviceRegistry ) { - return new ApolloRegistryClientApplicationRunner(registration, serviceRegistry); + return new ApolloServiceRegistryApplicationRunner(registration, serviceRegistry); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceDiscoveryProperties.java similarity index 75% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceDiscoveryProperties.java index 674017222c6..fb39077a919 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryDiscoveryProperties.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceDiscoveryProperties.java @@ -23,22 +23,16 @@ * @see org.springframework.cloud.consul.ConsulProperties * @see org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean */ -@ConfigurationProperties(prefix = ApolloRegistryDiscoveryProperties.PREFIX) -public class ApolloRegistryDiscoveryProperties { +@ConfigurationProperties(prefix = ApolloServiceDiscoveryProperties.PREFIX) +public class ApolloServiceDiscoveryProperties { - public static final String PREFIX = "apollo.registry.discovery"; + public static final String PREFIX = "apollo.service.discovery"; /** * enable discovery of registry or not */ private boolean enabled = false; - /** - * true mean only return instances which have same label as self. - * false mean return all instances without filter by label. - */ - private boolean filterByLabel = true; - /** * health check interval. *

@@ -48,14 +42,6 @@ public class ApolloRegistryDiscoveryProperties { */ private long healthCheckIntervalInSecond = 61; - public boolean isFilterByLabel() { - return filterByLabel; - } - - public void setFilterByLabel(boolean filterByLabel) { - this.filterByLabel = filterByLabel; - } - public long getHealthCheckIntervalInSecond() { return healthCheckIntervalInSecond; } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java similarity index 91% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientApplicationRunner.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java index 6663251de4b..07ea455274e 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java @@ -28,11 +28,11 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; -public class ApolloRegistryClientApplicationRunner +public class ApolloServiceRegistryApplicationRunner implements ApplicationRunner { private static final Logger log = LoggerFactory - .getLogger(ApolloRegistryClientApplicationRunner.class); + .getLogger(ApolloServiceRegistryApplicationRunner.class); private final ServiceInstance registration; @@ -43,7 +43,7 @@ public class ApolloRegistryClientApplicationRunner */ private final ScheduledExecutorService heartbeatScheduledExecutorService; - public ApolloRegistryClientApplicationRunner( + public ApolloServiceRegistryApplicationRunner( ServiceInstance registration, DatabaseServiceRegistry serviceRegistry ) { @@ -61,7 +61,7 @@ public void run(ApplicationArguments args) throws Exception { "register to database. '{}': uri '{}', label '{}' ", this.registration.getServiceName(), this.registration.getUri(), - this.registration.getLabel() + this.registration.getCluster() ); // heartbeat as same as register this.heartbeatScheduledExecutorService @@ -76,14 +76,14 @@ private void deregister() { "deregister success, '{}' uri '{}', label '{}'", this.registration.getServiceName(), this.registration.getUri(), - this.registration.getLabel() + this.registration.getCluster() ); } catch (Exception e) { log.error( "deregister fail, '{}' uri '{}', label '{}'", this.registration.getServiceName(), this.registration.getUri(), - this.registration.getLabel(), + this.registration.getCluster(), e ); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClearApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java similarity index 70% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClearApplicationRunner.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java index 694514efcc6..bc7b911599b 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClearApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java @@ -16,8 +16,8 @@ */ package com.ctrip.framework.apollo.biz.registry.configuration.support; -import com.ctrip.framework.apollo.biz.entity.Registry; -import com.ctrip.framework.apollo.biz.service.RegistryService; +import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; import java.time.Duration; import java.util.List; @@ -32,10 +32,11 @@ /** * clear the unhealthy instances. */ -public class ApolloRegistryClearApplicationRunner +public class ApolloServiceRegistryClearApplicationRunner implements ApplicationRunner { - private static final Logger log = LoggerFactory.getLogger(ApolloRegistryClearApplicationRunner.class); + private static final Logger log = LoggerFactory.getLogger( + ApolloServiceRegistryClearApplicationRunner.class); /** * for {@link #clearUnhealthyInstances()} @@ -43,11 +44,11 @@ public class ApolloRegistryClearApplicationRunner private final ScheduledExecutorService instanceClearScheduledExecutorService; - private final RegistryService registryService; + private final ServiceRegistryService serviceRegistryService; - public ApolloRegistryClearApplicationRunner( - RegistryService registryService) { - this.registryService = registryService; + public ApolloServiceRegistryClearApplicationRunner( + ServiceRegistryService serviceRegistryService) { + this.serviceRegistryService = serviceRegistryService; this.instanceClearScheduledExecutorService = Executors.newSingleThreadScheduledExecutor( ApolloThreadFactory.create("ApolloRegistryServerClearInstances", true) ); @@ -58,10 +59,10 @@ public ApolloRegistryClearApplicationRunner( */ private void clearUnhealthyInstances() { try { - List registryListDeleted = - this.registryService.deleteTimeBefore(Duration.ofMinutes(10)); - if (registryListDeleted != null && !registryListDeleted.isEmpty()) { - log.info("clear {} unhealthy instances by scheduled task", registryListDeleted.size()); + List serviceRegistryListDeleted = + this.serviceRegistryService.deleteTimeBefore(Duration.ofMinutes(10)); + if (serviceRegistryListDeleted != null && !serviceRegistryListDeleted.isEmpty()) { + log.info("clear {} unhealthy instances by scheduled task", serviceRegistryListDeleted.size()); } } catch (Exception e) { log.error("fail to clear unhealthy instances by scheduled task", e); diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientProperties.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java similarity index 87% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientProperties.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java index 42110e42a25..9163d13ee89 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloRegistryClientProperties.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java @@ -31,10 +31,10 @@ * @see org.springframework.cloud.netflix.eureka.EurekaClientConfigBean * @see org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean */ -@ConfigurationProperties(prefix = ApolloRegistryClientProperties.PREFIX) -public class ApolloRegistryClientProperties implements ServiceInstance { +@ConfigurationProperties(prefix = ApolloServiceRegistryProperties.PREFIX) +public class ApolloServiceRegistryProperties implements ServiceInstance { - public static final String PREFIX = "apollo.registry.client"; + public static final String PREFIX = "apollo.service.registry"; /** * register self to registry or not @@ -53,9 +53,9 @@ public class ApolloRegistryClientProperties implements ServiceInstance { private URI uri; /** - * @see ServiceInstance#getLabel() + * @see ServiceInstance#getCluster() */ - private String label; + private String cluster; @Autowired private PropertyResolver propertyResolver; @@ -110,11 +110,11 @@ public void setServiceName(String serviceName) { } @Override - public String getLabel() { - return label; + public String getCluster() { + return cluster; } - public void setLabel(String label) { - this.label = label; + public void setCluster(String cluster) { + this.cluster = cluster; } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/RegistryRepository.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java similarity index 75% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/RegistryRepository.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java index c4f192ba603..ebb2b1b4c1d 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/RegistryRepository.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java @@ -16,24 +16,23 @@ */ package com.ctrip.framework.apollo.biz.repository; -import com.ctrip.framework.apollo.biz.entity.Registry; +import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; import java.time.LocalDateTime; -import java.util.Date; import java.util.List; import javax.transaction.Transactional; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; -public interface RegistryRepository extends PagingAndSortingRepository { +public interface ServiceRegistryRepository extends PagingAndSortingRepository { - List findByServiceName(String serviceName); + List findByServiceName(String serviceName); - Registry findByServiceNameAndUri(String serviceName, String uri); + ServiceRegistry findByServiceNameAndUri(String serviceName, String uri); @Modifying @Transactional - List deleteByDataChangeLastModifiedTimeLessThan(LocalDateTime localDateTime); + List deleteByDataChangeLastModifiedTimeLessThan(LocalDateTime localDateTime); @Modifying @Transactional diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/RegistryService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java similarity index 52% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/RegistryService.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java index 9b22b8ff4a0..62027d6c512 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/RegistryService.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java @@ -16,39 +16,39 @@ */ package com.ctrip.framework.apollo.biz.service; -import com.ctrip.framework.apollo.biz.entity.Registry; -import com.ctrip.framework.apollo.biz.repository.RegistryRepository; +import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; +import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; import java.time.Duration; import java.time.LocalDateTime; import java.util.List; -public class RegistryService { +public class ServiceRegistryService { - private final RegistryRepository repository; + private final ServiceRegistryRepository repository; - public RegistryService(RegistryRepository repository) { + public ServiceRegistryService(ServiceRegistryRepository repository) { this.repository = repository; } - public Registry saveIfNotExistByServiceNameAndUri(Registry registry) { - Registry registrySaved = this.repository.findByServiceNameAndUri(registry.getServiceName(), registry.getUri()); - if (null == registrySaved) { - registrySaved = registry; + public ServiceRegistry saveIfNotExistByServiceNameAndUri(ServiceRegistry serviceRegistry) { + ServiceRegistry serviceRegistrySaved = this.repository.findByServiceNameAndUri(serviceRegistry.getServiceName(), serviceRegistry.getUri()); + if (null == serviceRegistrySaved) { + serviceRegistrySaved = serviceRegistry; } else { // update - registrySaved.setLabel(registry.getLabel()); - registrySaved.setDataChangeLastModifiedTime(LocalDateTime.now()); + serviceRegistrySaved.setCluster(serviceRegistry.getCluster()); + serviceRegistrySaved.setDataChangeLastModifiedTime(LocalDateTime.now()); } - return this.repository.save(registrySaved); + return this.repository.save(serviceRegistrySaved); } - public void delete(Registry registry) { + public void delete(ServiceRegistry serviceRegistry) { this.repository.deleteByServiceNameAndUri( - registry.getServiceName(), registry.getUri() + serviceRegistry.getServiceName(), serviceRegistry.getUri() ); } - public List findByServiceName(String serviceName) { + public List findByServiceName(String serviceName) { return this.repository.findByServiceName(serviceName); } @@ -56,7 +56,7 @@ public LocalDateTime getTimeBeforeSeconds(long seconds) { return this.repository.currentTimestamp().minusSeconds(seconds); } - public List deleteTimeBefore(Duration duration) { + public List deleteTimeBefore(Duration duration) { LocalDateTime time = this.repository.currentTimestamp().minus(duration); return this.repository.deleteByDataChangeLastModifiedTimeLessThan(time); } diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java index a885fa4b12a..bd1dedc0b58 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java @@ -19,9 +19,9 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.anyLong; -import com.ctrip.framework.apollo.biz.entity.Registry; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloRegistryDiscoveryProperties; -import com.ctrip.framework.apollo.biz.service.RegistryService; +import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; @@ -30,36 +30,36 @@ class DatabaseDiscoveryClientImplTest { - static Registry newRegistry(String serviceName, String uri, String label) { - Registry registry = new Registry(); - registry.setServiceName(serviceName); - registry.setUri(uri); - registry.setLabel(label); - registry.setDataChangeCreatedTime(LocalDateTime.now()); - registry.setDataChangeLastModifiedTime(LocalDateTime.now()); - return registry; + static ServiceRegistry newRegistry(String serviceName, String uri, String label) { + ServiceRegistry serviceRegistry = new ServiceRegistry(); + serviceRegistry.setServiceName(serviceName); + serviceRegistry.setUri(uri); + serviceRegistry.setCluster(label); + serviceRegistry.setDataChangeCreatedTime(LocalDateTime.now()); + serviceRegistry.setDataChangeLastModifiedTime(LocalDateTime.now()); + return serviceRegistry; } @Test void getInstancesWithoutLabel() { final String serviceName = "a-service"; - RegistryService registryService = Mockito.mock(RegistryService.class); + ServiceRegistryService serviceRegistryService = Mockito.mock(ServiceRegistryService.class); { - List registryList = Arrays.asList( + List serviceRegistryList = Arrays.asList( newRegistry(serviceName, "http://localhost:8081/", "label1"), newRegistry(serviceName, "http://localhost:8082/", "label2") ); - Mockito.when(registryService.findByServiceName(serviceName)) - .thenReturn(registryList); - Mockito.when(registryService.getTimeBeforeSeconds(anyLong())) + Mockito.when(serviceRegistryService.findByServiceName(serviceName)) + .thenReturn(serviceRegistryList); + Mockito.when(serviceRegistryService.getTimeBeforeSeconds(anyLong())) .thenReturn(LocalDateTime.now().minusMinutes(1)); } - ApolloRegistryDiscoveryProperties properties = new ApolloRegistryDiscoveryProperties(); + ApolloServiceDiscoveryProperties properties = new ApolloServiceDiscoveryProperties(); properties.setFilterByLabel(false); DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( - registryService, + serviceRegistryService, properties, null ); @@ -75,30 +75,30 @@ void getInstancesWithoutLabel() { @Test void getInstancesWithLabel() { final String serviceName = "a-service"; - RegistryService registryService = Mockito.mock(RegistryService.class); + ServiceRegistryService serviceRegistryService = Mockito.mock(ServiceRegistryService.class); { - List registryList = Arrays.asList( + List serviceRegistryList = Arrays.asList( newRegistry(serviceName, "http://localhost:8081/", "label1"), newRegistry("b-service", "http://localhost:8082/", "label2"), newRegistry("c-service", "http://localhost:8082/", "label3") ); - Mockito.when(registryService.findByServiceName(serviceName)) - .thenReturn(registryList); - Mockito.when(registryService.getTimeBeforeSeconds(anyLong())) + Mockito.when(serviceRegistryService.findByServiceName(serviceName)) + .thenReturn(serviceRegistryList); + Mockito.when(serviceRegistryService.getTimeBeforeSeconds(anyLong())) .thenReturn(LocalDateTime.now().minusMinutes(1)); } ServiceInstance serviceInstance = Mockito.mock(ServiceInstance.class); - Mockito.when(serviceInstance.getLabel()).thenReturn("label1"); + Mockito.when(serviceInstance.getCluster()).thenReturn("label1"); DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( - registryService, - new ApolloRegistryDiscoveryProperties(), + serviceRegistryService, + new ApolloServiceDiscoveryProperties(), serviceInstance ); List serviceInstances = discoveryClient.getInstances(serviceName); assertEquals(1, serviceInstances.size()); assertEquals(serviceName, serviceInstances.get(0).getServiceName()); - assertEquals("label1", serviceInstances.get(0).getLabel()); + assertEquals("label1", serviceInstances.get(0).getCluster()); } } \ No newline at end of file diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfigurationNotEnabledTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfigurationNotEnabledTest.java similarity index 81% rename from apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfigurationNotEnabledTest.java rename to apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfigurationNotEnabledTest.java index a4092f789bf..f93aac28b83 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloRegistryAutoConfigurationNotEnabledTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfigurationNotEnabledTest.java @@ -21,8 +21,11 @@ import org.springframework.test.context.ContextConfiguration; @SpringBootTest -@ContextConfiguration(classes = ApolloRegistryAutoConfiguration.class) -class ApolloRegistryAutoConfigurationNotEnabledTest { +@ContextConfiguration(classes = { + ApolloServiceRegistryAutoConfiguration.class, + ApolloServiceDiscoveryAutoConfiguration.class +}) +class ApolloServiceRegistryAutoConfigurationNotEnabledTest { @Test void load() { diff --git a/apollo-configservice/src/main/resources/application-database-discovery.properties b/apollo-configservice/src/main/resources/application-database-discovery.properties index b824910565a..28b1e60da58 100644 --- a/apollo-configservice/src/main/resources/application-database-discovery.properties +++ b/apollo-configservice/src/main/resources/application-database-discovery.properties @@ -17,12 +17,9 @@ apollo.eureka.server.enabled=false eureka.client.enabled=false spring.cloud.discovery.enabled=false -apollo.registry.client.enabled=true -apollo.registry.client.label=default +apollo.service.registry.enabled=true +apollo.service.registry.cluster=default -apollo.registry.discovery.enabled=true -# only do discovery with same label or not, -# if set to false, return all service instances without label filter -apollo.registry.discovery.filterByLabel=true -# health check by heartbeat, heartbeat time before 61s ago will be tag as unhealthy -apollo.registry.discovery.healthCheckInterval = 61 +apollo.service.discovery.enabled=true +# health check by heartbeat, heartbeat time before 61s ago will be seemed as unhealthy +apollo.service.discovery.healthCheckIntervalInSecond = 61 diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index 20009c70653..d5ef0d8248e 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -416,16 +416,16 @@ CREATE TABLE `AccessKey` ( DROP TABLE IF EXISTS `Registry`; -CREATE TABLE `Registry` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ServiceName` varchar(64) NOT NULL COMMENT '服务名', - `Uri` varchar(64) NOT NULL COMMENT '服务地址', - `Label` varchar(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `IX_UNIQUE_KEY` (`ServiceName`,`Uri`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +CREATE TABLE `ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`) USING BTREE, + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; diff --git a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql index 1d78d6e543b..29e01be9bf7 100644 --- a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -17,14 +17,14 @@ Use ApolloConfigDB; -CREATE TABLE `Registry` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ServiceName` varchar(64) NOT NULL COMMENT '服务名', - `Uri` varchar(64) NOT NULL COMMENT '服务地址', - `Label` varchar(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `IX_UNIQUE_KEY` (`ServiceName`,`Uri`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +CREATE TABLE `ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`) USING BTREE, + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; \ No newline at end of file From 343d9f96ce8a018f1b4d10bfff77eba095828283 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 20:26:17 +0800 Subject: [PATCH 08/31] feat: add service registry config heartbeatIntervalInSecond --- .../application-database-discovery.properties | 1 + .../ApolloServiceRegistryApplicationRunner.java | 9 +++++---- .../support/ApolloServiceRegistryProperties.java | 13 +++++++++++++ .../application-database-discovery.properties | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apollo-adminservice/src/main/resources/application-database-discovery.properties b/apollo-adminservice/src/main/resources/application-database-discovery.properties index 9f19228da69..b67172a1fc9 100644 --- a/apollo-adminservice/src/main/resources/application-database-discovery.properties +++ b/apollo-adminservice/src/main/resources/application-database-discovery.properties @@ -18,4 +18,5 @@ spring.cloud.discovery.enabled=false apollo.service.registry.enabled=true apollo.service.registry.cluster=default +apollo.service.registry.heartbeatIntervalInSecond=10 diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java index 07ea455274e..66c9e3a986b 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java @@ -34,7 +34,7 @@ public class ApolloServiceRegistryApplicationRunner private static final Logger log = LoggerFactory .getLogger(ApolloServiceRegistryApplicationRunner.class); - private final ServiceInstance registration; + private final ApolloServiceRegistryProperties registration; private final DatabaseServiceRegistry serviceRegistry; @@ -44,13 +44,13 @@ public class ApolloServiceRegistryApplicationRunner private final ScheduledExecutorService heartbeatScheduledExecutorService; public ApolloServiceRegistryApplicationRunner( - ServiceInstance registration, + ApolloServiceRegistryProperties registration, DatabaseServiceRegistry serviceRegistry ) { this.registration = registration; this.serviceRegistry = serviceRegistry; this.heartbeatScheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - ApolloThreadFactory.create("ApolloRegistryClientHeartBeat", true) + ApolloThreadFactory.create("ApolloServiceRegistryHeartBeat", true) ); } @@ -65,7 +65,8 @@ public void run(ApplicationArguments args) throws Exception { ); // heartbeat as same as register this.heartbeatScheduledExecutorService - .scheduleAtFixedRate(this::heartbeat, 0, 10, TimeUnit.SECONDS); + .scheduleAtFixedRate(this::heartbeat, 0, this.registration.getHeartbeatIntervalInSecond(), + TimeUnit.SECONDS); } @PreDestroy diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java index 9163d13ee89..549ed591f1d 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java @@ -57,6 +57,11 @@ public class ApolloServiceRegistryProperties implements ServiceInstance { */ private String cluster; + /** + * heartbeat to registry in second. + */ + private long heartbeatIntervalInSecond = 10; + @Autowired private PropertyResolver propertyResolver; @@ -117,4 +122,12 @@ public String getCluster() { public void setCluster(String cluster) { this.cluster = cluster; } + + public long getHeartbeatIntervalInSecond() { + return heartbeatIntervalInSecond; + } + + public void setHeartbeatIntervalInSecond(long heartbeatIntervalInSecond) { + this.heartbeatIntervalInSecond = heartbeatIntervalInSecond; + } } diff --git a/apollo-configservice/src/main/resources/application-database-discovery.properties b/apollo-configservice/src/main/resources/application-database-discovery.properties index 28b1e60da58..de8b15950ce 100644 --- a/apollo-configservice/src/main/resources/application-database-discovery.properties +++ b/apollo-configservice/src/main/resources/application-database-discovery.properties @@ -19,6 +19,7 @@ spring.cloud.discovery.enabled=false apollo.service.registry.enabled=true apollo.service.registry.cluster=default +apollo.service.registry.heartbeatIntervalInSecond=10 apollo.service.discovery.enabled=true # health check by heartbeat, heartbeat time before 61s ago will be seemed as unhealthy From 1eed34ab14581a5680dde7d75135bc32cf9bbcf5 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 20:32:30 +0800 Subject: [PATCH 09/31] feat: clear service instances 1 days ago --- .../support/ApolloServiceRegistryClearApplicationRunner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java index bc7b911599b..6bfab297a16 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java @@ -60,7 +60,7 @@ public ApolloServiceRegistryClearApplicationRunner( private void clearUnhealthyInstances() { try { List serviceRegistryListDeleted = - this.serviceRegistryService.deleteTimeBefore(Duration.ofMinutes(10)); + this.serviceRegistryService.deleteTimeBefore(Duration.ofDays(1)); if (serviceRegistryListDeleted != null && !serviceRegistryListDeleted.isEmpty()) { log.info("clear {} unhealthy instances by scheduled task", serviceRegistryListDeleted.size()); } @@ -71,6 +71,6 @@ private void clearUnhealthyInstances() { @Override public void run(ApplicationArguments args) throws Exception { - this.instanceClearScheduledExecutorService.scheduleAtFixedRate(this::clearUnhealthyInstances, 0, 60, TimeUnit.SECONDS); + this.instanceClearScheduledExecutorService.scheduleAtFixedRate(this::clearUnhealthyInstances, 0, 1, TimeUnit.DAYS); } } From e4513c65fb6991702da5165a02e664f4f2d8d389 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 20:38:32 +0800 Subject: [PATCH 10/31] fix: move '@Transactional' from repository up to service --- .../apollo/biz/repository/ServiceRegistryRepository.java | 6 ------ .../apollo/biz/service/ServiceRegistryService.java | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java index ebb2b1b4c1d..055cd57dff7 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java @@ -19,8 +19,6 @@ import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; import java.time.LocalDateTime; import java.util.List; -import javax.transaction.Transactional; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; @@ -30,12 +28,8 @@ public interface ServiceRegistryRepository extends PagingAndSortingRepository deleteByDataChangeLastModifiedTimeLessThan(LocalDateTime localDateTime); - @Modifying - @Transactional int deleteByServiceNameAndUri(String serviceName, String uri); /** diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java index 62027d6c512..0d01ce0f3a1 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java @@ -21,6 +21,7 @@ import java.time.Duration; import java.time.LocalDateTime; import java.util.List; +import org.springframework.transaction.annotation.Transactional; public class ServiceRegistryService { @@ -42,6 +43,7 @@ public ServiceRegistry saveIfNotExistByServiceNameAndUri(ServiceRegistry service return this.repository.save(serviceRegistrySaved); } + @Transactional public void delete(ServiceRegistry serviceRegistry) { this.repository.deleteByServiceNameAndUri( serviceRegistry.getServiceName(), serviceRegistry.getUri() @@ -56,6 +58,7 @@ public LocalDateTime getTimeBeforeSeconds(long seconds) { return this.repository.currentTimestamp().minusSeconds(seconds); } + @Transactional public List deleteTimeBefore(Duration duration) { LocalDateTime time = this.repository.currentTimestamp().minus(duration); return this.repository.deleteByDataChangeLastModifiedTimeLessThan(time); From 4fa67b78ac7d34f3beb48567b8d725f4ca6a936b Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 22:22:33 +0800 Subject: [PATCH 11/31] refactor: Change all to use jvm `LocalDateTime.now()` --- .../registry/DatabaseDiscoveryClientImpl.java | 49 +++------------- .../registry/DatabaseServiceRegistryImpl.java | 1 + .../repository/ServiceRegistryRepository.java | 11 +--- .../biz/service/ServiceRegistryService.java | 21 ++++--- .../DatabaseDiscoveryClientImplTest.java | 57 +++++-------------- scripts/sql/apolloconfigdb.sql | 6 +- .../v210-v220/apolloconfigdb-v210-v220.sql | 6 +- 7 files changed, 44 insertions(+), 107 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java index b68b936bcfc..f0c5759639b 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java @@ -25,13 +25,8 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class DatabaseDiscoveryClientImpl implements DatabaseDiscoveryClient { - - private static final Logger log = LoggerFactory.getLogger(DatabaseDiscoveryClientImpl.class); - private final ServiceRegistryService serviceRegistryService; private final ApolloServiceDiscoveryProperties discoveryProperties; @@ -54,17 +49,18 @@ public DatabaseDiscoveryClientImpl( public List getInstances(String serviceName) { final List serviceRegistryListFiltered; { - List all = this.serviceRegistryService.findByServiceName(serviceName); - serviceRegistryListFiltered = filterByCluster(all, this.self.getCluster()); + LocalDateTime healthTime = LocalDateTime.now() + .minusSeconds(this.discoveryProperties.getHealthCheckIntervalInSecond()); + List filterByHealthCheck = + this.serviceRegistryService.findByServiceNameDataChangeLastModifiedTimeGreaterThan( + serviceName, healthTime + ); + serviceRegistryListFiltered = filterByCluster(filterByHealthCheck, this.self.getCluster()); } - LocalDateTime healthCheckTime = this.serviceRegistryService.getTimeBeforeSeconds( - this.discoveryProperties.getHealthCheckIntervalInSecond() - ); - final List filterByHealthCheck = filterByHealthCheck(serviceRegistryListFiltered, healthCheckTime, serviceName); // convert - List registrationList = new ArrayList<>(filterByHealthCheck.size()); - for (ServiceRegistry serviceRegistry : filterByHealthCheck) { + List registrationList = new ArrayList<>(serviceRegistryListFiltered.size()); + for (ServiceRegistry serviceRegistry : serviceRegistryListFiltered) { ApolloServiceRegistryProperties registration = convert(serviceRegistry); registrationList.add(registration); } @@ -92,31 +88,4 @@ static List filterByCluster(List list, String return listAfterFilter; } - static List filterByHealthCheck( - List list, - LocalDateTime healthCheckTime, - String serviceName - ) { - if (list.isEmpty()) { - return Collections.emptyList(); - } - List listAfterFilter = new ArrayList<>(8); - for (ServiceRegistry serviceRegistry : list) { - LocalDateTime lastModifiedTime = serviceRegistry.getDataChangeLastModifiedTime(); - if (lastModifiedTime.isAfter(healthCheckTime)) { - listAfterFilter.add(serviceRegistry); - } - } - - if (listAfterFilter.isEmpty()) { - log.error( - "there is no healthy instance of '{}'. And there are {} unhealthy instances", - serviceName, - list.size() - ); - } - - return listAfterFilter; - } - } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java index 87f9088e365..55ab714fffd 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java @@ -18,6 +18,7 @@ import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; +import java.time.LocalDateTime; public class DatabaseServiceRegistryImpl implements DatabaseServiceRegistry { diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java index 055cd57dff7..1cacee0fad1 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/repository/ServiceRegistryRepository.java @@ -19,22 +19,17 @@ import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; import java.time.LocalDateTime; import java.util.List; -import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; public interface ServiceRegistryRepository extends PagingAndSortingRepository { - List findByServiceName(String serviceName); + List findByServiceNameAndDataChangeLastModifiedTimeGreaterThan( + String serviceName, LocalDateTime localDateTime + ); ServiceRegistry findByServiceNameAndUri(String serviceName, String uri); List deleteByDataChangeLastModifiedTimeLessThan(LocalDateTime localDateTime); int deleteByServiceNameAndUri(String serviceName, String uri); - - /** - * use time in database instead of JVM - */ - @Query(value = "SELECT CURRENT_TIMESTAMP", nativeQuery = true) - LocalDateTime currentTimestamp(); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java index 0d01ce0f3a1..441628bc894 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java @@ -33,12 +33,16 @@ public ServiceRegistryService(ServiceRegistryRepository repository) { public ServiceRegistry saveIfNotExistByServiceNameAndUri(ServiceRegistry serviceRegistry) { ServiceRegistry serviceRegistrySaved = this.repository.findByServiceNameAndUri(serviceRegistry.getServiceName(), serviceRegistry.getUri()); + final LocalDateTime now = LocalDateTime.now(); if (null == serviceRegistrySaved) { serviceRegistrySaved = serviceRegistry; + serviceRegistrySaved.setDataChangeCreatedTime(now); + serviceRegistrySaved.setDataChangeLastModifiedTime(now); } else { - // update + // update cluster serviceRegistrySaved.setCluster(serviceRegistry.getCluster()); - serviceRegistrySaved.setDataChangeLastModifiedTime(LocalDateTime.now()); + + serviceRegistrySaved.setDataChangeLastModifiedTime(now); } return this.repository.save(serviceRegistrySaved); } @@ -50,17 +54,16 @@ public void delete(ServiceRegistry serviceRegistry) { ); } - public List findByServiceName(String serviceName) { - return this.repository.findByServiceName(serviceName); - } - - public LocalDateTime getTimeBeforeSeconds(long seconds) { - return this.repository.currentTimestamp().minusSeconds(seconds); + public List findByServiceNameDataChangeLastModifiedTimeGreaterThan( + String serviceName, + LocalDateTime localDateTime + ) { + return this.repository.findByServiceNameAndDataChangeLastModifiedTimeGreaterThan(serviceName, localDateTime); } @Transactional public List deleteTimeBefore(Duration duration) { - LocalDateTime time = this.repository.currentTimestamp().minus(duration); + LocalDateTime time = LocalDateTime.now().minus(duration); return this.repository.deleteByDataChangeLastModifiedTimeLessThan(time); } } diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java index bd1dedc0b58..c79fad79e57 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java @@ -17,7 +17,8 @@ package com.ctrip.framework.apollo.biz.registry; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties; @@ -30,66 +31,34 @@ class DatabaseDiscoveryClientImplTest { - static ServiceRegistry newRegistry(String serviceName, String uri, String label) { + static ServiceRegistry newRegistry(String serviceName, String uri, String cluster) { ServiceRegistry serviceRegistry = new ServiceRegistry(); serviceRegistry.setServiceName(serviceName); serviceRegistry.setUri(uri); - serviceRegistry.setCluster(label); + serviceRegistry.setCluster(cluster); serviceRegistry.setDataChangeCreatedTime(LocalDateTime.now()); serviceRegistry.setDataChangeLastModifiedTime(LocalDateTime.now()); return serviceRegistry; } @Test - void getInstancesWithoutLabel() { + void getInstances() { final String serviceName = "a-service"; ServiceRegistryService serviceRegistryService = Mockito.mock(ServiceRegistryService.class); { List serviceRegistryList = Arrays.asList( - newRegistry(serviceName, "http://localhost:8081/", "label1"), - newRegistry(serviceName, "http://localhost:8082/", "label2") + newRegistry(serviceName, "http://localhost:8081/", "1"), + newRegistry("b-service", "http://localhost:8082/", "2"), + newRegistry("c-service", "http://localhost:8082/", "3") ); - Mockito.when(serviceRegistryService.findByServiceName(serviceName)) + Mockito.when( + serviceRegistryService.findByServiceNameDataChangeLastModifiedTimeGreaterThan(eq(serviceName), + any(LocalDateTime.class))) .thenReturn(serviceRegistryList); - Mockito.when(serviceRegistryService.getTimeBeforeSeconds(anyLong())) - .thenReturn(LocalDateTime.now().minusMinutes(1)); - } - - ApolloServiceDiscoveryProperties properties = new ApolloServiceDiscoveryProperties(); - properties.setFilterByLabel(false); - - DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( - serviceRegistryService, - properties, - null - ); - - List serviceInstances = discoveryClient.getInstances(serviceName); - assertEquals(2, serviceInstances.size()); - serviceInstances.forEach( - serviceInstance -> assertEquals(serviceName, serviceInstance.getServiceName()) - ); - } - - - @Test - void getInstancesWithLabel() { - final String serviceName = "a-service"; - ServiceRegistryService serviceRegistryService = Mockito.mock(ServiceRegistryService.class); - { - List serviceRegistryList = Arrays.asList( - newRegistry(serviceName, "http://localhost:8081/", "label1"), - newRegistry("b-service", "http://localhost:8082/", "label2"), - newRegistry("c-service", "http://localhost:8082/", "label3") - ); - Mockito.when(serviceRegistryService.findByServiceName(serviceName)) - .thenReturn(serviceRegistryList); - Mockito.when(serviceRegistryService.getTimeBeforeSeconds(anyLong())) - .thenReturn(LocalDateTime.now().minusMinutes(1)); } ServiceInstance serviceInstance = Mockito.mock(ServiceInstance.class); - Mockito.when(serviceInstance.getCluster()).thenReturn("label1"); + Mockito.when(serviceInstance.getCluster()).thenReturn("1"); DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( serviceRegistryService, new ApolloServiceDiscoveryProperties(), @@ -99,6 +68,6 @@ void getInstancesWithLabel() { List serviceInstances = discoveryClient.getInstances(serviceName); assertEquals(1, serviceInstances.size()); assertEquals(serviceName, serviceInstances.get(0).getServiceName()); - assertEquals("label1", serviceInstances.get(0).getCluster()); + assertEquals("1", serviceInstances.get(0).getCluster()); } } \ No newline at end of file diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index d5ef0d8248e..6b695fdad78 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -420,9 +420,9 @@ CREATE TABLE `ServiceRegistry` ( `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', - `Cluster` VARCHAR(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', - `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', PRIMARY KEY (`Id`) USING BTREE, UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE diff --git a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql index 29e01be9bf7..18de209a163 100644 --- a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -21,9 +21,9 @@ CREATE TABLE `ServiceRegistry` ( `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', - `Cluster` VARCHAR(64) NOT NULL COMMENT '标签,可以用来标识apollo.cluster或者网络分区', - `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', PRIMARY KEY (`Id`) USING BTREE, UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE From bcc5575b4739ea181e43b47171e82455c303e8c0 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 22:29:22 +0800 Subject: [PATCH 12/31] fix test fail --- apollo-biz/src/test/resources/sql/clean.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/apollo-biz/src/test/resources/sql/clean.sql b/apollo-biz/src/test/resources/sql/clean.sql index edbb682a2ae..57e3344fdc3 100644 --- a/apollo-biz/src/test/resources/sql/clean.sql +++ b/apollo-biz/src/test/resources/sql/clean.sql @@ -25,4 +25,3 @@ DELETE FROM releasemessage; DELETE FROM releasehistory; DELETE FROM namespacelock; DELETE FROM `commit`; -DELETE FROM `Registry`; From 98b55f7395864acb087a34619e8541649a1e0243 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 22:31:42 +0800 Subject: [PATCH 13/31] Update apolloconfigdb.sql --- scripts/sql/apolloconfigdb.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index 6b695fdad78..273e007fd30 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -411,10 +411,10 @@ CREATE TABLE `AccessKey` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; -# Dump of table registry +# Dump of table serviceregistry # ------------------------------------------------------------ -DROP TABLE IF EXISTS `Registry`; +DROP TABLE IF EXISTS `ServiceRegistry`; CREATE TABLE `ServiceRegistry` ( `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', From e6de6ae558dec9d90d40abedd35653a0be2d2049 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 10 Oct 2022 22:43:21 +0800 Subject: [PATCH 14/31] refactor: split heartbeat and deregister --- ...polloServiceRegistryAutoConfiguration.java | 17 ++++- ...RegistryDeregisterApplicationListener.java | 67 +++++++++++++++++++ ...ceRegistryHeartbeatApplicationRunner.java} | 32 ++------- 3 files changed, 87 insertions(+), 29 deletions(-) create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java rename apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/{ApolloServiceRegistryApplicationRunner.java => ApolloServiceRegistryHeartbeatApplicationRunner.java} (74%) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfiguration.java index b3445b18aa2..628c8237f52 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfiguration.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfiguration.java @@ -18,7 +18,8 @@ import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistry; import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistryImpl; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryApplicationRunner; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryDeregisterApplicationListener; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryHeartbeatApplicationRunner; import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; @@ -49,10 +50,20 @@ public DatabaseServiceRegistry databaseServiceRegistry( @Bean @ConditionalOnMissingBean - public ApolloServiceRegistryApplicationRunner apolloServiceRegistryApplicationRunner( + public ApolloServiceRegistryHeartbeatApplicationRunner apolloServiceRegistryHeartbeatApplicationRunner( ApolloServiceRegistryProperties registration, DatabaseServiceRegistry serviceRegistry ) { - return new ApolloServiceRegistryApplicationRunner(registration, serviceRegistry); + return new ApolloServiceRegistryHeartbeatApplicationRunner(registration, serviceRegistry); } + + @Bean + @ConditionalOnMissingBean + public ApolloServiceRegistryDeregisterApplicationListener apolloServiceRegistryDeregisterApplicationListener( + ApolloServiceRegistryProperties registration, + DatabaseServiceRegistry serviceRegistry + ) { + return new ApolloServiceRegistryDeregisterApplicationListener(registration, serviceRegistry); + } + } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java new file mode 100644 index 00000000000..0677e6b6919 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java @@ -0,0 +1,67 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration.support; + +import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; + +/** + * remove self before shutdown + */ +public class ApolloServiceRegistryDeregisterApplicationListener + implements ApplicationListener { + + private static final Logger log = LoggerFactory + .getLogger(ApolloServiceRegistryDeregisterApplicationListener.class); + private final ApolloServiceRegistryProperties registration; + + private final DatabaseServiceRegistry serviceRegistry; + + public ApolloServiceRegistryDeregisterApplicationListener( + ApolloServiceRegistryProperties registration, DatabaseServiceRegistry serviceRegistry) { + this.registration = registration; + this.serviceRegistry = serviceRegistry; + } + + @Override + public void onApplicationEvent(ContextClosedEvent event) { + this.deregister(); + } + + private void deregister() { + try { + this.serviceRegistry.deregister(this.registration); + log.info( + "deregister success, '{}' uri '{}', label '{}'", + this.registration.getServiceName(), + this.registration.getUri(), + this.registration.getCluster() + ); + } catch (Exception e) { + log.error( + "deregister fail, '{}' uri '{}', label '{}'", + this.registration.getServiceName(), + this.registration.getUri(), + this.registration.getCluster(), + e + ); + } + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java similarity index 74% rename from apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java index 66c9e3a986b..e6509460312 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java @@ -17,22 +17,23 @@ package com.ctrip.framework.apollo.biz.registry.configuration.support; import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistry; -import com.ctrip.framework.apollo.biz.registry.ServiceInstance; import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; -public class ApolloServiceRegistryApplicationRunner +/** + * send heartbeat on runtime. + */ +public class ApolloServiceRegistryHeartbeatApplicationRunner implements ApplicationRunner { private static final Logger log = LoggerFactory - .getLogger(ApolloServiceRegistryApplicationRunner.class); + .getLogger(ApolloServiceRegistryHeartbeatApplicationRunner.class); private final ApolloServiceRegistryProperties registration; @@ -43,7 +44,7 @@ public class ApolloServiceRegistryApplicationRunner */ private final ScheduledExecutorService heartbeatScheduledExecutorService; - public ApolloServiceRegistryApplicationRunner( + public ApolloServiceRegistryHeartbeatApplicationRunner( ApolloServiceRegistryProperties registration, DatabaseServiceRegistry serviceRegistry ) { @@ -69,27 +70,6 @@ public void run(ApplicationArguments args) throws Exception { TimeUnit.SECONDS); } - @PreDestroy - private void deregister() { - try { - this.serviceRegistry.deregister(this.registration); - log.info( - "deregister success, '{}' uri '{}', label '{}'", - this.registration.getServiceName(), - this.registration.getUri(), - this.registration.getCluster() - ); - } catch (Exception e) { - log.error( - "deregister fail, '{}' uri '{}', label '{}'", - this.registration.getServiceName(), - this.registration.getUri(), - this.registration.getCluster(), - e - ); - } - } - private void heartbeat() { try { this.serviceRegistry.register(this.registration); From a1c148844c119cd2cb43c7c70d22c640d4564a91 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 19:19:00 +0800 Subject: [PATCH 15/31] fix: catch Throwable instead of catch Exception --- .../support/ApolloServiceRegistryClearApplicationRunner.java | 4 ++-- .../ApolloServiceRegistryDeregisterApplicationListener.java | 4 ++-- .../ApolloServiceRegistryHeartbeatApplicationRunner.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java index 6bfab297a16..6abb8b26758 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java @@ -64,8 +64,8 @@ private void clearUnhealthyInstances() { if (serviceRegistryListDeleted != null && !serviceRegistryListDeleted.isEmpty()) { log.info("clear {} unhealthy instances by scheduled task", serviceRegistryListDeleted.size()); } - } catch (Exception e) { - log.error("fail to clear unhealthy instances by scheduled task", e); + } catch (Throwable t) { + log.error("fail to clear unhealthy instances by scheduled task", t); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java index 0677e6b6919..7f01a238236 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java @@ -54,13 +54,13 @@ private void deregister() { this.registration.getUri(), this.registration.getCluster() ); - } catch (Exception e) { + } catch (Throwable t) { log.error( "deregister fail, '{}' uri '{}', label '{}'", this.registration.getServiceName(), this.registration.getUri(), this.registration.getCluster(), - e + t ); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java index e6509460312..46818fa4101 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java @@ -73,8 +73,8 @@ public void run(ApplicationArguments args) throws Exception { private void heartbeat() { try { this.serviceRegistry.register(this.registration); - } catch (Exception e) { - log.error("fail to send heartbeat by scheduled task", e); + } catch (Throwable t) { + log.error("fail to send heartbeat by scheduled task", t); } } From ef4fc4b2b0af85c99858bb12984ca0d9f687ca6c Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 19:23:08 +0800 Subject: [PATCH 16/31] refactor: use stream and lambda instead of for each loop filter --- .../registry/DatabaseDiscoveryClientImpl.java | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java index f0c5759639b..bea561c5170 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java @@ -21,10 +21,9 @@ import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; public class DatabaseDiscoveryClientImpl implements DatabaseDiscoveryClient { private final ServiceRegistryService serviceRegistryService; @@ -58,13 +57,9 @@ public List getInstances(String serviceName) { serviceRegistryListFiltered = filterByCluster(filterByHealthCheck, this.self.getCluster()); } - // convert - List registrationList = new ArrayList<>(serviceRegistryListFiltered.size()); - for (ServiceRegistry serviceRegistry : serviceRegistryListFiltered) { - ApolloServiceRegistryProperties registration = convert(serviceRegistry); - registrationList.add(registration); - } - return registrationList; + return serviceRegistryListFiltered.stream() + .map(DatabaseDiscoveryClientImpl::convert) + .collect(Collectors.toList()); } static ApolloServiceRegistryProperties convert(ServiceRegistry serviceRegistry) { @@ -76,16 +71,9 @@ static ApolloServiceRegistryProperties convert(ServiceRegistry serviceRegistry) } static List filterByCluster(List list, String cluster) { - if (list.isEmpty()) { - return Collections.emptyList(); - } - List listAfterFilter = new ArrayList<>(8); - for (ServiceRegistry serviceRegistry : list) { - if (Objects.equals(cluster, serviceRegistry.getCluster())) { - listAfterFilter.add(serviceRegistry); - } - } - return listAfterFilter; + return list.stream() + .filter(serviceRegistry -> Objects.equals(cluster, serviceRegistry.getCluster())) + .collect(Collectors.toList()); } } From fa0d4f7ff4944982f787fe057c4d64152e1b06e6 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 19:27:41 +0800 Subject: [PATCH 17/31] delete USING BTREE --- scripts/sql/apolloconfigdb.sql | 2 +- scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index 273e007fd30..5ce7032cd03 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -423,7 +423,7 @@ CREATE TABLE `ServiceRegistry` ( `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', - PRIMARY KEY (`Id`) USING BTREE, + PRIMARY KEY (`Id`), UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; diff --git a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql index 18de209a163..231fd5a57d1 100644 --- a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -24,7 +24,7 @@ CREATE TABLE `ServiceRegistry` ( `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', - PRIMARY KEY (`Id`) USING BTREE, + PRIMARY KEY (`Id`), UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; \ No newline at end of file From fbf7d2dc311d3f2453d9bfe10659de3bfaa8e98f Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 19:29:42 +0800 Subject: [PATCH 18/31] fix: label -> cluster --- .../ApolloServiceRegistryDeregisterApplicationListener.java | 4 ++-- .../ApolloServiceRegistryHeartbeatApplicationRunner.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java index 7f01a238236..f7c9a529b2f 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryDeregisterApplicationListener.java @@ -49,14 +49,14 @@ private void deregister() { try { this.serviceRegistry.deregister(this.registration); log.info( - "deregister success, '{}' uri '{}', label '{}'", + "deregister success, '{}' uri '{}', cluster '{}'", this.registration.getServiceName(), this.registration.getUri(), this.registration.getCluster() ); } catch (Throwable t) { log.error( - "deregister fail, '{}' uri '{}', label '{}'", + "deregister fail, '{}' uri '{}', cluster '{}'", this.registration.getServiceName(), this.registration.getUri(), this.registration.getCluster(), diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java index 46818fa4101..0cb0eac94d3 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryHeartbeatApplicationRunner.java @@ -59,7 +59,7 @@ public ApolloServiceRegistryHeartbeatApplicationRunner( public void run(ApplicationArguments args) throws Exception { // register log.info( - "register to database. '{}': uri '{}', label '{}' ", + "register to database. '{}': uri '{}', cluster '{}' ", this.registration.getServiceName(), this.registration.getUri(), this.registration.getCluster() From 5d57924638cad1c12153eeb8bf9faa263efe4881 Mon Sep 17 00:00:00 2001 From: wxq Date: Fri, 14 Oct 2022 21:09:03 +0800 Subject: [PATCH 19/31] Update scripts/sql/apolloconfigdb.sql Co-authored-by: Jason Song --- scripts/sql/apolloconfigdb.sql | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index 5ce7032cd03..ce196f83549 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -417,15 +417,15 @@ CREATE TABLE `AccessKey` ( DROP TABLE IF EXISTS `ServiceRegistry`; CREATE TABLE `ServiceRegistry` ( - `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', - `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', - `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', - `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', - `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, - INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; From 5bb73d1795e3ae96310a933044b9283d28938e9d Mon Sep 17 00:00:00 2001 From: wxq Date: Fri, 14 Oct 2022 21:09:14 +0800 Subject: [PATCH 20/31] Update scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql Co-authored-by: Jason Song --- .../v210-v220/apolloconfigdb-v210-v220.sql | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql index 231fd5a57d1..9351a47bea7 100644 --- a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -18,13 +18,13 @@ Use ApolloConfigDB; CREATE TABLE `ServiceRegistry` ( - `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', - `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', - `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', - `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', - `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) USING BTREE, - INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) USING BTREE + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; \ No newline at end of file From 16f237de22ea34e37b53d819ad55df0d75d8ad50 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:21:47 +0800 Subject: [PATCH 21/31] test: add bean exist check --- ...gistryAutoConfigurationNotEnabledTest.java | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfigurationNotEnabledTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfigurationNotEnabledTest.java index f93aac28b83..0efe88e6fa5 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfigurationNotEnabledTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceRegistryAutoConfigurationNotEnabledTest.java @@ -16,10 +16,25 @@ */ package com.ctrip.framework.apollo.biz.registry.configuration; +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClient; +import com.ctrip.framework.apollo.biz.registry.DatabaseServiceRegistry; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryClearApplicationRunner; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryDeregisterApplicationListener; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryHeartbeatApplicationRunner; +import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; +/** + * ensure that this feature, i.e. database discovery won't cause configservice or adminservice + * startup fail when it doesn't enable. + */ @SpringBootTest @ContextConfiguration(classes = { ApolloServiceRegistryAutoConfiguration.class, @@ -27,8 +42,26 @@ }) class ApolloServiceRegistryAutoConfigurationNotEnabledTest { + @Autowired + private ApplicationContext context; + + + private void assertNoSuchBean(Class requiredType) { + Assertions.assertThrows( + NoSuchBeanDefinitionException.class, + () -> context.getBean(requiredType) + ); + } + @Test - void load() { - // do nothing + void ensureNoSuchBeans() { + assertNoSuchBean(ServiceRegistryRepository.class); + assertNoSuchBean(ServiceRegistryService.class); + assertNoSuchBean(DatabaseServiceRegistry.class); + assertNoSuchBean(ApolloServiceRegistryHeartbeatApplicationRunner.class); + assertNoSuchBean(ApolloServiceRegistryDeregisterApplicationListener.class); + + assertNoSuchBean(DatabaseDiscoveryClient.class); + assertNoSuchBean(ApolloServiceRegistryClearApplicationRunner.class); } } \ No newline at end of file From a9a05b92fc63acb40f498301021f3c3daaaee291 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:40:06 +0800 Subject: [PATCH 22/31] feat: add Metadata column --- .../ctrip/framework/apollo/biz/registry/ServiceInstance.java | 4 +--- scripts/sql/apolloconfigdb.sql | 3 ++- scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java index f02c185e0ca..7caad07b90d 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java @@ -42,10 +42,8 @@ public interface ServiceInstance { /** * Tag a service instance for service discovery. *

- * It's a little hard to persist the key / value pair metadata to database, - * so use cluster instead of metadata for service discovery. + * so use cluster for service discovery. * - * @see org.springframework.cloud.client.ServiceInstance#getMetadata() * @return The cluster of the service instance. */ String getCluster(); diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index ce196f83549..54bec8e6cc9 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -421,10 +421,11 @@ CREATE TABLE `ServiceRegistry` ( `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', PRIMARY KEY (`Id`), - UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; diff --git a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql index 9351a47bea7..78e686abd8b 100644 --- a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -22,9 +22,10 @@ CREATE TABLE `ServiceRegistry` ( `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', `DataChange_CreatedTime` TIMESTAMP NOT NULL COMMENT '创建时间', `DataChange_LastTime` TIMESTAMP NOT NULL COMMENT '最后修改时间', PRIMARY KEY (`Id`), - UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`) + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; \ No newline at end of file From c61f8ef31ba083d967964925f71eb6692af17046 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:47:10 +0800 Subject: [PATCH 23/31] refactor: only use cluster in DatabaseDiscoveryClientImpl --- .../apollo/biz/registry/DatabaseDiscoveryClientImpl.java | 8 ++++---- .../ApolloServiceDiscoveryAutoConfiguration.java | 2 +- .../biz/registry/DatabaseDiscoveryClientImplTest.java | 4 +--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java index bea561c5170..f74b000a0cc 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImpl.java @@ -30,15 +30,15 @@ public class DatabaseDiscoveryClientImpl implements DatabaseDiscoveryClient { private final ApolloServiceDiscoveryProperties discoveryProperties; - private final ServiceInstance self; + private final String cluster; public DatabaseDiscoveryClientImpl( ServiceRegistryService serviceRegistryService, ApolloServiceDiscoveryProperties discoveryProperties, - ServiceInstance self) { + String cluster) { this.serviceRegistryService = serviceRegistryService; this.discoveryProperties = discoveryProperties; - this.self = self; + this.cluster = cluster; } /** @@ -54,7 +54,7 @@ public List getInstances(String serviceName) { this.serviceRegistryService.findByServiceNameDataChangeLastModifiedTimeGreaterThan( serviceName, healthTime ); - serviceRegistryListFiltered = filterByCluster(filterByHealthCheck, this.self.getCluster()); + serviceRegistryListFiltered = filterByCluster(filterByHealthCheck, this.cluster); } return serviceRegistryListFiltered.stream() diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java index c3f7a3eb615..df4bb52327c 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java @@ -46,7 +46,7 @@ public DatabaseDiscoveryClient databaseDiscoveryClient( ServiceRegistryService serviceRegistryService ) { return new DatabaseDiscoveryClientImpl( - serviceRegistryService, discoveryProperties, selfServiceInstance + serviceRegistryService, discoveryProperties, selfServiceInstance.getCluster() ); } diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java index c79fad79e57..1e20c6a03df 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java @@ -57,12 +57,10 @@ void getInstances() { .thenReturn(serviceRegistryList); } - ServiceInstance serviceInstance = Mockito.mock(ServiceInstance.class); - Mockito.when(serviceInstance.getCluster()).thenReturn("1"); DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( serviceRegistryService, new ApolloServiceDiscoveryProperties(), - serviceInstance + "1" ); List serviceInstances = discoveryClient.getInstances(serviceName); From ad2a1f03589b9989eaa87a66834df12ddcffb629 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:14:33 +0800 Subject: [PATCH 24/31] feat: add metadata config in code -Dapollo.service.registry.metadata.a=1 -Dapollo.service.registry.metadata.isAutoRegister=true generate {"a":"1","isAutoRegister":"true"} in database --- .../biz/entity/JpaMapFieldJsonConverter.java | 47 +++++++++++++++++++ .../apollo/biz/entity/ServiceRegistry.java | 16 +++++++ .../registry/DatabaseServiceRegistryImpl.java | 13 +++-- .../apollo/biz/registry/ServiceInstance.java | 8 ++++ .../ApolloServiceRegistryProperties.java | 13 +++++ .../biz/service/ServiceRegistryService.java | 4 +- .../DatabaseDiscoveryClientImplTest.java | 2 + 7 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverter.java diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverter.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverter.java new file mode 100644 index 00000000000..c8f06699d14 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverter.java @@ -0,0 +1,47 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.entity; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +@Converter(autoApply = true) +class JpaMapFieldJsonConverter implements AttributeConverter, String> { + + private static final Gson GSON = new Gson(); + + private static final TypeToken> TYPE_TOKEN = new TypeToken>() { + }; + + @SuppressWarnings("unchecked") + private static final Type TYPE = TYPE_TOKEN.getType(); + + @Override + public String convertToDatabaseColumn(Map attribute) { + return GSON.toJson(attribute); + } + + @Override + public Map convertToEntityAttribute(String dbData) { + return GSON.fromJson(dbData, TYPE); + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/ServiceRegistry.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/ServiceRegistry.java index 74482c3c844..9182ae38d1a 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/ServiceRegistry.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/entity/ServiceRegistry.java @@ -18,7 +18,10 @@ import com.ctrip.framework.apollo.biz.registry.ServiceInstance; import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; import javax.persistence.Column; +import javax.persistence.Convert; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -55,6 +58,10 @@ public class ServiceRegistry { @Column(name = "Cluster", nullable = false) private String cluster; + @Column(name = "Metadata", nullable = false) + @Convert(converter = JpaMapFieldJsonConverter.class) + private Map metadata; + @Column(name = "DataChange_CreatedTime", nullable = false) private LocalDateTime dataChangeCreatedTime; @@ -81,6 +88,7 @@ public String toString() { ", serviceName='" + serviceName + '\'' + ", uri='" + uri + '\'' + ", cluster='" + cluster + '\'' + + ", metadata='" + metadata + '\'' + ", dataChangeCreatedTime=" + dataChangeCreatedTime + ", dataChangeLastModifiedTime=" + dataChangeLastModifiedTime + '}'; @@ -118,6 +126,14 @@ public void setCluster(String cluster) { this.cluster = cluster; } + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + public LocalDateTime getDataChangeCreatedTime() { return dataChangeCreatedTime; } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java index 55ab714fffd..6ec0b6fa0e2 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseServiceRegistryImpl.java @@ -29,19 +29,22 @@ public DatabaseServiceRegistryImpl( this.serviceRegistryService = serviceRegistryService; } - public void register(ServiceInstance instance) { + static ServiceRegistry convert(ServiceInstance instance) { ServiceRegistry serviceRegistry = new ServiceRegistry(); serviceRegistry.setServiceName(instance.getServiceName()); serviceRegistry.setUri(instance.getUri().toString()); serviceRegistry.setCluster(instance.getCluster()); + serviceRegistry.setMetadata(instance.getMetadata()); + return serviceRegistry; + } + + public void register(ServiceInstance instance) { + ServiceRegistry serviceRegistry = convert(instance); this.serviceRegistryService.saveIfNotExistByServiceNameAndUri(serviceRegistry); } public void deregister(ServiceInstance instance) { - ServiceRegistry serviceRegistry = new ServiceRegistry(); - serviceRegistry.setServiceName(instance.getServiceName()); - serviceRegistry.setUri(instance.getUri().toString()); - serviceRegistry.setCluster(instance.getCluster()); + ServiceRegistry serviceRegistry = convert(instance); this.serviceRegistryService.delete(serviceRegistry); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java index 7caad07b90d..b9e225f756a 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/ServiceInstance.java @@ -17,6 +17,7 @@ package com.ctrip.framework.apollo.biz.registry; import java.net.URI; +import java.util.Map; /** * @see org.springframework.cloud.client.ServiceInstance @@ -35,6 +36,7 @@ public interface ServiceInstance { *

  • http://10.240.12.34:8080/
  • *
  • http://47.56.23.34:8080/
  • * + * * @return The service URI address. */ URI getUri(); @@ -47,4 +49,10 @@ public interface ServiceInstance { * @return The cluster of the service instance. */ String getCluster(); + + /** + * @return The key / value pair metadata associated with the service instance. + * @see org.springframework.cloud.client.ServiceInstance#getMetadata() + */ + Map getMetadata(); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java index 549ed591f1d..8652795dd7e 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryProperties.java @@ -18,6 +18,8 @@ import com.ctrip.framework.apollo.biz.registry.ServiceInstance; import java.net.URI; +import java.util.HashMap; +import java.util.Map; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -57,6 +59,8 @@ public class ApolloServiceRegistryProperties implements ServiceInstance { */ private String cluster; + private Map metadata = new HashMap<>(8); + /** * heartbeat to registry in second. */ @@ -123,6 +127,15 @@ public void setCluster(String cluster) { this.cluster = cluster; } + @Override + public Map getMetadata() { + return this.metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + public long getHeartbeatIntervalInSecond() { return heartbeatIntervalInSecond; } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java index 441628bc894..e841db1eb1e 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ServiceRegistryService.java @@ -39,9 +39,9 @@ public ServiceRegistry saveIfNotExistByServiceNameAndUri(ServiceRegistry service serviceRegistrySaved.setDataChangeCreatedTime(now); serviceRegistrySaved.setDataChangeLastModifiedTime(now); } else { - // update cluster + // update serviceRegistrySaved.setCluster(serviceRegistry.getCluster()); - + serviceRegistrySaved.setMetadata(serviceRegistry.getMetadata()); serviceRegistrySaved.setDataChangeLastModifiedTime(now); } return this.repository.save(serviceRegistrySaved); diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java index 1e20c6a03df..8d8647bcf88 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java @@ -25,6 +25,7 @@ import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import java.time.LocalDateTime; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -36,6 +37,7 @@ static ServiceRegistry newRegistry(String serviceName, String uri, String cluste serviceRegistry.setServiceName(serviceName); serviceRegistry.setUri(uri); serviceRegistry.setCluster(cluster); + serviceRegistry.setMetadata(new HashMap<>()); serviceRegistry.setDataChangeCreatedTime(LocalDateTime.now()); serviceRegistry.setDataChangeLastModifiedTime(LocalDateTime.now()); return serviceRegistry; From 6fa748f61df9a85c8f25883ed702e982f5a70349 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Mon, 17 Oct 2022 23:32:02 +0800 Subject: [PATCH 25/31] test: add tests of registry --- ...ServiceRegistryClearApplicationRunner.java | 2 +- .../entity/JpaMapFieldJsonConverterTest.java | 93 ++++++++++ .../DatabaseDiscoveryClientImplTest.java | 49 ++++- .../DatabaseDiscoveryIntegrationTest.java | 174 ++++++++++++++++++ ...ClearApplicationRunnerIntegrationTest.java | 101 ++++++++++ .../resources/json/converter/element.1.json | 1 + .../resources/json/converter/element.2.json | 1 + 7 files changed, 413 insertions(+), 8 deletions(-) create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverterTest.java create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunnerIntegrationTest.java create mode 100644 apollo-biz/src/test/resources/json/converter/element.1.json create mode 100644 apollo-biz/src/test/resources/json/converter/element.2.json diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java index 6abb8b26758..afa5cb99cbf 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunner.java @@ -57,7 +57,7 @@ public ApolloServiceRegistryClearApplicationRunner( /** * clear instance */ - private void clearUnhealthyInstances() { + void clearUnhealthyInstances() { try { List serviceRegistryListDeleted = this.serviceRegistryService.deleteTimeBefore(Duration.ofDays(1)); diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverterTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverterTest.java new file mode 100644 index 00000000000..80f7d58158d --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/entity/JpaMapFieldJsonConverterTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.entity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; + +class JpaMapFieldJsonConverterTest { + + private final JpaMapFieldJsonConverter converter = new JpaMapFieldJsonConverter(); + + static String readAllContentOf(String path) throws IOException { + ClassPathResource classPathResource = new ClassPathResource(path); + byte[] bytes = Files.readAllBytes(classPathResource.getFile().toPath()); + return new String(bytes, StandardCharsets.UTF_8); + } + + @Test + void convertToDatabaseColumn_null() { + assertEquals("null", this.converter.convertToDatabaseColumn(null)); + } + + @Test + void convertToDatabaseColumn_empty() { + assertEquals("{}", this.converter.convertToDatabaseColumn(new HashMap<>(4))); + } + + @Test + void convertToDatabaseColumn_oneElement() throws IOException { + Map map = new HashMap<>(8); + map.put("a", "1"); + + String expected = readAllContentOf("json/converter/element.1.json"); + assertEquals(expected, this.converter.convertToDatabaseColumn(map)); + } + + @Test + void convertToDatabaseColumn_twoElement() throws IOException { + Map map = new HashMap<>(8); + map.put("a", "1"); + map.put("disableCheck", "true"); + + String expected = readAllContentOf("json/converter/element.2.json"); + assertEquals(expected, this.converter.convertToDatabaseColumn(map)); + } + + @Test + void convertToEntityAttribute_null() { + assertNull(this.converter.convertToEntityAttribute(null)); + assertNull(this.converter.convertToEntityAttribute("null")); + } + + @Test + void convertToEntityAttribute_null_oneElement() throws IOException { + Map map = new HashMap<>(8); + map.put("a", "1"); + + String content = readAllContentOf("json/converter/element.1.json"); + assertEquals(map, this.converter.convertToEntityAttribute(content)); + } + + @Test + void convertToEntityAttribute_null_twoElement() throws IOException { + Map map = new HashMap<>(8); + map.put("a", "1"); + map.put("disableCheck", "true"); + + String content = readAllContentOf("json/converter/element.2.json"); + assertEquals(map, this.converter.convertToEntityAttribute(content)); + } +} \ No newline at end of file diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java index 8d8647bcf88..6bd1107e073 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientImplTest.java @@ -25,6 +25,7 @@ import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import java.time.LocalDateTime; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import org.junit.jupiter.api.Test; @@ -32,29 +33,37 @@ class DatabaseDiscoveryClientImplTest { - static ServiceRegistry newRegistry(String serviceName, String uri, String cluster) { + private static ServiceRegistry newServiceRegistry( + String serviceName, String uri, String cluster, LocalDateTime dataChangeLastModifiedTime + ) { ServiceRegistry serviceRegistry = new ServiceRegistry(); serviceRegistry.setServiceName(serviceName); serviceRegistry.setUri(uri); serviceRegistry.setCluster(cluster); serviceRegistry.setMetadata(new HashMap<>()); serviceRegistry.setDataChangeCreatedTime(LocalDateTime.now()); - serviceRegistry.setDataChangeLastModifiedTime(LocalDateTime.now()); + serviceRegistry.setDataChangeLastModifiedTime(dataChangeLastModifiedTime); return serviceRegistry; } + private static ServiceRegistry newServiceRegistry(String serviceName, String uri, + String cluster) { + return newServiceRegistry(serviceName, uri, cluster, LocalDateTime.now()); + } + @Test - void getInstances() { + void getInstances_filterByCluster() { final String serviceName = "a-service"; ServiceRegistryService serviceRegistryService = Mockito.mock(ServiceRegistryService.class); { List serviceRegistryList = Arrays.asList( - newRegistry(serviceName, "http://localhost:8081/", "1"), - newRegistry("b-service", "http://localhost:8082/", "2"), - newRegistry("c-service", "http://localhost:8082/", "3") + newServiceRegistry(serviceName, "http://localhost:8081/", "1"), + newServiceRegistry("b-service", "http://localhost:8082/", "2"), + newServiceRegistry("c-service", "http://localhost:8082/", "3") ); Mockito.when( - serviceRegistryService.findByServiceNameDataChangeLastModifiedTimeGreaterThan(eq(serviceName), + serviceRegistryService.findByServiceNameDataChangeLastModifiedTimeGreaterThan( + eq(serviceName), any(LocalDateTime.class))) .thenReturn(serviceRegistryList); } @@ -70,4 +79,30 @@ void getInstances() { assertEquals(serviceName, serviceInstances.get(0).getServiceName()); assertEquals("1", serviceInstances.get(0).getCluster()); } + + @Test + void getInstances_filterByHealthCheck() { + final String serviceName = "a-service"; + ServiceRegistryService serviceRegistryService = Mockito.mock(ServiceRegistryService.class); + + ServiceRegistry healthy = newServiceRegistry(serviceName, "http://localhost:8081/", "1", + LocalDateTime.now()); + Mockito.when( + serviceRegistryService.findByServiceNameDataChangeLastModifiedTimeGreaterThan( + eq(serviceName), + any(LocalDateTime.class))) + .thenReturn(Collections.singletonList(healthy)); + + DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( + serviceRegistryService, + new ApolloServiceDiscoveryProperties(), + "1" + ); + + List serviceInstances = discoveryClient.getInstances(serviceName); + assertEquals(1, serviceInstances.size()); + assertEquals(serviceName, serviceInstances.get(0).getServiceName()); + assertEquals("http://localhost:8081/", serviceInstances.get(0).getUri().toString()); + assertEquals("1", serviceInstances.get(0).getCluster()); + } } \ No newline at end of file diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java new file mode 100644 index 00000000000..9e40721097e --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java @@ -0,0 +1,174 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.ctrip.framework.apollo.biz.AbstractIntegrationTest; +import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceDiscoveryAutoConfiguration; +import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceRegistryAutoConfiguration; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; +import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; +import java.util.List; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; + +@TestPropertySource( + properties = { + "apollo.service.registry.enabled=true", + "apollo.service.registry.cluster=default", + "apollo.service.discovery.enabled=true", + "spring.application.name=for-test-service", + "server.port=10000", + } +) +@ContextConfiguration(classes = { + ApolloServiceRegistryAutoConfiguration.class, + ApolloServiceDiscoveryAutoConfiguration.class, +}) +@EnableJpaRepositories(basePackageClasses = ServiceRegistryRepository.class) +public class DatabaseDiscoveryIntegrationTest extends AbstractIntegrationTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private DatabaseServiceRegistry serviceRegistry; + + @Autowired + private DatabaseDiscoveryClient discoveryClient; + + /** + * discover one after register, and delete it + */ + @Test + public void registerThenDiscoveryThenDelete() { + // register it + String serviceName = "a-service"; + String uri = "http://192.168.1.20:8080/"; + String cluster = "default"; + ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); + instance.setServiceName(serviceName); + instance.setUri(uri); + instance.setCluster(cluster); + this.serviceRegistry.register(instance); + + // find it + List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(1, serviceInstances.size()); + ServiceInstance actual = serviceInstances.get(0); + assertEquals(serviceName, actual.getServiceName()); + assertEquals(uri, actual.getUri().toString()); + assertEquals(cluster, actual.getCluster()); + assertEquals(0, actual.getMetadata().size()); + + // delete it + this.serviceRegistry.deregister(instance); + // find none + assertEquals(0, this.discoveryClient.getInstances(serviceName).size()); + } + + /** + * diff cluster so cannot be discover + */ + @Test + public void registerThenDiscoveryNone() { + // register it + String serviceName = "b-service"; + String uri = "http://192.168.1.20:8080/"; + String cluster = "cannot-be-discovery"; + ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); + instance.setServiceName(serviceName); + instance.setUri(uri); + instance.setCluster(cluster); + this.serviceRegistry.register(instance); + + // find none + List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(0, serviceInstances.size()); + } + + @Test + public void registerTwice() { + + String serviceName = "c-service"; + String uri = "http://192.168.1.20:8080/"; + String cluster = "default"; + ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); + instance.setServiceName(serviceName); + instance.setUri(uri); + instance.setCluster(cluster); + + // register it + this.serviceRegistry.register(instance); + // register again + this.serviceRegistry.register(instance); + + // only discover one + List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(1, serviceInstances.size()); + } + + @Test + public void registerTwoInstancesThenDeleteOne() { + final String serviceName = "d-service"; + final String cluster = "default"; + { + String uri = "http://192.168.1.20:8080/"; + ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); + instance.setServiceName(serviceName); + instance.setUri(uri); + instance.setCluster(cluster); + this.serviceRegistry.register(instance); + } + { + String uri = "http://192.168.1.20:10000/"; + ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); + instance.setServiceName(serviceName); + instance.setUri(uri); + instance.setCluster(cluster); + this.serviceRegistry.register(instance); + } + + final List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(2, serviceInstances.size()); + + for (ServiceInstance serviceInstance : serviceInstances) { + assertEquals(serviceName, serviceInstance.getServiceName()); + assertEquals(cluster, serviceInstance.getCluster()); + assertEquals(0, serviceInstance.getMetadata().size()); + } + + // delete one + { + String uri = "http://192.168.1.20:10000/"; + ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); + instance.setServiceName(serviceName); + instance.setUri(uri); + instance.setCluster(cluster); + this.serviceRegistry.deregister(instance); + } + + assertEquals(1, this.discoveryClient.getInstances(serviceName).size()); + assertEquals("http://192.168.1.20:8080/", + this.discoveryClient.getInstances(serviceName).get(0).getUri().toString()); + } +} diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunnerIntegrationTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunnerIntegrationTest.java new file mode 100644 index 00000000000..50fedba6899 --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/configuration/support/ApolloServiceRegistryClearApplicationRunnerIntegrationTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry.configuration.support; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.ctrip.framework.apollo.biz.AbstractIntegrationTest; +import com.ctrip.framework.apollo.biz.entity.ServiceRegistry; +import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceDiscoveryAutoConfiguration; +import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceRegistryAutoConfiguration; +import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; + +@TestPropertySource( + properties = { + "apollo.service.registry.enabled=true", + "apollo.service.registry.cluster=default", + "apollo.service.discovery.enabled=true", + "spring.application.name=for-test-service", + "server.port=10000", + } +) +@ContextConfiguration(classes = { + ApolloServiceRegistryAutoConfiguration.class, + ApolloServiceDiscoveryAutoConfiguration.class, +}) +@EnableJpaRepositories(basePackageClasses = ServiceRegistryRepository.class) +public class ApolloServiceRegistryClearApplicationRunnerIntegrationTest + extends AbstractIntegrationTest { + + @Autowired + private ServiceRegistryRepository repository; + + @Autowired + private ApolloServiceRegistryClearApplicationRunner runner; + + @Test + public void clearUnhealthyInstances() { + final String serviceName = "h-service"; + + final String healthUri = "http://10.240.11.22:8080/"; + ServiceRegistry healthy = new ServiceRegistry(); + healthy.setServiceName(serviceName); + healthy.setCluster("c-1"); + healthy.setUri(healthUri); + healthy.setDataChangeCreatedTime(LocalDateTime.now()); + healthy.setDataChangeLastModifiedTime(LocalDateTime.now()); + this.repository.save(healthy); + + LocalDateTime unhealthyTime = LocalDateTime.now().minusDays(2L); + ServiceRegistry unhealthy = new ServiceRegistry(); + unhealthy.setServiceName("h-service"); + unhealthy.setCluster("c-2"); + unhealthy.setUri("http://10.240.33.44:9090/"); + unhealthy.setDataChangeCreatedTime(unhealthyTime); + unhealthy.setDataChangeLastModifiedTime(unhealthyTime); + this.repository.save(unhealthy); + + { + List serviceRegistryList = this.repository.findByServiceNameAndDataChangeLastModifiedTimeGreaterThan( + serviceName, + LocalDateTime.now().minusDays(3L) + ); + assertEquals(2, serviceRegistryList.size()); + } + + runner.clearUnhealthyInstances(); + + { + List serviceRegistryList = this.repository.findByServiceNameAndDataChangeLastModifiedTimeGreaterThan( + serviceName, + LocalDateTime.now().minusDays(3L) + ); + assertEquals(1, serviceRegistryList.size()); + ServiceRegistry registry = serviceRegistryList.get(0); + assertEquals(serviceName, registry.getServiceName()); + assertEquals(healthUri, registry.getUri()); + } + } + +} \ No newline at end of file diff --git a/apollo-biz/src/test/resources/json/converter/element.1.json b/apollo-biz/src/test/resources/json/converter/element.1.json new file mode 100644 index 00000000000..6e8023fb39e --- /dev/null +++ b/apollo-biz/src/test/resources/json/converter/element.1.json @@ -0,0 +1 @@ +{"a":"1"} \ No newline at end of file diff --git a/apollo-biz/src/test/resources/json/converter/element.2.json b/apollo-biz/src/test/resources/json/converter/element.2.json new file mode 100644 index 00000000000..de2bd72bb59 --- /dev/null +++ b/apollo-biz/src/test/resources/json/converter/element.2.json @@ -0,0 +1 @@ +{"a":"1","disableCheck":"true"} \ No newline at end of file From 9219f3402b975a13f09a23f0f1cd802a40bc59ea Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Thu, 20 Oct 2022 23:10:07 +0800 Subject: [PATCH 26/31] docs: Enable database-discovery to replace built-in eureka --- .../distributed-deployment-guide.md | 18 ++++++++++++++++++ .../distributed-deployment-guide.md | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/docs/en/deployment/distributed-deployment-guide.md b/docs/en/deployment/distributed-deployment-guide.md index 46cd1ad43f6..8763e67ee1d 100644 --- a/docs/en/deployment/distributed-deployment-guide.md +++ b/docs/en/deployment/distributed-deployment-guide.md @@ -583,6 +583,24 @@ apollo.config-service.url=http://apollo-config-service apollo.admin-service.url=http://apollo-admin-service ```` +##### 2.2.1.2.11 Enable database-discovery to replace built-in eureka + +> For version 2.1.0 and above +> +> Apollo supports the use of internal database table as registry, without relying on third-party registry. + +1. Modify build.sh/build.bat and change the maven compilation commands of `config-service` and `admin-service` to +```shell +mvn clean package -Pgithub -DskipTests -pl apollo-configservice,apollo-adminservice -am -Dapollo_profile=github,database-discovery -Dspring_datasource_url=$apollo_config_db_url -Dspring_datasource_username=$apollo_config_db_username -Dspring_datasource_password=$apollo_config_db_password +``` + +2. In multi-room deployments, if you want apollo client only read Config Service in the same room, +you can add a property in `config/application-github.properties` of the Config Service and Admin Service installation package +```properties +apollo.service.registry.cluster=same name with apollo Cluster +``` + + ### 2.2.2 Deploy Apollo server #### 2.2.2.1 Deploy apollo-configservice diff --git a/docs/zh/deployment/distributed-deployment-guide.md b/docs/zh/deployment/distributed-deployment-guide.md index cc91d1200ca..8ed8c226fad 100644 --- a/docs/zh/deployment/distributed-deployment-guide.md +++ b/docs/zh/deployment/distributed-deployment-guide.md @@ -544,6 +544,25 @@ INSERT INTO `ApolloConfigDB`.`ServerConfig` (`Key`, `Value`, `Comment`) VALUES ( apollo.config-service.url=http://apollo-config-service apollo.admin-service.url=http://apollo-admin-service ``` + +##### 2.2.1.2.11 启用database-discovery替换内置eureka + +> For version 2.1.0 and above +> +> Apollo支持使用内部的数据库表作为注册中心,不依赖第三方的注册中心 + +1. 修改build.sh/build.bat,将`config-service`和`admin-service`的maven编译命令更改为 +```shell +mvn clean package -Pgithub -DskipTests -pl apollo-configservice,apollo-adminservice -am -Dapollo_profile=github,database-discovery -Dspring_datasource_url=$apollo_config_db_url -Dspring_datasource_username=$apollo_config_db_username -Dspring_datasource_password=$apollo_config_db_password +``` + +2. 在多机房部署时, +如果你需要apollo客户端只读取同机房内的Config Service, +你可以在Config Service和Admin Service安装包中`config/application-github.properties`新增一条配置 +```properties +apollo.service.registry.cluster=与apollo的Cluster同名 +``` + ### 2.2.2 部署Apollo服务端 #### 2.2.2.1 部署apollo-configservice From 1baec929d1a09b196fc2a7d65099674860e569ec Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Thu, 20 Oct 2022 23:10:09 +0800 Subject: [PATCH 27/31] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 2fb88508c9e..e7041f0f223 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,6 +33,7 @@ Apollo 2.1.0 * [Move apollo-core, apollo-client, apollo-mockserver, apollo-openapi and apollo-client-config-data to apollo-java repo](https://github.com/apolloconfig/apollo/pull/4594) * [fix get the openapi interface that contains namespace information for deleted items](https://github.com/apolloconfig/apollo/pull/4596) * [A user-friendly config management page for apollo portal](https://github.com/apolloconfig/apollo/pull/4592) +* [feat: support use database as a registry](https://github.com/apolloconfig/apollo/pull/4595) ------------------ All issues and pull requests are [here](https://github.com/apolloconfig/apollo/milestone/11?closed=1) \ No newline at end of file From 4c3e409426da250ee62e95ad39fbf639f209772a Mon Sep 17 00:00:00 2001 From: wxq Date: Sat, 22 Oct 2022 19:35:12 +0800 Subject: [PATCH 28/31] room -> cluster Co-authored-by: Jason Song --- docs/en/deployment/distributed-deployment-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/deployment/distributed-deployment-guide.md b/docs/en/deployment/distributed-deployment-guide.md index 8763e67ee1d..7ec6ff53958 100644 --- a/docs/en/deployment/distributed-deployment-guide.md +++ b/docs/en/deployment/distributed-deployment-guide.md @@ -594,7 +594,7 @@ apollo.admin-service.url=http://apollo-admin-service mvn clean package -Pgithub -DskipTests -pl apollo-configservice,apollo-adminservice -am -Dapollo_profile=github,database-discovery -Dspring_datasource_url=$apollo_config_db_url -Dspring_datasource_username=$apollo_config_db_username -Dspring_datasource_password=$apollo_config_db_password ``` -2. In multi-room deployments, if you want apollo client only read Config Service in the same room, +2. In multi-cluster deployments, if you want apollo client only read Config Service in the same cluster, you can add a property in `config/application-github.properties` of the Config Service and Admin Service installation package ```properties apollo.service.registry.cluster=same name with apollo Cluster From 8eea742c3d07bd130f1a87005d01d97c9fc5ea8a Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Sat, 22 Oct 2022 19:36:55 +0800 Subject: [PATCH 29/31] room -> cluster --- docs/en/deployment/distributed-deployment-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/deployment/distributed-deployment-guide.md b/docs/en/deployment/distributed-deployment-guide.md index 7ec6ff53958..d4d858c6883 100644 --- a/docs/en/deployment/distributed-deployment-guide.md +++ b/docs/en/deployment/distributed-deployment-guide.md @@ -1361,7 +1361,7 @@ http://5.5.5.5:8080/eureka/,http://6.6.6.6:8080/eureka/ >Note 2: If you want to register Config Service and Admin Service to the company's unified Eureka, you can refer to [Deployment & Development FAQ - Registering Config Service and Admin Service to a separate Eureka Server](en/faq/common-issues-in-deployment-and-development-phase?id=_8-register-config-service-and-admin-service-to-a-separate-eureka-server) section ->Note 3: In multi-room deployments, you often want the config service and admin service to register only with the eureka in the same room. To achieve this, you need to use the cluster field in the `ServerConfig` table, and the config service and admin service will read the `/opt/settings/server.properties` (Mac/Linux) or `C:\opt\settings\server.properties` (Windows), and if the idc has a corresponding eureka.service.url configuration, then will only register with eureka for that server room. For example, if the config service and admin service are deployed to two IDCs, `SHAOY` and `SHAJQ`, then in order to register the services in these two server rooms only with that server room, you can add two new records in the `ServerConfig` table and fill in the `SHAOY` and `SHAJQ` server room eureka addresses respectively. If there are config service and admin service that are not deployed in `SHAOY` and `SHAJQ`, this default configuration will be used. +>Note 3: In multi-cluster deployments, you often want the config service and admin service to register only with the eureka in the same room. To achieve this, you need to use the cluster field in the `ServerConfig` table, and the config service and admin service will read the `/opt/settings/server.properties` (Mac/Linux) or `C:\opt\settings\server.properties` (Windows), and if the idc has a corresponding eureka.service.url configuration, then will only register with eureka for that server room. For example, if the config service and admin service are deployed to two IDCs, `SHAOY` and `SHAJQ`, then in order to register the services in these two server rooms only with that server room, you can add two new records in the `ServerConfig` table and fill in the `SHAOY` and `SHAJQ` server room eureka addresses respectively. If there are config service and admin service that are not deployed in `SHAOY` and `SHAJQ`, this default configuration will be used. | Key | Cluster | Value | Comment | | ------------------ | ------- | --------------------------- | ---------------------------- | From 02370fa5eda63f06085b43060d8968fb3f1884cc Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Sun, 23 Oct 2022 10:47:46 +0800 Subject: [PATCH 30/31] feat: when database fail, database-discovery still be useful. by decorator pattern, memory cache --- .../biz/registry/DatabaseDiscoveryClient.java | 2 + ...entAlwaysAddSelfInstanceDecoratorImpl.java | 84 +++++++ ...scoveryClientMemoryCacheDecoratorImpl.java | 105 +++++++++ ...olloServiceDiscoveryAutoConfiguration.java | 24 +- ...lwaysAddSelfInstanceDecoratorImplTest.java | 143 ++++++++++++ ...eryClientMemoryCacheDecoratorImplTest.java | 210 ++++++++++++++++++ .../DatabaseDiscoveryIntegrationTest.java | 68 +++--- .../biz/registry/ServiceInstanceFactory.java | 29 +++ 8 files changed, 622 insertions(+), 43 deletions(-) create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl.java create mode 100644 apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImpl.java create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImplTest.java create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImplTest.java create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/ServiceInstanceFactory.java diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java index 7ae6e2f5406..15af064f09f 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClient.java @@ -27,6 +27,8 @@ public interface DatabaseDiscoveryClient { /** * find by {@link ApolloServiceRegistryProperties#getServiceName()}, * then filter by {@link ApolloServiceRegistryProperties#getCluster()} + * + * @return empty list if there is no instance */ List getInstances(String serviceName); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl.java new file mode 100644 index 00000000000..9907fc9be35 --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl.java @@ -0,0 +1,84 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * decorator pattern + *

    + * when database crash, even cannot register self instance to database, + *

    + * this decorator will ensure return's result contains self instance. + */ +public class DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl + implements DatabaseDiscoveryClient { + + private final DatabaseDiscoveryClient delegate; + + private final ServiceInstance selfInstance; + + public DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl( + DatabaseDiscoveryClient delegate, + ServiceInstance selfInstance + ) { + this.delegate = delegate; + this.selfInstance = selfInstance; + } + + static boolean containSelf(List serviceInstances, ServiceInstance selfInstance) { + final String selfServiceName = selfInstance.getServiceName(); + final URI selfUri = selfInstance.getUri(); + final String cluster = selfInstance.getCluster(); + for (ServiceInstance serviceInstance : serviceInstances) { + if (Objects.equals(selfServiceName, serviceInstance.getServiceName())) { + if (Objects.equals(selfUri, serviceInstance.getUri())) { + if (Objects.equals(cluster, serviceInstance.getCluster())) { + return true; + } + } + } + } + return false; + } + + /** + * if the serviceName is same with self, always return self's instance + * @return never be empty list when serviceName is same with self + */ + @Override + public List getInstances(String serviceName) { + if (Objects.equals(serviceName, this.selfInstance.getServiceName())) { + List serviceInstances = this.delegate.getInstances(serviceName); + if (containSelf(serviceInstances, this.selfInstance)) { + // contains self instance already + return serviceInstances; + } + + // add self instance to result + List result = new ArrayList<>(serviceInstances.size() + 1); + result.add(this.selfInstance); + result.addAll(serviceInstances); + return result; + } else { + return this.delegate.getInstances(serviceName); + } + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImpl.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImpl.java new file mode 100644 index 00000000000..795e673caed --- /dev/null +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImpl.java @@ -0,0 +1,105 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import com.ctrip.framework.apollo.core.ServiceNameConsts; +import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * decorator pattern + *

    + * 1. use jvm memory as cache to decrease the read of database. + *

    + * 2. when database happened failure, return the cache in jvm memory. + */ +public class DatabaseDiscoveryClientMemoryCacheDecoratorImpl + implements DatabaseDiscoveryClient { + + private static final Logger log = LoggerFactory.getLogger( + DatabaseDiscoveryClientMemoryCacheDecoratorImpl.class + ); + + private final DatabaseDiscoveryClient delegate; + + private final Map> serviceName2ServiceInstances = new ConcurrentHashMap<>( + 8); + + private volatile ScheduledExecutorService scheduledExecutorService; + + private static final long SYNC_TASK_PERIOD_IN_SECOND = 5; + + public DatabaseDiscoveryClientMemoryCacheDecoratorImpl(DatabaseDiscoveryClient delegate) { + this.delegate = delegate; + } + + public void init() { + this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + ApolloThreadFactory + .create("DatabaseDiscoveryWithCache", true) + ); + scheduledExecutorService.scheduleAtFixedRate(this::updateCacheTask, + SYNC_TASK_PERIOD_IN_SECOND, SYNC_TASK_PERIOD_IN_SECOND, TimeUnit.SECONDS); + + // load them for init + try { + this.getInstances(ServiceNameConsts.APOLLO_CONFIGSERVICE); + } catch (Throwable t) { + log.error("fail to get instances of service name {}", ServiceNameConsts.APOLLO_CONFIGSERVICE, t); + } + try { + this.getInstances(ServiceNameConsts.APOLLO_ADMINSERVICE); + } catch (Throwable t) { + log.error("fail to get instances of service name {}", ServiceNameConsts.APOLLO_ADMINSERVICE, t); + } + } + + void updateCacheTask() { + try { + // for each service name, update their service instances in memory + this.serviceName2ServiceInstances.replaceAll( + (serviceName, serviceInstances) -> this.delegate.getInstances(serviceName) + ); + } catch (Throwable t) { + log.error("fail to read service instances from database", t); + } + } + + List readFromDatabase(String serviceName) { + return this.delegate.getInstances(serviceName); + } + + /** + * never throw {@link Throwable}, read from memory cache + */ + @Override + public List getInstances(String serviceName) { + // put serviceName as key to map, + // then the task use it to read service instances from database + this.serviceName2ServiceInstances.computeIfAbsent(serviceName, this::readFromDatabase); + // get from cache + return this.serviceName2ServiceInstances.getOrDefault(serviceName, Collections.emptyList()); + } +} diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java index df4bb52327c..7af64768e06 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/registry/configuration/ApolloServiceDiscoveryAutoConfiguration.java @@ -17,7 +17,9 @@ package com.ctrip.framework.apollo.biz.registry.configuration; import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClient; +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl; import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClientImpl; +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryClientMemoryCacheDecoratorImpl; import com.ctrip.framework.apollo.biz.registry.ServiceInstance; import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryClearApplicationRunner; import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties; @@ -38,6 +40,23 @@ }) public class ApolloServiceDiscoveryAutoConfiguration { + + private static DatabaseDiscoveryClient wrapMemoryCache(DatabaseDiscoveryClient discoveryClient) { + DatabaseDiscoveryClientMemoryCacheDecoratorImpl decorator + = new DatabaseDiscoveryClientMemoryCacheDecoratorImpl(discoveryClient); + decorator.init(); + return decorator; + } + + private static DatabaseDiscoveryClient wrapAlwaysAddSelfInstance( + DatabaseDiscoveryClient discoveryClient, + ServiceInstance selfInstance + ) { + return new DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl( + discoveryClient, selfInstance + ); + } + @Bean @ConditionalOnMissingBean public DatabaseDiscoveryClient databaseDiscoveryClient( @@ -45,9 +64,12 @@ public DatabaseDiscoveryClient databaseDiscoveryClient( ServiceInstance selfServiceInstance, ServiceRegistryService serviceRegistryService ) { - return new DatabaseDiscoveryClientImpl( + DatabaseDiscoveryClient discoveryClient = new DatabaseDiscoveryClientImpl( serviceRegistryService, discoveryProperties, selfServiceInstance.getCluster() ); + return wrapMemoryCache( + wrapAlwaysAddSelfInstance(discoveryClient, selfServiceInstance) + ); } @Bean diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImplTest.java new file mode 100644 index 00000000000..70d950e173f --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImplTest.java @@ -0,0 +1,143 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import static com.ctrip.framework.apollo.biz.registry.ServiceInstanceFactory.newServiceInstance; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImplTest { + + @Test + void getInstances_other_service_name() { + final String otherServiceName = "other-service"; + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + Mockito.when(client.getInstances(otherServiceName)) + .thenReturn( + Collections.singletonList( + newServiceInstance(otherServiceName, "http://10.240.34.56:8081/", "beijing") + ) + ); + + final String selfServiceName = "self-service"; + ServiceInstance selfInstance = newServiceInstance( + selfServiceName, "http://10.240.34.56:8081/", "beijing" + ); + + DatabaseDiscoveryClient decorator = new DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl( + client, selfInstance + ); + + List serviceInstances = decorator.getInstances(otherServiceName); + assertEquals(1, serviceInstances.size()); + ServiceInstance otherServiceNameInstance = serviceInstances.get(0); + assertEquals(otherServiceName, otherServiceNameInstance.getServiceName()); + + Mockito.verify(client, Mockito.times(1)) + .getInstances(Mockito.eq(otherServiceName)); + + Mockito.verify(client, Mockito.never()) + .getInstances(Mockito.eq(selfServiceName)); + } + + @Test + void getInstances_contain_self() { + final String otherServiceName = "other-service"; + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + Mockito.when(client.getInstances(otherServiceName)) + .thenReturn( + Collections.singletonList( + newServiceInstance(otherServiceName, "http://10.240.34.56:8081/", "beijing") + ) + ); + + final String selfServiceName = "self-service"; + ServiceInstance selfInstance = newServiceInstance( + selfServiceName, "http://10.240.34.56:8081/", "beijing" + ); + Mockito.when(client.getInstances(selfServiceName)) + .thenReturn( + Arrays.asList( + selfInstance, + // same service name but different service instance + newServiceInstance(selfServiceName, "http://10.240.34.56:8082/", "beijing"), + newServiceInstance(selfServiceName, "http://10.240.34.56:8083/", "beijing") + ) + ); + + DatabaseDiscoveryClient decorator = new DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl( + client, selfInstance + ); + + List serviceInstances = decorator.getInstances(selfServiceName); + assertEquals(3, serviceInstances.size()); + + Mockito.verify(client, Mockito.times(1)) + .getInstances(Mockito.eq(selfServiceName)); + + Mockito.verify(client, Mockito.never()) + .getInstances(Mockito.eq(otherServiceName)); + } + + /** + * will add self + */ + @Test + void getInstances_same_service_name_without_self() { + final String otherServiceName = "other-service"; + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + Mockito.when(client.getInstances(otherServiceName)) + .thenReturn( + Collections.singletonList( + newServiceInstance(otherServiceName, "http://10.240.34.56:8081/", "beijing") + ) + ); + + final String selfServiceName = "self-service"; + ServiceInstance selfInstance = newServiceInstance( + selfServiceName, "http://10.240.34.56:8081/", "beijing" + ); + Mockito.when(client.getInstances(selfServiceName)) + .thenReturn( + Arrays.asList( + // same service name but different service instance + newServiceInstance(selfServiceName, "http://10.240.34.56:8082/", "beijing"), + newServiceInstance(selfServiceName, "http://10.240.34.56:8083/", "beijing") + ) + ); + + DatabaseDiscoveryClient decorator = new DatabaseDiscoveryClientAlwaysAddSelfInstanceDecoratorImpl( + client, selfInstance + ); + + List serviceInstances = decorator.getInstances(selfServiceName); + // because mocked data don't contain self instance + // after add self instance, there are 3 instances now + assertEquals(3, serviceInstances.size()); + + Mockito.verify(client, Mockito.times(1)) + .getInstances(Mockito.eq(selfServiceName)); + + Mockito.verify(client, Mockito.never()) + .getInstances(Mockito.eq(otherServiceName)); + } +} \ No newline at end of file diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImplTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImplTest.java new file mode 100644 index 00000000000..097f35dc493 --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryClientMemoryCacheDecoratorImplTest.java @@ -0,0 +1,210 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import static com.ctrip.framework.apollo.biz.registry.ServiceInstanceFactory.newServiceInstance; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class DatabaseDiscoveryClientMemoryCacheDecoratorImplTest { + + @Test + void init() { + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + DatabaseDiscoveryClientMemoryCacheDecoratorImpl decorator + = new DatabaseDiscoveryClientMemoryCacheDecoratorImpl(client); + decorator.init(); + } + + @Test + void updateCacheTask_empty() { + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + DatabaseDiscoveryClientMemoryCacheDecoratorImpl decorator + = new DatabaseDiscoveryClientMemoryCacheDecoratorImpl(client); + decorator.updateCacheTask(); + + Mockito.verify(client, Mockito.never()).getInstances(Mockito.any()); + } + + @Test + void updateCacheTask_exception() { + final String serviceName = "a-service"; + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + Mockito.when(client.getInstances(serviceName)) + .thenReturn( + Arrays.asList( + newServiceInstance(serviceName, "http://10.240.34.56:8080/", "beijing"), + newServiceInstance(serviceName, "http://10.240.34.56:8081/", "beijing"), + newServiceInstance(serviceName, "http://10.240.34.56:8082/", "beijing") + ) + ); + DatabaseDiscoveryClientMemoryCacheDecoratorImpl decorator + = new DatabaseDiscoveryClientMemoryCacheDecoratorImpl(client); + List list = decorator.getInstances(serviceName); + assertEquals(3, list.size()); + + // if database error + Mockito.when(client.getInstances(serviceName)) + .thenThrow(OutOfMemoryError.class); + assertThrows(OutOfMemoryError.class, () -> decorator.readFromDatabase(serviceName)); + + // task won't be interrupted by Throwable + decorator.updateCacheTask(); + + Mockito.verify(client, Mockito.times(3)).getInstances(serviceName); + } + + @Test + void getInstances_from_cache() { + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + Mockito.when(client.getInstances("a-service")) + .thenReturn( + Arrays.asList( + newServiceInstance("a-service", "http://10.240.34.56:8080/", "beijing"), + newServiceInstance("a-service", "http://10.240.34.56:8081/", "beijing") + ) + ); + Mockito.when(client.getInstances("b-service")) + .thenReturn( + Arrays.asList( + newServiceInstance("b-service", "http://10.240.56.78:8080/", "shanghai"), + newServiceInstance("b-service", "http://10.240.56.78:8081/", "shanghai"), + newServiceInstance("b-service", "http://10.240.56.78:8082/", "shanghai") + ) + ); + + DatabaseDiscoveryClientMemoryCacheDecoratorImpl decorator + = new DatabaseDiscoveryClientMemoryCacheDecoratorImpl(client); + assertEquals(2, decorator.getInstances("a-service").size()); + assertEquals(2, decorator.getInstances("a-service").size()); + assertEquals(3, decorator.getInstances("b-service").size()); + assertEquals(3, decorator.getInstances("b-service").size()); + + // only invoke 1 times because always read from cache + Mockito.verify(client, Mockito.times(1)).getInstances("a-service"); + Mockito.verify(client, Mockito.times(1)).getInstances("b-service"); + } + + @Test + void getInstances_from_cache_when_database_updated() { + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + Mockito.when(client.getInstances("a-service")) + .thenReturn( + Arrays.asList( + newServiceInstance("a-service", "http://10.240.34.56:8080/", "beijing"), + newServiceInstance("a-service", "http://10.240.34.56:8081/", "beijing") + ) + ); + Mockito.when(client.getInstances("b-service")) + .thenReturn( + Arrays.asList( + newServiceInstance("b-service", "http://10.240.56.78:8080/", "shanghai"), + newServiceInstance("b-service", "http://10.240.56.78:8081/", "shanghai"), + newServiceInstance("b-service", "http://10.240.56.78:8082/", "shanghai") + ) + ); + + DatabaseDiscoveryClientMemoryCacheDecoratorImpl decorator + = new DatabaseDiscoveryClientMemoryCacheDecoratorImpl(client); + assertEquals(2, decorator.getInstances("a-service").size()); + assertEquals(2, decorator.getInstances("a-service").size()); + assertEquals(3, decorator.getInstances("b-service").size()); + assertEquals(3, decorator.getInstances("b-service").size()); + + // only invoke 1 times because always read from cache + Mockito.verify(client, Mockito.times(1)).getInstances("a-service"); + Mockito.verify(client, Mockito.times(1)).getInstances("b-service"); + + // instances in database are changed + Mockito.when(client.getInstances("b-service")) + .thenReturn( + Collections.singletonList( + newServiceInstance("b-service", "http://10.240.56.78:8080/", "shanghai") + ) + ); + + // read again + assertEquals(2, decorator.getInstances("a-service").size()); + // cache doesn't update yet, so we still get 3 instances + assertEquals(3, decorator.getInstances("b-service").size()); + + // only invoke 1 times because always read from cache + Mockito.verify(client, Mockito.times(1)).getInstances("a-service"); + Mockito.verify(client, Mockito.times(1)).getInstances("b-service"); + + decorator.updateCacheTask(); + + // read again + assertEquals(2, decorator.getInstances("a-service").size()); + // cache updated already, so we still get 1 instances + assertEquals(1, decorator.getInstances("b-service").size()); + + // invoke 2 times because always read from database again by task + Mockito.verify(client, Mockito.times(2)).getInstances("a-service"); + Mockito.verify(client, Mockito.times(2)).getInstances("b-service"); + } + + + @Test + void getInstances_from_cache_when_database_crash() { + DatabaseDiscoveryClient client = Mockito.mock(DatabaseDiscoveryClient.class); + Mockito.when(client.getInstances("a-service")) + .thenReturn( + Arrays.asList( + newServiceInstance("a-service", "http://10.240.34.56:8080/", "beijing"), + newServiceInstance("a-service", "http://10.240.34.56:8081/", "beijing") + ) + ); + Mockito.when(client.getInstances("b-service")) + .thenReturn( + Arrays.asList( + newServiceInstance("b-service", "http://10.240.56.78:8080/", "shanghai"), + newServiceInstance("b-service", "http://10.240.56.78:8081/", "shanghai"), + newServiceInstance("b-service", "http://10.240.56.78:8082/", "shanghai") + ) + ); + + DatabaseDiscoveryClientMemoryCacheDecoratorImpl decorator + = new DatabaseDiscoveryClientMemoryCacheDecoratorImpl(client); + assertEquals(2, decorator.getInstances("a-service").size()); + assertEquals(2, decorator.getInstances("a-service").size()); + assertEquals(3, decorator.getInstances("b-service").size()); + assertEquals(3, decorator.getInstances("b-service").size()); + + // only invoke 1 times because always read from cache + Mockito.verify(client, Mockito.times(1)).getInstances("a-service"); + Mockito.verify(client, Mockito.times(1)).getInstances("b-service"); + + // database crash + Mockito.when(client.getInstances(Mockito.any())) + .thenThrow(OutOfMemoryError.class); + assertThrows(OutOfMemoryError.class, () -> decorator.readFromDatabase("a-service")); + assertThrows(OutOfMemoryError.class, () -> decorator.readFromDatabase("b-service")); + + // read again + assertEquals(2, decorator.getInstances("a-service").size()); + assertEquals(3, decorator.getInstances("b-service").size()); + + Mockito.verify(client, Mockito.times(2)).getInstances("a-service"); + Mockito.verify(client, Mockito.times(2)).getInstances("b-service"); + } +} \ No newline at end of file diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java index 9e40721097e..80b79842207 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java @@ -16,12 +16,12 @@ */ package com.ctrip.framework.apollo.biz.registry; +import static com.ctrip.framework.apollo.biz.registry.ServiceInstanceFactory.newServiceInstance; import static org.junit.jupiter.api.Assertions.assertEquals; import com.ctrip.framework.apollo.biz.AbstractIntegrationTest; import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceDiscoveryAutoConfiguration; import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceRegistryAutoConfiguration; -import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; import java.util.List; import org.junit.Test; @@ -65,10 +65,9 @@ public void registerThenDiscoveryThenDelete() { String serviceName = "a-service"; String uri = "http://192.168.1.20:8080/"; String cluster = "default"; - ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); - instance.setServiceName(serviceName); - instance.setUri(uri); - instance.setCluster(cluster); + ServiceInstance instance = newServiceInstance( + serviceName, uri, cluster + ); this.serviceRegistry.register(instance); // find it @@ -93,12 +92,9 @@ public void registerThenDiscoveryThenDelete() { public void registerThenDiscoveryNone() { // register it String serviceName = "b-service"; - String uri = "http://192.168.1.20:8080/"; - String cluster = "cannot-be-discovery"; - ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); - instance.setServiceName(serviceName); - instance.setUri(uri); - instance.setCluster(cluster); + ServiceInstance instance = newServiceInstance( + serviceName, "http://192.168.1.20:8080/", "cannot-be-discovery" + ); this.serviceRegistry.register(instance); // find none @@ -108,14 +104,10 @@ public void registerThenDiscoveryNone() { @Test public void registerTwice() { - String serviceName = "c-service"; - String uri = "http://192.168.1.20:8080/"; - String cluster = "default"; - ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); - instance.setServiceName(serviceName); - instance.setUri(uri); - instance.setCluster(cluster); + ServiceInstance instance = newServiceInstance( + serviceName, "http://192.168.1.20:8080/", "default" + ); // register it this.serviceRegistry.register(instance); @@ -131,22 +123,17 @@ public void registerTwice() { public void registerTwoInstancesThenDeleteOne() { final String serviceName = "d-service"; final String cluster = "default"; - { - String uri = "http://192.168.1.20:8080/"; - ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); - instance.setServiceName(serviceName); - instance.setUri(uri); - instance.setCluster(cluster); - this.serviceRegistry.register(instance); - } - { - String uri = "http://192.168.1.20:10000/"; - ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); - instance.setServiceName(serviceName); - instance.setUri(uri); - instance.setCluster(cluster); - this.serviceRegistry.register(instance); - } + + this.serviceRegistry.register( + newServiceInstance( + serviceName, "http://192.168.1.20:8080/", cluster + ) + ); + this.serviceRegistry.register( + newServiceInstance( + serviceName, "http://192.168.1.20:10000/", cluster + ) + ); final List serviceInstances = this.discoveryClient.getInstances(serviceName); assertEquals(2, serviceInstances.size()); @@ -158,14 +145,11 @@ public void registerTwoInstancesThenDeleteOne() { } // delete one - { - String uri = "http://192.168.1.20:10000/"; - ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); - instance.setServiceName(serviceName); - instance.setUri(uri); - instance.setCluster(cluster); - this.serviceRegistry.deregister(instance); - } + this.serviceRegistry.deregister( + newServiceInstance( + serviceName, "http://192.168.1.20:10000/", cluster + ) + ); assertEquals(1, this.discoveryClient.getInstances(serviceName).size()); assertEquals("http://192.168.1.20:8080/", diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/ServiceInstanceFactory.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/ServiceInstanceFactory.java new file mode 100644 index 00000000000..fa4f4d2acf0 --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/ServiceInstanceFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceRegistryProperties; + +public class ServiceInstanceFactory { + static ServiceInstance newServiceInstance(String serviceName, String uri, String cluster) { + ApolloServiceRegistryProperties instance = new ApolloServiceRegistryProperties(); + instance.setServiceName(serviceName); + instance.setUri(uri); + instance.setCluster(cluster); + return instance; + } +} From 1d1d77e88102a9c3e316d23df9eae10e10dbc9d4 Mon Sep 17 00:00:00 2001 From: wxq <15523186+Anilople@users.noreply.github.com> Date: Sun, 23 Oct 2022 11:14:11 +0800 Subject: [PATCH 31/31] test: fix when DatabaseDiscoveryClient wrap by decorator --- .../DatabaseDiscoveryIntegrationTest.java | 18 +- ...coveryWithoutDecoratorIntegrationTest.java | 198 ++++++++++++++++++ 2 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryWithoutDecoratorIntegrationTest.java diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java index 80b79842207..9ac46ed6ad4 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.java @@ -20,18 +20,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import com.ctrip.framework.apollo.biz.AbstractIntegrationTest; +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryWithoutDecoratorIntegrationTest.ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration; import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceDiscoveryAutoConfiguration; import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceRegistryAutoConfiguration; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties; import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; import java.util.List; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; +/** + * test when {@link DatabaseDiscoveryClient} is warped by decorator. + */ @TestPropertySource( properties = { "apollo.service.registry.enabled=true", @@ -81,8 +90,8 @@ public void registerThenDiscoveryThenDelete() { // delete it this.serviceRegistry.deregister(instance); - // find none - assertEquals(0, this.discoveryClient.getInstances(serviceName).size()); + // because it save in memory, so we can still find it + assertEquals(1, this.discoveryClient.getInstances(serviceName).size()); } /** @@ -151,8 +160,7 @@ public void registerTwoInstancesThenDeleteOne() { ) ); - assertEquals(1, this.discoveryClient.getInstances(serviceName).size()); - assertEquals("http://192.168.1.20:8080/", - this.discoveryClient.getInstances(serviceName).get(0).getUri().toString()); + // because it save in memory, so we can still find it + assertEquals(2, this.discoveryClient.getInstances(serviceName).size()); } } diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryWithoutDecoratorIntegrationTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryWithoutDecoratorIntegrationTest.java new file mode 100644 index 00000000000..dffe06f0980 --- /dev/null +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryWithoutDecoratorIntegrationTest.java @@ -0,0 +1,198 @@ +/* + * Copyright 2022 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.biz.registry; + +import static com.ctrip.framework.apollo.biz.registry.ServiceInstanceFactory.newServiceInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.ctrip.framework.apollo.biz.AbstractIntegrationTest; +import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryWithoutDecoratorIntegrationTest.ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration; +import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceDiscoveryAutoConfiguration; +import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceRegistryAutoConfiguration; +import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties; +import com.ctrip.framework.apollo.biz.repository.ServiceRegistryRepository; +import com.ctrip.framework.apollo.biz.service.ServiceRegistryService; +import java.util.List; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; + +/** + * test when {@link DatabaseDiscoveryClient} doesn't warp by decorator. + */ +@TestPropertySource( + properties = { + "apollo.service.registry.enabled=true", + "apollo.service.registry.cluster=default", + "apollo.service.discovery.enabled=true", + "spring.application.name=for-test-service", + "server.port=10000", + // close decorator + "ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration.enabled=true", + } +) +@ContextConfiguration(classes = { + ApolloServiceRegistryAutoConfiguration.class, + // notice that the order of classes is import + // @AutoConfigureBefore(ApolloServiceDiscoveryAutoConfiguration.class) won't work when run test + ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration.class, + ApolloServiceDiscoveryAutoConfiguration.class, +}) +@EnableJpaRepositories(basePackageClasses = ServiceRegistryRepository.class) +public class DatabaseDiscoveryWithoutDecoratorIntegrationTest extends AbstractIntegrationTest { + + private final Logger log = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private DatabaseServiceRegistry serviceRegistry; + + @Autowired + private DatabaseDiscoveryClient discoveryClient; + + /** + * discover one after register, and delete it + */ + @Test + public void registerThenDiscoveryThenDelete() { + // register it + String serviceName = "a-service"; + String uri = "http://192.168.1.20:8080/"; + String cluster = "default"; + ServiceInstance instance = newServiceInstance( + serviceName, uri, cluster + ); + this.serviceRegistry.register(instance); + + // find it + List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(1, serviceInstances.size()); + ServiceInstance actual = serviceInstances.get(0); + assertEquals(serviceName, actual.getServiceName()); + assertEquals(uri, actual.getUri().toString()); + assertEquals(cluster, actual.getCluster()); + assertEquals(0, actual.getMetadata().size()); + + // delete it + this.serviceRegistry.deregister(instance); + // find none + assertEquals(0, this.discoveryClient.getInstances(serviceName).size()); + } + + /** + * diff cluster so cannot be discover + */ + @Test + public void registerThenDiscoveryNone() { + // register it + String serviceName = "b-service"; + ServiceInstance instance = newServiceInstance( + serviceName, "http://192.168.1.20:8080/", "cannot-be-discovery" + ); + this.serviceRegistry.register(instance); + + // find none + List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(0, serviceInstances.size()); + } + + @Test + public void registerTwice() { + String serviceName = "c-service"; + ServiceInstance instance = newServiceInstance( + serviceName, "http://192.168.1.20:8080/", "default" + ); + + // register it + this.serviceRegistry.register(instance); + // register again + this.serviceRegistry.register(instance); + + // only discover one + List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(1, serviceInstances.size()); + } + + @Test + public void registerTwoInstancesThenDeleteOne() { + final String serviceName = "d-service"; + final String cluster = "default"; + + this.serviceRegistry.register( + newServiceInstance( + serviceName, "http://192.168.1.20:8080/", cluster + ) + ); + this.serviceRegistry.register( + newServiceInstance( + serviceName, "http://192.168.1.20:10000/", cluster + ) + ); + + final List serviceInstances = this.discoveryClient.getInstances(serviceName); + assertEquals(2, serviceInstances.size()); + + for (ServiceInstance serviceInstance : serviceInstances) { + assertEquals(serviceName, serviceInstance.getServiceName()); + assertEquals(cluster, serviceInstance.getCluster()); + assertEquals(0, serviceInstance.getMetadata().size()); + } + + // delete one + this.serviceRegistry.deregister( + newServiceInstance( + serviceName, "http://192.168.1.20:10000/", cluster + ) + ); + + assertEquals(1, this.discoveryClient.getInstances(serviceName).size()); + assertEquals("http://192.168.1.20:8080/", + this.discoveryClient.getInstances(serviceName).get(0).getUri().toString()); + } + + /** + * only use in {@link DatabaseDiscoveryWithoutDecoratorIntegrationTest} + */ + @Configuration + @ConditionalOnProperty(prefix = "ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration", value = "enabled") + @ConditionalOnBean(ApolloServiceDiscoveryAutoConfiguration.class) + @AutoConfigureBefore(ApolloServiceDiscoveryAutoConfiguration.class) + @EnableConfigurationProperties({ + ApolloServiceDiscoveryProperties.class, + }) + static class ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration { + @Bean + public DatabaseDiscoveryClient databaseDiscoveryClient( + ApolloServiceDiscoveryProperties discoveryProperties, + ServiceInstance selfServiceInstance, + ServiceRegistryService serviceRegistryService + ) { + return new DatabaseDiscoveryClientImpl( + serviceRegistryService, discoveryProperties, selfServiceInstance.getCluster() + ); + } + } +}