Commit 629c14c
authored
fix: Not break gRPC transport for emulator.
## Problem Statement
When using the `java-datastore` SDK with `GrpcTransportOptions` and connecting
to a local Datastore Emulator (e.g., via the `DATASTORE_EMULATOR_HOST`
environment variable), the client consistently throws an `UNAUTHENTICATED:
Request is missing required authentication credential` error.
### The Root Cause
In `GrpcDatastoreRpc.java`, the SDK constructor detects the emulator correctly
and creates an unauthenticated, plaintext gRPC channel specifically tailored for
local development via `getClientContextForEmulator(datastoreOptions)`.
However, right after generating this specialized context, the SDK uses a builder
(`DatastoreStubSettings.newBuilder`) that **unconditionally overwrites** the
transport channel provider with a default production-oriented channel provider
in order to set channel pooling limits.
Because the emulator's custom local channel gets overwritten by this production
channel configuration, the SDK ultimately discards the emulator settings and
attempts to connect securely to the actual production endpoint
(`datastore.googleapis.com`), but without any credentials (since it knows it's
an emulator). Production immediately rejects the call.
## The Fix
The fix converts the monolithic `DatastoreStubSettings` builder chain into a
sequential one, and conditionally applies the custom channel pooling provider
only if the environment is **not** an emulator:
```java
DatastoreStubSettings.Builder datastoreStubSettingsBuilder =
DatastoreStubSettings.newBuilder(clientContext)
.applyToAllUnaryMethods(retrySettingSetter(datastoreOptions));
if (!isEmulator(datastoreOptions)) {
datastoreStubSettingsBuilder.setTransportChannelProvider(
// ... Production connection pool settings
);
}
```
## Why this is a safe fix without side effects
1. **Zero Impact on Production Traffic:** The fix relies exclusively on the
existing, battle-tested `isEmulator()` method. If the SDK is pointed at
production, `!isEmulator` returns true, and the code path executes the exact
same transport channel override as before. Production throughput, connection
pooling, and auth behavior remain 100% untouched.
2. **Restores Original Intent:** For emulator traffic, the channel provider
override is gracefully skipped. This allows the custom, unauthenticated
local gRPC channel created specifically for the emulator in
`getClientContextForEmulator()` to survive and be used by the
`GrpcDatastoreStub`.
3. **Architecturally Safe:** It introduces no new dependencies, requires no new
variables or complex state management, and makes no changes to the public
API surface. It simply resolves an unintentional clobbering of configuration
variables at object instantiation time.1 parent 91eb471 commit 629c14c
File tree
1 file changed
+15
-13
lines changed- java-datastore/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1
1 file changed
+15
-13
lines changedLines changed: 15 additions & 13 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
79 | | - | |
| 78 | + | |
| 79 | + | |
80 | 80 | | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
92 | 94 | | |
93 | 95 | | |
94 | 96 | | |
| |||
0 commit comments