-
Notifications
You must be signed in to change notification settings - Fork 227
Add baggage support #1659
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
siri-varma
wants to merge
17
commits into
dapr:master
Choose a base branch
from
siri-varma:users/svegiraju/add-baggage
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+463
−1
Open
Add baggage support #1659
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
5973074
Add baggage
siri-varma 17d6584
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma 2403e57
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma 4f434d1
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma f4a2452
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma 25ae330
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma cf8ed70
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma 33686be
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma b743a39
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma e49d03f
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma f24ec5f
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma 6e5bdd9
Merge branch 'master' into users/svegiraju/add-baggage
cicoyle c519d11
Merge branch 'master' into users/svegiraju/add-baggage
siri-varma 8e5c4e6
Update sdk/src/test/java/io/dapr/client/DaprClientGrpcBaggageTest.java
siri-varma a4150d8
Apply suggestions from code review
siri-varma ed541c2
Remove empty tearDown method in test class
siri-varma fe166be
Refactor contextWrite calls to remove casting
siri-varma File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
examples/src/main/java/io/dapr/examples/baggage/BaggageClient.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| /* | ||
| * Copyright 2024 The Dapr 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 io.dapr.examples.baggage; | ||
|
|
||
| import io.dapr.client.DaprClient; | ||
| import io.dapr.client.DaprClientBuilder; | ||
| import io.dapr.client.Headers; | ||
| import io.dapr.client.domain.HttpExtension; | ||
| import reactor.util.context.Context; | ||
|
|
||
| /** | ||
| * Example demonstrating W3C Baggage propagation with the Dapr Java SDK. | ||
| * | ||
| * <p>Baggage allows propagating key-value pairs across service boundaries alongside | ||
| * distributed traces. This is useful for passing contextual information (e.g., user IDs, | ||
| * tenant IDs, feature flags) without modifying request payloads. | ||
| * | ||
| * <p>The Dapr runtime supports baggage propagation as defined by the | ||
| * <a href="https://www.w3.org/TR/baggage/">W3C Baggage specification</a>. | ||
| * | ||
| * <h2>Usage</h2> | ||
| * <ol> | ||
| * <li>Build and install jars: {@code mvn clean install}</li> | ||
| * <li>{@code cd [repo root]/examples}</li> | ||
| * <li>Start the target service: | ||
| * {@code dapr run --app-id target-service --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar | ||
| * io.dapr.examples.invoke.http.DemoService -p 3000}</li> | ||
| * <li>Run the client: | ||
| * {@code dapr run -- java -jar target/dapr-java-sdk-examples-exec.jar | ||
| * io.dapr.examples.baggage.BaggageClient}</li> | ||
| * </ol> | ||
| */ | ||
| public class BaggageClient { | ||
|
|
||
| /** | ||
| * The main method to run the baggage example. | ||
| * | ||
| * @param args command line arguments (unused). | ||
| * @throws Exception on any error. | ||
| */ | ||
| public static void main(String[] args) throws Exception { | ||
| try (DaprClient client = new DaprClientBuilder().build()) { | ||
|
|
||
| // Build the W3C Baggage header value. | ||
| // Format: key1=value1,key2=value2 | ||
| // See https://www.w3.org/TR/baggage/#header-content | ||
| String baggageValue = "userId=alice,tenantId=acme-corp,featureFlag=new-ui"; | ||
|
|
||
| System.out.println("Invoking service with baggage: " + baggageValue); | ||
|
|
||
| // Propagate baggage via Reactor context. | ||
| // The SDK automatically injects the "baggage" header into outgoing gRPC | ||
| // and HTTP requests when present in the Reactor context. | ||
| byte[] response = client.invokeMethod( | ||
| "target-service", | ||
| "say", | ||
| "hello with baggage", | ||
| HttpExtension.POST, | ||
| null, | ||
| byte[].class) | ||
| .contextWrite(Context.of(Headers.BAGGAGE, baggageValue)) | ||
| .block(); | ||
|
|
||
| if (response != null) { | ||
| System.out.println("Response: " + new String(response)); | ||
| } | ||
|
|
||
| // You can also combine baggage with tracing context. | ||
| System.out.println("\nInvoking service with baggage and tracing context..."); | ||
| response = client.invokeMethod( | ||
| "target-service", | ||
| "say", | ||
| "hello with baggage and tracing", | ||
| HttpExtension.POST, | ||
| null, | ||
| byte[].class) | ||
| .contextWrite(Context.of(Headers.BAGGAGE, baggageValue) | ||
| .put("traceparent", "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01")) | ||
| .block(); | ||
|
|
||
| if (response != null) { | ||
| System.out.println("Response: " + new String(response)); | ||
| } | ||
|
|
||
| System.out.println("Done."); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| # Baggage Propagation Example | ||
|
|
||
| This example demonstrates [W3C Baggage](https://www.w3.org/TR/baggage/) propagation using the Dapr Java SDK. | ||
|
|
||
| ## Overview | ||
|
|
||
| Baggage allows you to propagate key-value pairs across service boundaries alongside distributed traces. This is useful for passing contextual information — such as user IDs, tenant IDs, or feature flags — without modifying request payloads. | ||
|
|
||
| The Dapr runtime supports baggage propagation as described in [Dapr PR #8649](https://github.com/dapr/dapr/pull/8649). The Java SDK propagates the `baggage` header via both gRPC metadata and HTTP headers automatically when the value is present in Reactor's context. | ||
|
|
||
| ## How It Works | ||
|
|
||
| The SDK reads the `baggage` key from Reactor's `ContextView` and injects it into: | ||
| - **gRPC metadata** via `DaprBaggageInterceptor` | ||
| - **HTTP headers** via `DaprHttp` (added to the context-to-header allowlist) | ||
|
|
||
| To propagate baggage, add it to the Reactor context using `.contextWrite()`: | ||
|
|
||
| ```java | ||
| import io.dapr.client.Headers; | ||
| import reactor.util.context.Context; | ||
|
|
||
| client.invokeMethod("target-service", "say", "hello", HttpExtension.POST, null, byte[].class) | ||
| .contextWrite(Context.of(Headers.BAGGAGE, "userId=alice,tenantId=acme-corp")) | ||
| .block(); | ||
| ``` | ||
|
|
||
| The baggage value follows the [W3C Baggage header format](https://www.w3.org/TR/baggage/#header-content): | ||
| ``` | ||
| key1=value1,key2=value2 | ||
| ``` | ||
|
|
||
| Each list-member can optionally include properties: | ||
| ``` | ||
| key1=value1;property1;property2,key2=value2 | ||
| ``` | ||
|
|
||
| ## Pre-requisites | ||
|
|
||
| * [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/) | ||
| * Java JDK 11 (or greater): | ||
| * [Microsoft JDK 11](https://docs.microsoft.com/en-us/java/openjdk/download#openjdk-11) | ||
| * [Oracle JDK 11](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11) | ||
| * [OpenJDK 11](https://jdk.java.net/11/) | ||
| * [Apache Maven](https://maven.apache.org/install.html) version 3.x. | ||
|
|
||
| ## Running the Example | ||
|
|
||
| ### 1. Build and install jars | ||
|
|
||
| ```sh | ||
| # From the java-sdk root directory | ||
| mvn clean install | ||
| ``` | ||
|
|
||
| ### 2. Start the target service | ||
|
|
||
| In one terminal, start the demo service: | ||
|
|
||
| ```sh | ||
| cd examples | ||
| dapr run --app-id target-service --app-port 3000 -- \ | ||
| java -jar target/dapr-java-sdk-examples-exec.jar \ | ||
| io.dapr.examples.invoke.http.DemoService -p 3000 | ||
| ``` | ||
|
|
||
| ### 3. Run the baggage client | ||
|
|
||
| In another terminal: | ||
|
|
||
| ```sh | ||
| cd examples | ||
| dapr run -- java -jar target/dapr-java-sdk-examples-exec.jar \ | ||
| io.dapr.examples.baggage.BaggageClient | ||
| ``` | ||
|
|
||
| You should see output like: | ||
|
|
||
| ``` | ||
| Invoking service with baggage: userId=alice,tenantId=acme-corp,featureFlag=new-ui | ||
| Response: ... | ||
| Done. | ||
| ``` | ||
|
|
||
| ## Combining Baggage with Tracing | ||
|
|
||
| You can propagate both baggage and tracing context together by adding multiple entries to the Reactor context: | ||
|
|
||
| ```java | ||
| client.invokeMethod("target-service", "say", "hello", HttpExtension.POST, null, byte[].class) | ||
| .contextWrite(Context.of(Headers.BAGGAGE, "userId=alice") | ||
| .put("traceparent", "00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01")) | ||
| .block(); | ||
| ``` | ||
|
|
||
| Both the `baggage` and `traceparent` headers will be propagated to downstream services via Dapr. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
sdk/src/main/java/io/dapr/internal/grpc/interceptors/DaprBaggageInterceptor.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /* | ||
| * Copyright 2024 The Dapr 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 io.dapr.internal.grpc.interceptors; | ||
|
|
||
| import io.dapr.client.Headers; | ||
| import io.grpc.CallOptions; | ||
| import io.grpc.Channel; | ||
| import io.grpc.ClientCall; | ||
| import io.grpc.ClientInterceptor; | ||
| import io.grpc.ForwardingClientCall; | ||
| import io.grpc.Metadata; | ||
| import io.grpc.MethodDescriptor; | ||
| import reactor.util.context.ContextView; | ||
|
|
||
| /** | ||
| * Injects W3C Baggage header into gRPC metadata from Reactor's context. | ||
| */ | ||
| public class DaprBaggageInterceptor implements ClientInterceptor { | ||
|
|
||
| private static final Metadata.Key<String> BAGGAGE_KEY = | ||
| Metadata.Key.of(Headers.BAGGAGE, Metadata.ASCII_STRING_MARSHALLER); | ||
|
|
||
| private final ContextView context; | ||
|
|
||
| /** | ||
| * Creates an instance of the baggage interceptor for gRPC. | ||
| * | ||
| * @param context Reactor's context | ||
| */ | ||
| public DaprBaggageInterceptor(ContextView context) { | ||
| this.context = context; | ||
| } | ||
|
|
||
| @Override | ||
| public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall( | ||
| MethodDescriptor<ReqT, RespT> methodDescriptor, | ||
| CallOptions callOptions, | ||
| Channel channel) { | ||
| ClientCall<ReqT, RespT> clientCall = channel.newCall(methodDescriptor, callOptions); | ||
| return new ForwardingClientCall.SimpleForwardingClientCall<>(clientCall) { | ||
| @Override | ||
| public void start(final Listener<RespT> responseListener, final Metadata metadata) { | ||
| if (context != null && context.hasKey(Headers.BAGGAGE)) { | ||
| String baggageValue = context.get(Headers.BAGGAGE).toString(); | ||
| if (baggageValue != null && !baggageValue.isEmpty()) { | ||
| metadata.put(BAGGAGE_KEY, baggageValue); | ||
| } | ||
| } | ||
| super.start(responseListener, metadata); | ||
| } | ||
| }; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.