# Close a KubeMQ Java Client (/sdks/java/how-to/connection/close)



## Overview [#overview]

Closing a client isn't an afterthought — it tells the broker and your own process that this connection is done, so both sides release what they were holding for it. A KubeMQ client is more than a socket: it's a gRPC channel plus whatever subscriptions and in-flight sends it's servicing. Skip the close and those linger — subscriptions keep streaming, the channel stays open — and in long-running services (or test suites spinning up many clients) you leak connections until the process dies.

Every KubeMQ client class implements `AutoCloseable`, so `try-with-resources` is the idiomatic way to guarantee `close()` runs when the block exits, even on exception. Calling `close()` explicitly drains in-flight operations and releases the gRPC channel and any background threads.

**Gotchas:** the drain window is bounded, not unlimited, so a slow consumer can still lose the tail of a burst if you close mid-stream; a closed client is dead forever — no reconnect on the same instance, build a new one; and when a process owns several client types (`PubSubClient`, `QueuesClient`, `CQClient`), close them in reverse construction order so nothing gets routed to a channel that's already tearing down.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Java SDK installed (`implementation 'io.kubemq.sdk:kubemq-sdk-Java:3.1.1'` (Gradle) or Maven dependency from [Getting Started](/sdks/java))

## Code [#code]

```java title="CloseExample.java"
package io.kubemq.example.connection;

import io.kubemq.sdk.common.ServerInfo;
import io.kubemq.sdk.pubsub.PubSubClient;
import io.kubemq.sdk.queues.QueuesClient;
import io.kubemq.sdk.cq.CQClient;

/**
 * Close Example
 *
 * Demonstrates proper client lifecycle management: creating, using,
 * and closing KubeMQ clients. Shows try-with-resources and explicit close patterns.
 */
public class CloseExample {

    private static final String ADDRESS = "localhost:50000";
    private static final String CLIENT_ID = "java-connection-close-client";

    public void tryWithResourcesExample() {
        System.out.println("=== Try-With-Resources Pattern ===\n");

        // Client auto-closes when leaving try block
        try (QueuesClient client = QueuesClient.builder()
                .address(ADDRESS)
                .clientId(CLIENT_ID + "-twr")
                .build()) {

            ServerInfo info = client.ping();
            System.out.println("Connected: " + info.getHost());
            System.out.println("Client will be auto-closed when leaving this block.\n");

        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }

        System.out.println("Client has been automatically closed.\n");
    }

    public void explicitCloseExample() {
        System.out.println("=== Explicit Close Pattern ===\n");

        // Create client and close explicitly in finally block
        PubSubClient client = null;
        try {
            client = PubSubClient.builder()
                    .address(ADDRESS)
                    .clientId(CLIENT_ID + "-explicit")
                    .build();

            ServerInfo info = client.ping();
            System.out.println("Connected: " + info.getHost());

        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        } finally {
            if (client != null) {
                client.close();
                System.out.println("Client explicitly closed.\n");
            }
        }
    }

    public void multiClientCloseExample() {
        System.out.println("=== Multi-Client Close ===\n");

        // Create multiple clients and close in reverse order
        PubSubClient pubSubClient = null;
        QueuesClient queuesClient = null;
        CQClient cqClient = null;

        try {
            pubSubClient = PubSubClient.builder()
                    .address(ADDRESS).clientId(CLIENT_ID + "-pubsub").build();
            queuesClient = QueuesClient.builder()
                    .address(ADDRESS).clientId(CLIENT_ID + "-queues").build();
            cqClient = CQClient.builder()
                    .address(ADDRESS).clientId(CLIENT_ID + "-cq").build();

            System.out.println("Three clients created.");
            pubSubClient.ping();
            queuesClient.ping();
            cqClient.ping();
            System.out.println("All clients connected.\n");

        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        } finally {
            if (cqClient != null) { cqClient.close(); System.out.println("CQClient closed."); }
            if (queuesClient != null) { queuesClient.close(); System.out.println("QueuesClient closed."); }
            if (pubSubClient != null) { pubSubClient.close(); System.out.println("PubSubClient closed."); }
        }
    }

    public static void main(String[] args) {
        CloseExample example = new CloseExample();
        example.tryWithResourcesExample();
        example.explicitCloseExample();
        example.multiClientCloseExample();
        System.out.println("\nClose examples completed.");
    }
}

```

## How It Works [#how-it-works]

* All KubeMQ client classes implement `AutoCloseable`, so `try-with-resources` is the preferred pattern — the gRPC channel and any background threads are released automatically when the block exits, even on exception.
* The explicit `close()` call in a `finally` block is the fallback for long-lived clients that outlive a single `try` scope (e.g., Spring beans or background workers).
* When closing multiple clients, reverse-construction order (CQClient → QueuesClient → PubSubClient) avoids sending messages on a channel that is already shutting down.
* `close()` is idempotent and safe to call multiple times.

## Related [#related]

* [Java SDK Reference](/sdks/java/reference)
* [Connect](/sdks/java/tutorials/connect)
* [Ping](/sdks/java/how-to/connection/ping)
