Skip to content

Commit 0e8b0e6

Browse files
Copilotaepfli
andcommitted
Document selector migration guidance for in-process mode
Co-authored-by: aepfli <[email protected]>
1 parent 0f0654f commit 0e8b0e6

File tree

1 file changed

+89
-1
lines changed

1 file changed

+89
-1
lines changed

providers/flagd/README.md

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,88 @@ FlagdProvider flagdProvider = new FlagdProvider(
4747

4848
In the above example, in-process handlers attempt to connect to a sync service on address `localhost:8013` to obtain [flag definitions](https://github.com/open-feature/schemas/blob/main/json/flags.json).
4949

50+
#### Selector filtering (In-process mode only)
51+
52+
The `selector` option allows filtering flag configurations from flagd based on source identifiers when using the in-process resolver. This is useful when flagd is configured with multiple flag sources and you want to sync only a specific subset.
53+
54+
##### Current implementation (Request body)
55+
56+
The current implementation passes the selector in the gRPC request body via the `SyncFlagsRequest`:
57+
58+
```java
59+
FlagdProvider flagdProvider = new FlagdProvider(
60+
FlagdOptions.builder()
61+
.resolverType(Config.Resolver.IN_PROCESS)
62+
.selector("source=my-app")
63+
.build());
64+
```
65+
66+
Or via environment variable:
67+
```bash
68+
export FLAGD_SOURCE_SELECTOR="source=my-app"
69+
```
70+
71+
##### Migration to header-based selector
72+
73+
> [!IMPORTANT]
74+
> **Selector normalization and deprecation notice**
75+
>
76+
> As part of [flagd issue #1814](https://github.com/open-feature/flagd/issues/1814), the flagd project is normalizing selector handling across all services. The preferred approach is to use the `flagd-selector` gRPC metadata header instead of the request body field.
77+
>
78+
> **Current status:**
79+
> - The Java SDK currently uses the **request body** approach (via `SyncFlagsRequest.setSelector()`)
80+
> - flagd services support both request body and header for backward compatibility
81+
> - In a future major version, the request body selector field may be removed from flagd
82+
>
83+
> **Recommended migration path:**
84+
>
85+
> To prepare for future changes and align with the preferred approach, you can pass the selector via gRPC headers using a custom `ClientInterceptor`:
86+
87+
```java
88+
import io.grpc.*;
89+
90+
private static ClientInterceptor createSelectorHeaderInterceptor(String selector) {
91+
return new ClientInterceptor() {
92+
@Override
93+
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
94+
MethodDescriptor<ReqT, RespT> method,
95+
CallOptions callOptions,
96+
Channel next) {
97+
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
98+
next.newCall(method, callOptions)) {
99+
@Override
100+
public void start(Listener<RespT> responseListener, Metadata headers) {
101+
headers.put(
102+
Metadata.Key.of("flagd-selector", Metadata.ASCII_STRING_MARSHALLER),
103+
selector
104+
);
105+
super.start(responseListener, headers);
106+
}
107+
};
108+
}
109+
};
110+
}
111+
112+
// Use the interceptor when creating the provider
113+
List<ClientInterceptor> interceptors = new ArrayList<>();
114+
interceptors.add(createSelectorHeaderInterceptor("source=my-app"));
115+
116+
FlagdProvider flagdProvider = new FlagdProvider(
117+
FlagdOptions.builder()
118+
.resolverType(Config.Resolver.IN_PROCESS)
119+
.clientInterceptors(interceptors)
120+
// Note: You can still use .selector() for backward compatibility
121+
// but the header approach is preferred for future-proofing
122+
.build());
123+
```
124+
125+
**Backward compatibility:**
126+
- The current request body approach will continue to work with flagd services that support it
127+
- Both approaches can be used simultaneously during the migration period
128+
- The Java SDK will be updated in a future major version to use headers by default
129+
130+
For more details on selector normalization, see the [flagd selector normalization issue](https://github.com/open-feature/flagd/issues/1814).
131+
50132
#### Sync-metadata
51133

52134
To support the injection of contextual data configured in flagd for in-process evaluation, the provider exposes a `getSyncMetadata` accessor which provides the most recent value returned by the [GetMetadata RPC](https://buf.build/open-feature/flagd/docs/main:flagd.sync.v1#flagd.sync.v1.FlagSyncService.GetMetadata).
@@ -119,7 +201,7 @@ Given below are the supported configurations:
119201
| deadline | FLAGD_DEADLINE_MS | int | 500 | rpc & in-process & file |
120202
| streamDeadlineMs | FLAGD_STREAM_DEADLINE_MS | int | 600000 | rpc & in-process |
121203
| keepAliveTime | FLAGD_KEEP_ALIVE_TIME_MS | long | 0 | rpc & in-process |
122-
| selector | FLAGD_SOURCE_SELECTOR | String | null | in-process |
204+
| selector | FLAGD_SOURCE_SELECTOR | String | null | in-process (see [migration guidance](#selector-filtering-in-process-mode-only)) |
123205
| providerId | FLAGD_SOURCE_PROVIDER_ID | String | null | in-process |
124206
| cache | FLAGD_CACHE | String - lru, disabled | lru | rpc |
125207
| maxCacheSize | FLAGD_MAX_CACHE_SIZE | int | 1000 | rpc |
@@ -130,6 +212,9 @@ Given below are the supported configurations:
130212

131213
> [!NOTE]
132214
> Some configurations are only applicable for RPC resolver.
215+
216+
> [!WARNING]
217+
> The `selector` option currently uses the gRPC request body approach, which may be deprecated in future flagd versions. See [Selector filtering](#selector-filtering-in-process-mode-only) for migration guidance to the header-based approach.
133218
>
134219
135220
### Unix socket support
@@ -189,6 +274,9 @@ FlagdProvider flagdProvider = new FlagdProvider(
189274

190275
The `clientInterceptors` and `defaultAuthority` are meant for connection of the in-process resolver to a Sync API implementation on a host/port, that might require special credentials or headers.
191276

277+
> [!TIP]
278+
> `ClientInterceptor` can also be used to pass the `flagd-selector` header for selector-based filtering. See [Selector filtering](#selector-filtering-in-process-mode-only) for details on the preferred header-based approach.
279+
192280
```java
193281
private static ClientInterceptor createHeaderInterceptor() {
194282
return new ClientInterceptor() {

0 commit comments

Comments
 (0)