Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import io.quarkus.test.QuarkusUnitTest;
import io.smallrye.common.vertx.ContextLocals;
import io.smallrye.mutiny.Uni;
import io.vertx.core.Context;
import io.vertx.core.Vertx;

Expand All @@ -33,13 +34,21 @@ public class ContextLocalPropagationTest {
"http://localhost:${quarkus.http.test-port:8081}");

@Test
void testQueryParamsWithPrimitiveArrays() {
void testClientFilterSeesParentContext() {
when().get("test/invokeClient")
.then()
.statusCode(200)
.body(is("test/foo/bar"));
}

@Test
void testClientUniInheritsParentContext() {
when().get("test/client-inherits-context")
.then()
.statusCode(200)
.body(is("test/set-in-parent"));
}

@Path("test")
public static class Resource {

Expand All @@ -58,11 +67,25 @@ public String invokeClient() {
return result + "/" + fromRequest.orElse("none") + "/" + fromResponse.orElse("none");
}

@Path("client-inherits-context")
@GET
public Uni<String> clientInheritsContext() {
ContextLocals.put("parent-value", "set-in-parent");
return client.getUni()
.map(result -> result + "/" + ContextLocals.get("parent-value").orElse("none"));
}

@Path("toClient")
@GET
public String toClient() {
return "test";
}

@Path("toClient2")
@GET
public String toClient2() {
return "test";
}
}

@Path("test")
Expand All @@ -74,6 +97,10 @@ public interface Client {
@GET
@Path("toClient")
String get();

@GET
@Path("toClient2")
Uni<String> getUni();
}

public static class RequestFilter implements ClientRequestFilter {
Expand Down Expand Up @@ -110,10 +137,10 @@ private static Context determineRestClientContext() {
// We will need a proper solution soon, but as we need to have a proper way to
// set contextual information in Quarkus 3.20 (LTS), we can't risk breaking
// client code everywhere, so for now we will tell people to check the context
Optional<Object> maybeParentContext = ContextLocals.get("__PARENT_CONTEXT__");
var maybeParentContext = ContextLocals.getParentContext();
Context effectiveContext;
if (maybeParentContext.isPresent()) {
effectiveContext = (Context) maybeParentContext.get();
if (maybeParentContext != null) {
effectiveContext = maybeParentContext;
} else {
effectiveContext = Vertx.currentContext();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,7 @@ public ClientRequestContextImpl(RestClientRequestContext restClientRequestContex
// Always create a duplicated context because each REST Client invocation must have its own context
// A separate context allows integrations like OTel to create a separate Span for each invocation (expected)
Context current = client.vertx.getOrCreateContext();
this.context = VertxContext.createNewDuplicatedContext(current);
// If an interceptor wants to access the parent context, it can do so by using the "__PARENT_CONTEXT__" key.
// This approach is compatible with the next-to-be nested context support (from SmallRye Common).
// The "__PARENT_CONTEXT__" key will continue to reference the _parent_ context.
// So, currently, an interceptor needing to read from the original context will need to use:
// Context parent = ContextLocals.get("__PARENT_CONTEXT__");
// V v = parent.getLocal("some-key");
// To write to the original context, it will need to use:
// Context parent = ContextLocals.get("__PARENT_CONTEXT__");
// parent.putLocal("some-key", someValue);
// Note that unlike with nested contexts, multiple child contexts can write to the same parent key, and may
// lead to a race condition.
this.context.putLocal("__PARENT_CONTEXT__", current);
this.context = VertxContext.newNestedContext(current);
restClientRequestContext.properties.put(VERTX_CONTEXT_PROPERTY, context);
}

Expand Down
Loading