void connect(SocketAddress remoteAddress, SessionProtocol desiredProtocol,
                 SerializationFormat serializationFormat,
                 PoolKey poolKey, Promise<Channel> sessionPromise,
                 @Nullable ClientConnectionTimingsBuilder timingsBuilder) {
        final Bootstrap bootstrap;
        try {
            bootstrap = bootstraps.getOrCreate(remoteAddress, desiredProtocol, serializationFormat);
        } catch (Exception e) {
            sessionPromise.tryFailure(e);
            return;
        }

        bootstrap.register().addListener((ChannelFuture registerFuture) -> {
            if (!registerFuture.isSuccess()) {
                sessionPromise.tryFailure(registerFuture.cause());
                return;
            }

            try {
                final Channel channel = registerFuture.channel();
                configureProxy(channel, poolKey.proxyConfig, desiredProtocol);

                if (desiredProtocol.isTls() && timingsBuilder != null) {
                    channel.attr(TIMINGS_BUILDER_KEY).set(timingsBuilder);
                }

                // should be invoked right before channel.connect() is invoked as defined in javadocs
                clientFactory.channelPipelineCustomizer().accept(channel.pipeline());

                final ChannelPromise connectionPromise = channel.newPromise();
                // Add a listener in advance so that the HTTP/1 pipeline can deliver the SessionProtocol event
                // to HttpSessionHandler.
                connectionPromise.addListener((ChannelFuture connectFuture) -> {
                    if (connectFuture.isSuccess()) {
                        initSession(desiredProtocol, serializationFormat,
                                    poolKey, connectFuture, sessionPromise);
                    } else {
                        maybeHandleProxyFailure(desiredProtocol, poolKey, connectFuture.cause());
                        sessionPromise.tryFailure(connectFuture.cause());
                    }
                });
                channel.connect(remoteAddress, connectionPromise);
            } catch (Throwable cause) {
                maybeHandleProxyFailure(desiredProtocol, poolKey, cause);
                sessionPromise.tryFailure(cause);
            }
        });
    }
A low-level operation that triggers a new connection attempt. Used only by:
<ul>
  <li>{@link #connect(SessionProtocol, SerializationFormat, PoolKey, ChannelAcquisitionFuture,
                      ClientConnectionTimingsBuilder)} - The pool has been exhausted.</li>
  <li>{@link HttpSessionHandler} - HTTP/2 upgrade has failed.</li>
</ul>
core/src/main/java/com/linecorp/armeria/client/HttpChannelPool.java