feat(generator): emit resumable upload settings and HttpJson upload stub - #14321
Conversation
f246196 to
1885bb8
Compare
1885bb8 to
542f6e7
Compare
542f6e7 to
6f00489
Compare
6f00489 to
296ed15
Compare
296ed15 to
bbc408e
Compare
bbc408e to
c8c1e06
Compare
c8c1e06 to
c41b295
Compare
c41b295 to
63a3b57
Compare
63a3b57 to
f014476
Compare
f014476 to
46d6fdf
Compare
46d6fdf to
2525926
Compare
2525926 to
2f42f31
Compare
| */ | ||
| public static HttpJsonResumableUploadServiceResumableUploadStub createFrom( | ||
| ClientContext clientContext, ResumableUploadServiceStubSettings settings) { | ||
| String uploadEndpoint = |
There was a problem hiding this comment.
Maybe create a new clientContext using ClientContext.create(settings)? So we don't have to manually re-create the clientContext from existing clientContext?
There was a problem hiding this comment.
After more investigation, I think ClientContext.create(settings) should work for httpjson stub without any issues. For grpc stub, we need to recreate the settings with a default internal header provider and httpjson channel, then ClientContext.create(settings) should work.
There was a problem hiding this comment.
Hmmm, I guess I'm not seeing how calling ClientContext.create(settings) inside the upload stub without referencing the parent context can avoid at least two main issues:
- for both transports, in the top-level stub layer's
create(ClientContext)factory overload,settingsis just<Service>StubSettings.newBuilder().build(), so if we re-create fromsettingsthen everything caller-supplied on theClientContextis dropped. We'd also be creating a separate thread pool and doing another ADC lookup on every client instance (even on REST stubs that already built an HTTPClientContext- this I guess isn't functionally a problem, just suboptimal). - we can't swap the gRPC internal headers (
x-goog-api-client: ... grpc/...) for HTTP headers viasettings.toBuilder()becauseStubSettings.Builder#setInternalHeaderProviderisprotectedand in a different package (unless you think it's worth widening it for this, but the above issue still seems like a blocker alone)
There was a problem hiding this comment.
Took another look at this - I still don't see how we can fully rebuild from just settings without using some of the "parent" clientContext? In this PR as-is the generated code is pretty ugly but perhaps pushing that into the ClientContext itself makes sense - prototyped #14412 for illustration.
There was a problem hiding this comment.
ClientContext is not the source of truth and users are not supposed to modify it directly, it is derived from StubSettings which is considered the source of truth for all the customization. Also see the javadocs for ClientContext.
For thread pool and ADC, I do agree it is a slightly overhead, but it might be OK for simplicity. For the least performance overhead, we can use clientContext directly for httpjson and recreate clientContext from StubSettings for grpc.
StubSettings.Builder#setInternalHeaderProvider is indeed a problem. We could expose a new toHttpJsonBuilder() that copies everything but change the internal header provider to httpjson format.
There was a problem hiding this comment.
Since we're OK with the thread pool/ADC inefficiency this now is just creating fresh ClientContext. To make the internal headers work, there's now a generated setHttpJsonInternalHeaderProvider on the <Service>StubSettings.Builder that's only added for services that need resumable upload support.
| * settings. This is protected so that it is easy to make a subclass, but otherwise, the static | ||
| * factory methods should be preferred. | ||
| */ | ||
| protected HttpJsonResumableUploadServiceResumableUploadStub( |
There was a problem hiding this comment.
We have three constructor/factory methods that have the same arguments, consider consolidate them.
There was a problem hiding this comment.
Modified this to have one private constructor and one factory method (which has a conditional to adapt for gRPC v. HTTP/JSON).
57daa1f to
954089e
Compare
| RetrySettings settings = null; | ||
| settings = RetrySettings.newBuilder().setRpcTimeoutMultiplier(1.0).build(); | ||
| definitions.put("no_retry_params", settings); | ||
| RETRY_PARAM_DEFINITIONS = definitions.build(); |
There was a problem hiding this comment.
The retry settings are not used currently, we need to add the initial unary call settings to ResumableUploadCallSettings. I'll work on it in a separate PR.
954089e to
5821e21
Compare
c7cffbf to
82fe151
Compare
| .build()) | ||
| .setTransportChannelProvider( | ||
| InstantiatingHttpJsonChannelProvider.newBuilder() | ||
| .setEndpoint(settings.getEndpoint()) |
There was a problem hiding this comment.
Endpoint will be set in ClientContext, I don't think we need to set endpoint explicitly. For non-httpjson, I think we can use a default InstantiatingHttpJsonChannelProvider.
| .setTransportToken( | ||
| GaxHttpJsonProperties.getHttpJsonTokenName(), | ||
| GaxHttpJsonProperties.getHttpJsonVersion()) | ||
| .setQuotaProjectIdToken(settings.getQuotaProjectId()) |
There was a problem hiding this comment.
quotaProjectId is also handled in ClientContext, we don't have to set it here.
| uploadMediaCallable; | ||
|
|
||
| public static HttpJsonResumableUploadServiceResumableUploadStub create( | ||
| ClientContext clientContext, ResumableUploadServiceStubSettings settings) throws IOException { |
There was a problem hiding this comment.
Do we still need to pass clientContext in if we are always recreating it from settings? I think we can use info from settings to determine if the setting is for grpc or httpjson.
There was a problem hiding this comment.
I had intended that create would operate only on settings on the last round but clearly didn't get all the way there - apologies for the churn.
Now using only settings, withsettings.getTransportChannelProvider().getTransportName().equals(HttpJsonTransportChannel.getHttpJsonTransportName()) as the condition to determine whether we need to derive the ClientContext from gRPC.
Adds generator support for protocol-specific resumable upload options, independent of any transport stub wiring: - Emit ResumableUploadCallSettings on the generated <Service>Settings and <Service>StubSettings, populated with global timeouts extracted from the service config while bypassing standard unary retries. - Add HttpJsonServiceResumableUploadStubClassComposer, which generates the dedicated REST stub (HttpJson[Service]ResumableUploadStub) for services containing resumable upload RPC methods. - Extract HttpJsonDescriptorComposer out of HttpJsonServiceStubClassComposer and add path prefix support. Pure refactor with no golden changes, reused by the upload stub composer above. Supersedes #14318 and #14320, which are folded in here.
82fe151 to
1dee45d
Compare
commented
Sep 18, 2026
|
commented
Sep 18, 2026
|
| settings | ||
| .toBuilder() | ||
| .setHttpJsonInternalHeaderProvider( | ||
| ApiClientHeaderProvider.newBuilder() |
There was a problem hiding this comment.
Not in this PR: There might be a better way to do this without exposing a protected method. Or at least share the same generation code as the defaultHttpJsonHeaderProvider.



Modified and introduces composers to emit an internal, dedicated REST stub and settings for resumable upload-powered services