Configure automatic context propagation for Reactor
This commit adds a new configuration property, `spring.reactor.context-propagation` that configures the context propagation mode for Reactor operators. By default the value is set to "AUTO" for reinstating automatically context values as ThreadLocals within Reactor operators. The "LIMITED" mode restricts this feature ot the "tap" and "handle" operators but has a slightly lower footprint. Closes gh-34201
This commit is contained in:
parent
bf15797014
commit
4da42c09a6
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2012-2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.reactor;
|
||||
|
||||
import reactor.core.publisher.Hooks;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Reactor.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 3.0.2
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Hooks.class)
|
||||
@EnableConfigurationProperties(ReactorProperties.class)
|
||||
public class ReactorAutoConfiguration {
|
||||
|
||||
public ReactorAutoConfiguration(ReactorProperties properties) {
|
||||
if (properties.getContextPropagation() == ReactorProperties.ContextPropagationMode.AUTO) {
|
||||
Hooks.enableAutomaticContextPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2012-2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.reactor;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for Reactor.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 3.0.3
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.reactor")
|
||||
public class ReactorProperties {
|
||||
|
||||
/**
|
||||
* Context Propagation support mode for Reactor operators.
|
||||
*/
|
||||
private ContextPropagationMode contextPropagation = ContextPropagationMode.AUTO;
|
||||
|
||||
public ContextPropagationMode getContextPropagation() {
|
||||
return this.contextPropagation;
|
||||
}
|
||||
|
||||
public void setContextPropagation(ContextPropagationMode contextPropagation) {
|
||||
this.contextPropagation = contextPropagation;
|
||||
}
|
||||
|
||||
public enum ContextPropagationMode {
|
||||
|
||||
/**
|
||||
* Context Propagation is applied to all Reactor operators.
|
||||
*/
|
||||
AUTO,
|
||||
|
||||
/**
|
||||
* Context Propagation is only applied to "tap" and "handle" Reactor operators.
|
||||
*/
|
||||
LIMITED
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2012-2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Reactor.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.reactor;
|
|
@ -2176,6 +2176,10 @@
|
|||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.reactor.context-propagation",
|
||||
"defaultValue": "auto"
|
||||
},
|
||||
{
|
||||
"name": "spring.reactor.stacktrace-mode.enabled",
|
||||
"description": "Whether Reactor should collect stacktrace information at runtime.",
|
||||
|
|
|
@ -93,6 +93,7 @@ org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration
|
|||
org.springframework.boot.autoconfigure.netty.NettyAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.r2dbc.R2dbcTransactionManagerAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2012-2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.reactor;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import io.micrometer.context.ContextRegistry;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.Context;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReactorAutoConfiguration}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class ReactorAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactorAutoConfiguration.class));
|
||||
|
||||
private static final String THREADLOCAL_KEY = "ReactorAutoConfigurationTests";
|
||||
|
||||
private static final ThreadLocal<String> THREADLOCAL_VALUE = ThreadLocal.withInitial(() -> "failure");
|
||||
|
||||
@BeforeAll
|
||||
static void initializeThreadLocalAccessors() {
|
||||
ContextRegistry globalRegistry = ContextRegistry.getInstance();
|
||||
globalRegistry.registerThreadLocalAccessor(THREADLOCAL_KEY, THREADLOCAL_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConfigureAutomaticContextPropagation() {
|
||||
AtomicReference<String> threadLocalValue = new AtomicReference<>();
|
||||
this.contextRunner.run((applicationContext) -> {
|
||||
Mono.just("test").doOnNext((element) -> threadLocalValue.set(THREADLOCAL_VALUE.get()))
|
||||
.contextWrite(Context.of(THREADLOCAL_KEY, "success")).block();
|
||||
assertThat(threadLocalValue.get()).isEqualTo("success");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -21,4 +21,7 @@ For JDBC, the https://github.com/jdbc-observations/datasource-micrometer[Datasou
|
|||
Read more about it https://jdbc-observations.github.io/datasource-micrometer/docs/current/docs/html/[in the reference documentation].
|
||||
For R2DBC, the https://github.com/spring-projects-experimental/r2dbc-micrometer-spring-boot[Spring Boot Auto Configuration for R2DBC Observation] creates observations for R2DBC query invocations.
|
||||
|
||||
Observability support relies on the https://github.com/micrometer-metrics/context-propagation[Context Propagation library] for forwarding the current observation across threads and reactive pipelines.
|
||||
`ThreadLocal` values are automatically reinstated in reactive operators, this behavior is controlled with the configprop:spring.reactor.context-propagation[] property.
|
||||
|
||||
The next sections will provide more details about logging, metrics and traces.
|
||||
|
|
Loading…
Reference in New Issue