Skip to content

JVM Hangs on gRPC if you don't close Spanner Object #2315

Closed

Description

@ericandrewschmidt

I ran across a path with the Java Spanner client that if you create several Spanner instances and do not explicitly close them the JVM will hang (it will not terminate it's process after code execution).

To reproduce the behavior create an object that wraps Spanner creation. Create the object several times in a loop. Then execute some additional code.

You can see the hanging wait on KQueueArrayWrapper.

Thanks.

screen shot 2017-08-07 at 9 05 21 pm

screen shot 2017-08-07 at 9 05 36 pm

Activity

  1. added
    api: spannerIssues related to the Spanner API.
    priority: p2Moderately-important priority. Fix may not be included in next release.
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    on Aug 8, 2017
  2. garrettjonesgoogle commented on Aug 10, 2017

    @garrettjonesgoogle
    Contributor

    We may creating non-daemon threads somewhere.

  3. vkedia commented on Aug 22, 2017

    @vkedia

    @ericandrewschmidt Does this only happen if you create multiple instance of Spanner object?
    Also are you creating multiple SpannerOptions or are you creating a single SpannerOptions and multiple Spanner instances from that?
    It will be useful if you can put a short code snippet showing exactly how you are creating the spanner objects.
    @garrettjonesgoogle Only explicit thread we create in spanner library is a daemon thread:
    https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/WatchdogInterceptor.java#L106

  4. vkedia commented on Sep 12, 2017

    @vkedia
  5. pongad commented on Jan 19, 2018

    @pongad
    Contributor

    I'll close this due to inactivity. Please reopen if you are still seeing this problem.

  6. TJ-Liu commented on May 15, 2019

    @TJ-Liu

    I experience similar thing.
    Our application did:

    SpannerOptions options = SpannerOptions.newBuilder().setProjectId(projectId).build();
    Spanner spanner = options.getService();
    dbClient = spanner.getDatabaseClient(DatabaseId.of(options.getProjectId(), instance, database));
    

    In our application Spanner is not closed gracefully and the application hangs after dbClient read/write some requests. It has been hanging for days until reboot manually.

    I am adding a fix to our application to fix this. But hanging without giving any error message isn't really helpful for debugging...

  7. sduskis commented on May 16, 2019

    @sduskis
    Contributor

    @TJ-Liu which version of the client are you using?

  8. assigned and unassigned on May 16, 2019
  9. olavloite commented on May 16, 2019

    @olavloite
    Contributor

    I can confirm this behavior in all recent versions of the client library. I tested from 1.14.0 to 1.19.0, and they all show this behavior using this simple application:

      public static void main(String[] args) throws IOException {
        System.out.println("Starting application");
        SpannerOptions options = SpannerOptions.newBuilder().setProjectId("test-project")
            .setCredentials(GoogleCredentials.fromStream(new FileInputStream("key.json")))
            .build();
        Spanner spanner = options.getService();
        DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of("test-project", "test-instance", "test-db"));
        try(ResultSet rs = client.singleUse().executeQuery(Statement.of("SELECT 1" ))) {
          while(rs.next()) {
            // do nothing
          }
        }
        System.out.println("Finished application");
      }

    It seems it is caused by the default executor that is created here:

    ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(8);

    Changing that executor to create daemon threads solves the problem and will allow the above example program to shutdown automatically at the end of the main method.

    @sduskis I would think that this is something that should be changed in google-cloud-core-grpc and not something that the Spanner library should try to work around. Or is there a reason why this class is not creating daemon threads?

  10. olavloite commented on May 16, 2019

    @olavloite
    Contributor

    Note to all above: Even though this problem should be fixed, it is still always a good idea to close a Spanner instance at the end of your application. Spanner#close() will close all connections and clean up all sessions that have been created on the backend Cloud Spanner servers. Failing to do so, will keep sessions living longer on the backend than is necessary. Spanner has a limit on the number of open sessions per node, and you could run into this limit if you fail to close your Spanner instances.

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

Metadata

Metadata

Assignees

Labels

🚨 criticalP0 critical issue. Requires immediate fixapi: spannerIssues related to the Spanner API.priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions