Skip to content

fix: Prevent OkHttp idle threads from blocking JVM shutdown#1268

Merged
copybara-service[bot] merged 1 commit into
google:mainfrom
svetanis:fix/graceful-jvm-shutdown
Jul 2, 2026
Merged

fix: Prevent OkHttp idle threads from blocking JVM shutdown#1268
copybara-service[bot] merged 1 commit into
google:mainfrom
svetanis:fix/graceful-jvm-shutdown

Conversation

@svetanis

Copy link
Copy Markdown
Contributor

Prevent OkHttp idle threads from blocking JVM shutdown

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

2. Or, if no issue exists, describe the change:

Problem:
The ADK framework does not cleanly terminate the JVM upon process completion when making chat completions requests because ChatCompletionsHttpClient and the internal Gemini API client construct default OkHttpClient instances. These produce non-daemon threads with a keep-alive timeout, keeping the JVM alive.

Solution:
Created HttpUtils.createSharedHttpClient() utility method that returns an OkHttpClient using a custom dispatcher with a daemon thread factory and 5-minute timeouts. Refactored ChatCompletionsHttpClient, ApiClient, and Gemini to invoke this utility and maintain their own shared daemon-thread client pools.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

All existing core tests pass successfully. (A new test for HttpUtils can be added to verify the ThreadFactory creates daemon threads).

Manual End-to-End (E2E) Tests:

Wired the Google native chat completion client into the external model-prism project (PR #1199). Ran the integration through all the demo tests covering all main ADK features. Explicitly tested the native Gemini provider (via the google_search_agent tests) as well as third-party OpenAI-compatible providers. After the final agent response is logged, the Java process successfully exits cleanly with code 0 across all model types instead of hanging while waiting for background threads to timeout.

Checklist

  • I have read the CONTRIBUTING.md document.
  • My pull request contains a single commit.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

This fixes critical thread leaks for users running short-lived or background ADK agents.

@hemasekhar-p

Copy link
Copy Markdown
Contributor

Hi @svetanis, thank you for your contribution! We appreciate you taking the time to submit this pull request. Currently this PR is under review by our team, we will keep you posted if any additional information is required. thank you.

@hemasekhar-p

Copy link
Copy Markdown
Contributor

@anFatum, Could you please review this PR.

@hemasekhar-p hemasekhar-p self-assigned this Jun 15, 2026
@svetanis svetanis force-pushed the fix/graceful-jvm-shutdown branch from f92a4ab to b95dd45 Compare June 16, 2026 00:08
@svetanis

Copy link
Copy Markdown
Contributor Author

Hi @hemasekhar-p,

Thanks for the update! Just a quick heads up: I went ahead and rebased the branch onto the latest main so that it stays perfectly clean and conflict-free for your review.

Looking forward to hearing back from the team!

@krwc krwc left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the contribution! Left some comments requiring changes, but no major issues.

@@ -0,0 +1,62 @@
/*
* Copyright 2025 Google LLC

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: 2026

@@ -0,0 +1,29 @@
package com.google.adk.utils;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Please add copyright headers to this file.

Comment on lines +57 to +59
.connectTimeout(Duration.ofMinutes(5))
.readTimeout(Duration.ofMinutes(5))
.writeTimeout(Duration.ofMinutes(5))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

OkHttp's default timeouts are 10s. Any reason we decided to set them to 5mins now? If not, let's not change them to maintain backwards compat and let the callers decide.

import okhttp3.OkHttpClient;

/** Utility class for common HTTP client configuration across the ADK. */
public final class HttpUtils {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

While we can't make this class truly package private due to its use in multiple packages, I still think we should move it to somewhere else, indicating its not truly intended to be a part of public API of Java ADK.

How about we move it into core/src/main/java/com/google/adk/internal/http?

import okhttp3.OkHttpClient;

/** Utility class for common HTTP client configuration across the ADK. */
public final class HttpUtils {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nit: HttpClientFactory?

@krwc krwc added the waiting on reporter Waiting for reaction by reporter. Failing that, maintainers will eventually closed it as stale. label Jul 1, 2026
…hutdown

This fixes an issue where the JVM hangs waiting for background networking threads to timeout after completing an execution. Replaced default OkHttpClient builders with a new HttpUtils.createSharedHttpClient factory that injects a custom thread factory setting daemon=true.
@svetanis svetanis force-pushed the fix/graceful-jvm-shutdown branch from b95dd45 to 9b046b6 Compare July 2, 2026 02:57
@svetanis

svetanis commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@krwc,

Thanks for the review! I've addressed all your comments:

  1. Copyright: Updated the year to 2026 in HttpClientFactory and added the standard header to the test file.
  2. Rename & Move: Moved the utility to core/src/main/java/com/google/adk/internal/http/HttpClientFactory.java to indicate it is not part of the public API, and renamed the test file accordingly.
  3. Timeouts: Removed the 5-minute timeouts from HttpClientFactory. Let the callers (ChatCompletionsHttpClient and the GenAI SDK) manage their own timeouts appropriately.

Rebased onto latest main, single clean commit, all tests passing.

@krwc krwc left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM, thank you!

@krwc krwc added ready to pull and removed waiting on reporter Waiting for reaction by reporter. Failing that, maintainers will eventually closed it as stale. needs review labels Jul 2, 2026
@copybara-service copybara-service Bot merged commit ec6c45d into google:main Jul 2, 2026
8 checks passed
@krwc

krwc commented Jul 3, 2026

Copy link
Copy Markdown

FYI: we actually had to roll it back due to some issue with one of the internal systems using it. Will investigate this and try to forward fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prevent OkHttp idle threads from blocking JVM shutdown

3 participants