diff --git a/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/build.gradle.kts b/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/build.gradle.kts index 4d9a10536..008cac0e1 100644 --- a/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/build.gradle.kts +++ b/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/build.gradle.kts @@ -5,4 +5,5 @@ dependencies { api("io.github.openfeign:feign-jaxrs") api("io.github.openfeign:feign-okhttp") api("io.github.openfeign:feign-jackson") + api("com.google.guava:guava") } diff --git a/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/src/main/kotlin/com/tencent/devops/common/client/ms/FeignTarget.kt b/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/src/main/kotlin/com/tencent/devops/common/client/ms/FeignTarget.kt index 10563f342..9326a6267 100644 --- a/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/src/main/kotlin/com/tencent/devops/common/client/ms/FeignTarget.kt +++ b/src/backend/turbo/common-turbo/common-turbo-client/common-client-base/src/main/kotlin/com/tencent/devops/common/client/ms/FeignTarget.kt @@ -26,18 +26,25 @@ package com.tencent.devops.common.client.ms +import com.google.common.cache.Cache +import com.google.common.cache.CacheBuilder import feign.Request import feign.RequestTemplate import feign.Target import org.springframework.cloud.client.ServiceInstance import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit abstract class FeignTarget( protected open val serviceName: String, protected open val type: Class, protected open val commonUrlPrefix: String, - protected val usedInstance: ConcurrentHashMap = - ConcurrentHashMap() + // key: serviceName, value: List + protected val usedInstance: Cache> = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterWrite(3, TimeUnit.SECONDS) + .build>() ) : Target { override fun apply(input: RequestTemplate?): Request { diff --git a/src/backend/turbo/common-turbo/common-turbo-client/common-client-consul/src/main/kotlin/com/tencent/devops/common/client/ms/ConsulServiceTarget.kt b/src/backend/turbo/common-turbo/common-turbo-client/common-client-consul/src/main/kotlin/com/tencent/devops/common/client/ms/ConsulServiceTarget.kt index 8981f822c..3686e3ed5 100644 --- a/src/backend/turbo/common-turbo/common-turbo-client/common-client-consul/src/main/kotlin/com/tencent/devops/common/client/ms/ConsulServiceTarget.kt +++ b/src/backend/turbo/common-turbo/common-turbo-client/common-client-consul/src/main/kotlin/com/tencent/devops/common/client/ms/ConsulServiceTarget.kt @@ -10,12 +10,13 @@ * * Terms of the MIT License: * --------------------------------------------------- - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN @@ -49,45 +50,37 @@ open class ConsulServiceTarget constructor( } override fun choose(serviceName: String): ServiceInstance { - val instances = discoveryClient.getInstances(serviceName) - ?: throw ClientException( - "找不到任何有效的[$serviceName]服务提供者" - ) - if (instances.isEmpty()) { - throw ClientException( - "找不到任何有效的[$serviceName]服务提供者" - ) - } - - val matchTagInstances = ArrayList() + val serviceInstanceList: List = usedInstance.getIfPresent(serviceName) ?: emptyList() - instances.forEach { serviceInstance -> - if (serviceInstance is ConsulServiceInstance && serviceInstance.tags.contains(tag) && - !usedInstance.contains(serviceInstance.url())) { - matchTagInstances.add(serviceInstance) + if (serviceInstanceList.isEmpty()) { + val currentInstanceList = discoveryClient.getInstances(serviceName) + if (currentInstanceList.isEmpty()) { + logger.error("Unable to find any valid [$serviceName] service provider") + throw ClientException( + "Unable to find any valid [$serviceName] service provider" + ) + } + currentInstanceList.forEach { serviceInstance -> + if (serviceInstance is ConsulServiceInstance && serviceInstance.tags.contains(tag)) { + serviceInstanceList.toMutableList().add(serviceInstance) + } } - } - - // 如果为空,则将之前用过的实例重新加入选择 - if (matchTagInstances.isEmpty() && usedInstance.isNotEmpty()) { - matchTagInstances.addAll(usedInstance.values) - } - if (matchTagInstances.isEmpty()) { - throw ClientException( - "找不到任何有效的[$serviceName]服务提供者" - ) - } else if (matchTagInstances.size > 1) { - matchTagInstances.shuffle() + if (serviceInstanceList.isEmpty()) { + logger.error("Unable to find any valid [$serviceName] service provider") + throw ClientException( + "Unable to find any valid [$serviceName] service provider" + ) + } else { + usedInstance.put(serviceName, serviceInstanceList) + serviceInstanceList.toMutableList().shuffle() + } } - usedInstance[matchTagInstances[0].url()] = matchTagInstances[0] - return matchTagInstances[0] + return serviceInstanceList[0] } override fun url(): String { return choose(serviceName).url() } - - } diff --git a/src/backend/turbo/common-turbo/common-turbo-client/common-client-k8s/src/main/kotlin/com/tencent/devops/common/client/ms/KubernetesServiceTarget.kt b/src/backend/turbo/common-turbo/common-turbo-client/common-client-k8s/src/main/kotlin/com/tencent/devops/common/client/ms/KubernetesServiceTarget.kt index 64053397a..8777919bc 100644 --- a/src/backend/turbo/common-turbo/common-turbo-client/common-client-k8s/src/main/kotlin/com/tencent/devops/common/client/ms/KubernetesServiceTarget.kt +++ b/src/backend/turbo/common-turbo/common-turbo-client/common-client-k8s/src/main/kotlin/com/tencent/devops/common/client/ms/KubernetesServiceTarget.kt @@ -10,12 +10,13 @@ * * Terms of the MIT License: * --------------------------------------------------- - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN @@ -27,6 +28,7 @@ package com.tencent.devops.common.client.ms import com.tencent.devops.common.api.exception.ClientException +import org.apache.commons.lang3.RandomUtils import org.slf4j.LoggerFactory import org.springframework.cloud.client.ServiceInstance import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient @@ -47,40 +49,21 @@ class KubernetesServiceTarget constructor( } override fun choose(serviceName: String): ServiceInstance { - val instances = discoveryClient.getInstances(serviceName) - ?: throw ClientException( - "找不到任何有效的[$serviceName]服务提供者" - ) - if (instances.isEmpty()) { - throw ClientException( - "找不到任何有效的[$serviceName]服务提供者" - ) - } + val serviceInstanceList: List = usedInstance.getIfPresent(serviceName) ?: emptyList() - val matchTagInstances = ArrayList() - - instances.forEach { serviceInstance -> - if (!usedInstance.contains(serviceInstance.url())) { - // logger.info("service instance url: ${serviceInstance.url()}") - matchTagInstances.add(serviceInstance) + if (serviceInstanceList.isEmpty()) { + val currentInstanceList = discoveryClient.getInstances(serviceName) + if (currentInstanceList.isEmpty()) { + logger.error("Unable to find any valid [$serviceName] service provider") + throw ClientException( + "Unable to find any valid [$serviceName] service provider" + ) } + serviceInstanceList.toMutableList().addAll(currentInstanceList) + usedInstance.put(serviceName, serviceInstanceList) } - // 如果为空,则将之前用过的实例重新加入选择 - if (matchTagInstances.isEmpty() && usedInstance.isNotEmpty()) { - matchTagInstances.addAll(usedInstance.values) - } - - if (matchTagInstances.isEmpty()) { - throw ClientException( - "找不到任何有效的[$serviceName]服务提供者" - ) - } else if (matchTagInstances.size > 1) { - matchTagInstances.shuffle() - } - - usedInstance[matchTagInstances[0].url()] = matchTagInstances[0] - return matchTagInstances[0] + return serviceInstanceList[RandomUtils.nextInt(0, serviceInstanceList.size)] } }