Merge remote-tracking branch 'origin/main'
This commit is contained in:
47
.github/dependabot.yml
vendored
47
.github/dependabot.yml
vendored
@@ -2,17 +2,12 @@ version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "3.1.x" # oldest OSS supported branch
|
||||
target-branch: "4.1.x" # oldest OSS supported branch
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "4.0.x" # oldest OSS supported branch
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "4.1.x"
|
||||
target-branch: "4.2.x"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
@@ -20,28 +15,6 @@ updates:
|
||||
target-branch: "main"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
target-branch: 3.1.x
|
||||
ignore:
|
||||
# only upgrade patch versions for maintenance branch
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
target-branch: 4.0.x
|
||||
ignore:
|
||||
# only upgrade patch versions for maintenance branch
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
@@ -53,6 +26,17 @@ updates:
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
target-branch: 4.2.x
|
||||
ignore:
|
||||
# only upgrade patch versions for maintenance branch
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- package-ecosystem: maven
|
||||
directory: /
|
||||
schedule:
|
||||
@@ -78,3 +62,8 @@ updates:
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
- package-ecosystem: npm
|
||||
target-branch: 4.2.x
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
4
.github/workflows/maven.yml
vendored
4
.github/workflows/maven.yml
vendored
@@ -5,9 +5,9 @@ name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, 4.1.x ]
|
||||
branches: [ main, 4.2.x, 4.1.x ]
|
||||
pull_request:
|
||||
branches: [ main, 4.1.x ]
|
||||
branches: [ main, 4.2.x, 4.1.x ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -85,9 +85,9 @@ The `Customizer` interface has a single method (called `customize`) that takes t
|
||||
For detailed information on how to customize a given implementation see
|
||||
the following documentation:
|
||||
|
||||
* link:../../../../spring-cloud-circuitbreaker/current/reference/html/spring-cloud-circuitbreaker.html#configuring-resilience4j-circuit-breakers[Resilience4J]
|
||||
* link:../../../../spring-cloud-circuitbreaker/reference/spring-cloud-circuitbreaker-resilience4j.html[Resilience4J]
|
||||
* link:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc/circuitbreaker-sentinel.adoc#circuit-breaker-spring-cloud-circuit-breaker-with-sentinel--configuring-sentinel-circuit-breakers[Sentinel]
|
||||
* link:../../../../../spring-cloud-circuitbreaker/docs/current/reference/html/spring-cloud-circuitbreaker.html#configuring-spring-retry-circuit-breakers[Spring Retry]
|
||||
* link:../../../../../spring-cloud-circuitbreaker/reference/spring-cloud-circuitbreaker-spring-retry.html[Spring Retry]
|
||||
|
||||
Some `CircuitBreaker` implementations such as `Resilience4JCircuitBreaker` call `customize` method every time `CircuitBreaker#run` is called.
|
||||
It can be inefficient. In that case, you can use `CircuitBreaker#once` method. It is useful where calling `customize` many times doesn't make sense,
|
||||
|
||||
@@ -76,8 +76,8 @@
|
||||
|spring.cloud.loadbalancer.zone | | Spring Cloud LoadBalancer zone.
|
||||
|spring.cloud.refresh.additional-property-sources-to-retain | | Additional property sources to retain during a refresh. Typically only system property sources are retained. This property allows property sources, such as property sources created by EnvironmentPostProcessors to be retained as well.
|
||||
|spring.cloud.refresh.enabled | `+++true+++` | Enables autoconfiguration for the refresh scope and associated features.
|
||||
|spring.cloud.refresh.extra-refreshable | `+++true+++` | Additional class names for beans to post process into refresh scope.
|
||||
|spring.cloud.refresh.never-refreshable | `+++true+++` | Comma separated list of class names for beans to never be refreshed or rebound.
|
||||
|spring.cloud.refresh.extra-refreshable | `+++true+++` | Additional bean names or class names for beans to post process into refresh scope.
|
||||
|spring.cloud.refresh.never-refreshable | `+++true+++` | Comma separated list of bean names or class names for beans to never be refreshed or rebound.
|
||||
|spring.cloud.refresh.on-restart.enabled | `+++true+++` | Enable refreshing context on start.
|
||||
|spring.cloud.service-registry.auto-registration.enabled | `+++true+++` | Whether service auto-registration is enabled. Defaults to true.
|
||||
|spring.cloud.service-registry.auto-registration.fail-fast | `+++false+++` | Whether startup fails if there is no AutoServiceRegistration. Defaults to false.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"@antora/atlas-extension": "1.0.0-alpha.2",
|
||||
"@antora/collector-extension": "1.0.1",
|
||||
"@asciidoctor/tabs": "1.0.0-beta.6",
|
||||
"@springio/antora-extensions": "1.14.2",
|
||||
"@springio/asciidoctor-extensions": "1.0.0-alpha.14"
|
||||
"@springio/antora-extensions": "1.14.4",
|
||||
"@springio/asciidoctor-extensions": "1.0.0-alpha.16"
|
||||
}
|
||||
}
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -28,7 +28,7 @@
|
||||
<properties>
|
||||
<bintray.package>commons</bintray.package>
|
||||
<evictor.version>1.0.0</evictor.version>
|
||||
<bouncycastle-bcprov-jdk18on.version>1.78.1</bouncycastle-bcprov-jdk18on.version>
|
||||
<bouncycastle-bcprov-jdk18on.version>1.80</bouncycastle-bcprov-jdk18on.version>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<name>spring-cloud-commons-dependencies</name>
|
||||
<description>Spring Cloud Commons Dependencies</description>
|
||||
<properties>
|
||||
<okhttp.version>4.12.0</okhttp.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -53,6 +54,20 @@
|
||||
<artifactId>spring-cloud-test-support</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Spring Boot removed its dependency management of okhttp in Spring Boot 3.4.0 -->
|
||||
<!-- This resulted in a different version fo okhttp in Spring Cloud 2024.0.0 -->
|
||||
<!-- We will now manage the version in Spring Cloud Commons to maintain backward compatibility -->
|
||||
<!-- This can be removed in the next major -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<profiles>
|
||||
|
||||
@@ -176,6 +176,16 @@
|
||||
<artifactId>httpclient5</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,6 +63,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Dave Syer
|
||||
* @author Venil Noronha
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RefreshScope.class)
|
||||
@@ -209,6 +210,9 @@ public class RefreshAutoConfiguration {
|
||||
// Already refresh scoped
|
||||
return false;
|
||||
}
|
||||
if (this.refreshables.contains(name)) {
|
||||
return true;
|
||||
}
|
||||
String type = definition.getBeanClassName();
|
||||
if (!StringUtils.hasText(type) && registry instanceof BeanFactory) {
|
||||
Class<?> cls = ((BeanFactory) registry).getType(name);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,6 +47,7 @@ import org.springframework.util.StringUtils;
|
||||
* the <code>@ConfigurationProperties</code> bean.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Yanming Zhou
|
||||
* @see RefreshScope for a deeper and optionally more focused refresh of bean components.
|
||||
*
|
||||
*/
|
||||
@@ -131,7 +132,7 @@ public class ConfigurationPropertiesRebinder
|
||||
// TODO: determine a more general approach to fix this.
|
||||
// see
|
||||
// https://github.com/spring-cloud/spring-cloud-commons/issues/571
|
||||
if (getNeverRefreshable().contains(bean.getClass().getName())) {
|
||||
if (getNeverRefreshable().contains(bean.getClass().getName()) || getNeverRefreshable().contains(name)) {
|
||||
return false; // ignore
|
||||
}
|
||||
appContext.getAutowireCapableBeanFactory().destroyBean(bean);
|
||||
|
||||
@@ -92,9 +92,6 @@ public class ConfigDataContextRefresher extends ContextRefresher
|
||||
postProcessor.postProcessEnvironment(environment, application);
|
||||
}
|
||||
|
||||
if (environment.getPropertySources().contains(REFRESH_ARGS_PROPERTY_SOURCE)) {
|
||||
environment.getPropertySources().remove(REFRESH_ARGS_PROPERTY_SOURCE);
|
||||
}
|
||||
MutablePropertySources target = getContext().getEnvironment().getPropertySources();
|
||||
String targetName = null;
|
||||
for (PropertySource<?> source : environment.getPropertySources()) {
|
||||
|
||||
@@ -51,8 +51,6 @@ public abstract class ContextRefresher {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected static final String REFRESH_ARGS_PROPERTY_SOURCE = "refreshArgs";
|
||||
|
||||
protected static final String[] DEFAULT_PROPERTY_SOURCES = new String[] {
|
||||
// order matters, if cli args aren't first, things get messy
|
||||
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME, "defaultProperties" };
|
||||
|
||||
@@ -41,6 +41,8 @@ import static org.springframework.cloud.util.PropertyUtils.BOOTSTRAP_ENABLED_PRO
|
||||
*/
|
||||
public class LegacyContextRefresher extends ContextRefresher {
|
||||
|
||||
private static final String REFRESH_ARGS_PROPERTY_SOURCE = "refreshArgs";
|
||||
|
||||
@Deprecated
|
||||
public LegacyContextRefresher(ConfigurableApplicationContext context, RefreshScope scope) {
|
||||
super(context, scope);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.core.env.Environment;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Deprecated(since = "4.3.0", forRemoval = true)
|
||||
public final class EnvironmentUtils {
|
||||
|
||||
private EnvironmentUtils() {
|
||||
|
||||
@@ -39,13 +39,13 @@
|
||||
{
|
||||
"name": "spring.cloud.refresh.extra-refreshable",
|
||||
"type": "java.util.Set<java.lang.String>",
|
||||
"description": "Additional class names for beans to post process into refresh scope.",
|
||||
"description": "Additional bean names or class names for beans to post process into refresh scope.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.cloud.refresh.never-refreshable",
|
||||
"type": "java.lang.String",
|
||||
"description": "Comma separated list of class names for beans to never be refreshed or rebound.",
|
||||
"description": "Comma separated list of bean names or class names for beans to never be refreshed or rebound.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -41,6 +41,7 @@ import static org.assertj.core.api.BDDAssertions.then;
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class RefreshAutoConfigurationTests {
|
||||
@@ -79,7 +80,7 @@ class RefreshAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extraRefreshables() {
|
||||
public void extraRefreshableWithClassName() {
|
||||
try (ConfigurableApplicationContext context = getApplicationContext(WebApplicationType.NONE, Config.class,
|
||||
"sealedconfig.foo=bar",
|
||||
"spring.cloud.refresh.extra-refreshable:" + SealedConfigProps.class.getName())) {
|
||||
@@ -89,7 +90,17 @@ class RefreshAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void neverRefreshable() {
|
||||
public void extraRefreshableWithBeanName() {
|
||||
String beanName = "sealedconfig-" + SealedConfigProps.class.getName();
|
||||
try (ConfigurableApplicationContext context = getApplicationContext(WebApplicationType.NONE, Config.class,
|
||||
"sealedconfig.foo=bar", "spring.cloud.refresh.extra-refreshable:" + beanName)) {
|
||||
context.getBean(SealedConfigProps.class);
|
||||
context.getBean(ContextRefresher.class).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void neverRefreshableWithClassName() {
|
||||
try (ConfigurableApplicationContext context = getApplicationContext(WebApplicationType.NONE, Config.class,
|
||||
"countingconfig.foo=bar",
|
||||
"spring.cloud.refresh.never-refreshable:" + CountingConfigProps.class.getName())) {
|
||||
@@ -99,6 +110,17 @@ class RefreshAutoConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void neverRefreshableWithBeanName() {
|
||||
String beanName = "countingconfig-" + CountingConfigProps.class.getName();
|
||||
try (ConfigurableApplicationContext context = getApplicationContext(WebApplicationType.NONE, Config.class,
|
||||
"countingconfig.foo=bar", "spring.cloud.refresh.never-refreshable:" + beanName)) {
|
||||
CountingConfigProps configProps = context.getBean(CountingConfigProps.class);
|
||||
context.getBean(ContextRefresher.class).refresh();
|
||||
assertThat(configProps.count).as("config props was rebound when it should not have been").hasValue(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshScopeLifecylePresentByDefault() {
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(RefreshAutoConfiguration.class))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,8 +27,10 @@ import io.micrometer.core.instrument.Tags;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.CompletionContext;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.Request;
|
||||
import org.springframework.cloud.client.loadbalancer.RequestData;
|
||||
import org.springframework.cloud.client.loadbalancer.RequestDataContext;
|
||||
import org.springframework.cloud.client.loadbalancer.Response;
|
||||
import org.springframework.cloud.client.loadbalancer.ResponseData;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -55,7 +57,11 @@ class LoadBalancerTags {
|
||||
}
|
||||
|
||||
Iterable<Tag> buildSuccessRequestTags(CompletionContext<Object, ServiceInstance, Object> completionContext) {
|
||||
ServiceInstance serviceInstance = completionContext.getLoadBalancerResponse().getServer();
|
||||
Response<ServiceInstance> lbResponse = completionContext.getLoadBalancerResponse();
|
||||
if (lbResponse == null) {
|
||||
return Tags.empty();
|
||||
}
|
||||
ServiceInstance serviceInstance = lbResponse.getServer();
|
||||
Tags tags = Tags.of(buildServiceInstanceTags(serviceInstance));
|
||||
Object clientResponse = completionContext.getClientResponse();
|
||||
if (clientResponse instanceof ResponseData responseData) {
|
||||
@@ -100,9 +106,9 @@ class LoadBalancerTags {
|
||||
}
|
||||
|
||||
Iterable<Tag> buildDiscardedRequestTags(CompletionContext<Object, ServiceInstance, Object> completionContext) {
|
||||
if (completionContext.getLoadBalancerRequest().getContext() instanceof RequestDataContext) {
|
||||
RequestData requestData = ((RequestDataContext) completionContext.getLoadBalancerRequest().getContext())
|
||||
.getClientRequest();
|
||||
Request<Object> lbRequest = completionContext.getLoadBalancerRequest();
|
||||
if (lbRequest != null && lbRequest.getContext() instanceof RequestDataContext requestDataContext) {
|
||||
RequestData requestData = requestDataContext.getClientRequest();
|
||||
if (requestData != null) {
|
||||
return Tags.of(valueOrUnknown("method", requestData.getHttpMethod()),
|
||||
valueOrUnknown("uri", getPath(requestData)), valueOrUnknown("serviceId", getHost(requestData)));
|
||||
@@ -118,11 +124,15 @@ class LoadBalancerTags {
|
||||
}
|
||||
|
||||
Iterable<Tag> buildFailedRequestTags(CompletionContext<Object, ServiceInstance, Object> completionContext) {
|
||||
ServiceInstance serviceInstance = completionContext.getLoadBalancerResponse().getServer();
|
||||
Response<ServiceInstance> lbResponse = completionContext.getLoadBalancerResponse();
|
||||
if (lbResponse == null) {
|
||||
return Tags.empty();
|
||||
}
|
||||
ServiceInstance serviceInstance = lbResponse.getServer();
|
||||
Tags tags = Tags.of(buildServiceInstanceTags(serviceInstance)).and(exception(completionContext.getThrowable()));
|
||||
if (completionContext.getLoadBalancerRequest().getContext() instanceof RequestDataContext) {
|
||||
RequestData requestData = ((RequestDataContext) completionContext.getLoadBalancerRequest().getContext())
|
||||
.getClientRequest();
|
||||
Request<Object> lbRequest = completionContext.getLoadBalancerRequest();
|
||||
if (lbRequest != null && lbRequest.getContext() instanceof RequestDataContext requestDataContext) {
|
||||
RequestData requestData = requestDataContext.getClientRequest();
|
||||
if (requestData != null) {
|
||||
return tags.and(Tags.of(valueOrUnknown("method", requestData.getHttpMethod()),
|
||||
valueOrUnknown("uri", getPath(requestData))));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -85,10 +85,10 @@ public class MicrometerStatsLoadBalancerLifecycle implements LoadBalancerLifecyc
|
||||
|
||||
@Override
|
||||
public void onStartRequest(Request<Object> request, Response<ServiceInstance> lbResponse) {
|
||||
if (request.getContext() instanceof TimedRequestContext) {
|
||||
if (request != null && request.getContext() instanceof TimedRequestContext) {
|
||||
((TimedRequestContext) request.getContext()).setRequestStartTime(System.nanoTime());
|
||||
}
|
||||
if (!lbResponse.hasServer()) {
|
||||
if (lbResponse == null || !lbResponse.hasServer()) {
|
||||
return;
|
||||
}
|
||||
ServiceInstance serviceInstance = lbResponse.getServer();
|
||||
@@ -104,7 +104,11 @@ public class MicrometerStatsLoadBalancerLifecycle implements LoadBalancerLifecyc
|
||||
|
||||
@Override
|
||||
public void onComplete(CompletionContext<Object, ServiceInstance, Object> completionContext) {
|
||||
ServiceInstance serviceInstance = completionContext.getLoadBalancerResponse().getServer();
|
||||
ServiceInstance serviceInstance = null;
|
||||
Response<ServiceInstance> loadBalancerResponse = completionContext.getLoadBalancerResponse();
|
||||
if (loadBalancerResponse != null) {
|
||||
serviceInstance = loadBalancerResponse.getServer();
|
||||
}
|
||||
LoadBalancerProperties properties = serviceInstance != null
|
||||
? loadBalancerFactory.getProperties(serviceInstance.getServiceId())
|
||||
: loadBalancerFactory.getProperties(null);
|
||||
@@ -121,7 +125,11 @@ public class MicrometerStatsLoadBalancerLifecycle implements LoadBalancerLifecyc
|
||||
if (activeRequestsCounter != null) {
|
||||
activeRequestsCounter.decrementAndGet();
|
||||
}
|
||||
Object loadBalancerRequestContext = completionContext.getLoadBalancerRequest().getContext();
|
||||
Request<Object> lbRequest = completionContext.getLoadBalancerRequest();
|
||||
if (lbRequest == null) {
|
||||
return;
|
||||
}
|
||||
Object loadBalancerRequestContext = lbRequest.getContext();
|
||||
if (requestHasBeenTimed(loadBalancerRequestContext)) {
|
||||
if (CompletionContext.Status.FAILED.equals(completionContext.status())) {
|
||||
Timer.builder("loadbalancer.requests.failed")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,6 +47,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.MultiValueMapAdapter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.cloud.loadbalancer.stats.LoadBalancerTags.UNKNOWN;
|
||||
@@ -243,6 +244,26 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
Tag.of("serviceInstance.port", "0"), Tag.of("status", "200"), Tag.of("uri", UNKNOWN));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleNullLoadBalancerResponse() {
|
||||
RequestData requestData = new RequestData(HttpMethod.GET, URI.create("http://test.org/test"), new HttpHeaders(),
|
||||
new HttpHeaders(), new HashMap<>());
|
||||
Request<Object> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData));
|
||||
assertThatCode(() -> {
|
||||
statsLifecycle.onStartRequest(lbRequest, null);
|
||||
statsLifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, null));
|
||||
}).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleNullLoadBalancerRequest() {
|
||||
Response<ServiceInstance> lbResponse = new EmptyResponse();
|
||||
assertThatCode(() -> {
|
||||
statsLifecycle.onStartRequest(null, lbResponse);
|
||||
statsLifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, null, lbResponse));
|
||||
}).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
private static class StatsTestContext {
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<suppress files=".*Tests.*" checks="MethodParamPad"/>
|
||||
<suppress files=".*AutoConfiguration.*" checks="HideUtilityClassConstructor"/>
|
||||
<suppress files=".*AutoConfiguration.*" checks="FinalClass"/>
|
||||
<suppress files=".*ApplicationListener.*" checks="FinalClass"/>
|
||||
<suppress files=".*Tests.*" checks="FinalClass"/>
|
||||
<suppress files=".*ReactiveDiscoveryClient.*" checks="JavadocVariable"/>
|
||||
<suppress files="[\\/]src[\\/](test|testFixtures)[\\/](java|java21)[\\/]" checks="RegexpSinglelineJava" id="toLowerCaseWithoutLocale"/>
|
||||
<suppress files="[\\/]src[\\/](test|testFixtures)[\\/](java|java21)[\\/]" checks="RegexpSinglelineJava" id="toUpperCaseWithoutLocale"/>
|
||||
|
||||
Reference in New Issue
Block a user