All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.ydb.core.impl.pool.GrpcChannel Maven / Gradle / Ivy

package tech.ydb.core.impl.pool;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import io.grpc.Channel;
import io.grpc.ConnectivityState;
import io.grpc.ManagedChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Nikolay Perfilov
 */
public class GrpcChannel {
    private static final long WAIT_FOR_CLOSING_MS = 1000;
    private static final Logger logger = LoggerFactory.getLogger(GrpcChannel.class);

    private final EndpointRecord endpoint;
    private final ManagedChannel channel;
    private final long connectTimeoutMs;
    private final ReadyWatcher readyWatcher;

    public GrpcChannel(EndpointRecord endpoint, ManagedChannelFactory factory, boolean tryToConnect) {
        logger.debug("Creating grpc channel with {}", endpoint);
        this.endpoint = endpoint;
        this.channel = factory.newManagedChannel(endpoint.getHost(), endpoint.getPort());
        this.connectTimeoutMs = factory.getConnectTimeoutMs();
        this.readyWatcher = new ReadyWatcher();
        this.readyWatcher.check(tryToConnect);
    }

    public EndpointRecord getEndpoint() {
        return this.endpoint;
    }

    public Channel getReadyChannel() {
        return readyWatcher.getReadyChannel();
    }

    public boolean isShutdown() {
        return channel.isShutdown();
    }

    public boolean shutdown() {
        if (isShutdown()) {
            return true;
        }

        try {
            boolean closed = channel.shutdown().awaitTermination(WAIT_FOR_CLOSING_MS, TimeUnit.MILLISECONDS);
            if (closed) {
                logger.debug("Grpc channel {} shutdown successfully", endpoint);
            } else {
                logger.warn("Grpc channel {} shutdown timeout exceeded", endpoint);
            }
            return closed;
        } catch (InterruptedException e) {
            logger.warn("transport shutdown interrupted for channel {}: {}", endpoint, e);
            Thread.currentThread().interrupt();
            return false;
        } finally {
            channel.shutdownNow();
        }
    }

    private class ReadyWatcher implements Runnable {
        private final CompletableFuture future = new CompletableFuture<>();

        public Channel getReadyChannel() {
            try {
                return future.get(connectTimeoutMs, TimeUnit.MILLISECONDS);
            } catch (InterruptedException ex) {
                logger.error("Grpc channel {} ready waiting is interrupted", endpoint, ex);
                Thread.currentThread().interrupt();
            } catch (ExecutionException ex) {
                logger.error("Grpc channel {} connecting problem", endpoint, ex);
                throw new RuntimeException("Channel " + endpoint + " connecting problem", ex);
            } catch (TimeoutException ex) {
                logger.error("Grpc channel {} connect timeout excided", endpoint);
                throw new RuntimeException("Channel " + endpoint + " connecting timeout");
            }
            return null;
        }

        public void check(boolean tryToConnect) {
            ConnectivityState state = channel.getState(tryToConnect);
            logger.debug("Grpc channel {} new state: {}", endpoint, state);
            switch (state) {
                case READY:
                    future.complete(channel);
                    break;
                case SHUTDOWN:
                    future.completeExceptionally(new IllegalStateException("Grpc channel already closed"));
                    break;
                case TRANSIENT_FAILURE:
                case CONNECTING:
                case IDLE:
                default:
                    // repeat watch
                    channel.notifyWhenStateChanged(state, this);
                    break;
            }
        }

        @Override
        public void run() {
            check(false);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy