Skip to content

feat: DH-19901: Use grpc-java in JS API#7878

Merged
niloc132 merged 54 commits intodeephaven:mainfrom
niloc132:19901-grpc-gwt
Apr 20, 2026
Merged

feat: DH-19901: Use grpc-java in JS API#7878
niloc132 merged 54 commits intodeephaven:mainfrom
niloc132:19901-grpc-gwt

Conversation

@niloc132
Copy link
Copy Markdown
Member

@niloc132 niloc132 commented Apr 7, 2026

This is in part a backport from DHE, bringing grpc-java and protobuf-java support to the JS API. Removes the need to load dh-internal.js by compiling the Java protos and grpc services to JS, allowing easier code reuse and sharing, supporting more gRPC features, and removing the need to work around limitations around longs, headers, etc. Some of these changes will allow us to simplify DHE to better share code after this merges and is released.

Some grpc-java semantics are not exactly the same as in a JVM - Context's threadlocals won't play nicely with browser Promises for example, so must be explicitly propagated when used.

More cleanup is possible than has been done here - BiDiStream should no longer be necessary, but can just be a normal pair of StreamObservers. All of web/client-backplane can be deleted, but that would substantially bloat this patch, so I've left it out for now.

@niloc132 niloc132 added this to the 42.0 milestone Apr 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 7, 2026

No docs changes detected for 485deb9

@niloc132
Copy link
Copy Markdown
Member Author

niloc132 commented Apr 7, 2026

Marked as a draft for now, I have a few outstanding work items to complete, but all integration tests pass and local websocket use seems to function.

  • Test h2/tls
  • Test custom transports (integration tests pass, but will test vscode directly)
  • restore custom header support (e.g. for envoy request routing)

@niloc132 niloc132 requested a review from Copilot April 7, 2026 16:27
ref.setTicket(op.getSource().makeTicket());
} else {
// every subsequent pb op references the entry before it
ref.setBatchOffset(send.length + internalOffset);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've done testing to make this work, but rather than spend more minutes puzzling over why we don't need to include the size of the list in our batch offset anymore I figured I could just ask.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it works out that a lot of this machinery is never actually used - the client sends batches when appropriate, but doesn't actually use the offset feature at all via BatchBuilder, but specifies tickets for each node in the DAG. That lets the client explicitly retain exports and rebuild partway as it believes it is appropriate, rather than rely on memoization and refcount/gc.

aggColumns.forEach((p0, p1) -> {
aggColumns.forEach((p0) -> {
String colName = p0.split("=")[0].trim();
customColumns.push(colName + "= `` + " + colName);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we toStringing the columns here? I know it isn't new, but I am certainly suspicious.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#3662 (comment)

It looks like I'm throwing Ryan under the bus here - but this is just for the post-agg display. Now that we can support arrays of just about any kind, we should be able to remove that extra step.

return workerConnection.newState((c, state, metadata) -> {
AsOfJoinTablesRequest request = new AsOfJoinTablesRequest();
return workerConnection.newState((c, state) -> {
AsOfJoinTablesRequest.Builder request = AsOfJoinTablesRequest.newBuilder();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not a terrible time to do https://deephaven.atlassian.net/browse/DH-19188

If not in this PR as a simple follow-on?

Copy link
Copy Markdown
Member Author

@niloc132 niloc132 Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reopened, will do this and the agg cleanup(s) in a followup.

@niloc132 niloc132 marked this pull request as ready for review April 15, 2026 16:37
DomGlobal.fetch(options.url, init).then(response -> {
if (!abortController.signal.aborted) {
options.onHeaders.onHeaders(readHeaders(response.headers), response.status);
assert response.body != null : "Browser should always include a response body";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assert seems to contradict the response.body comment on line 66

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with better comments and an if just in case browsers do decide to someday follow the spec.

@niloc132 niloc132 merged commit 3615c92 into deephaven:main Apr 20, 2026
24 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants