final void fail(long now, Throwable throwable) {
            if (curNode != null) {
                runnable.nodeReadyDeadlines.remove(curNode);
                curNode = null;
            }
            // If the admin client is closing, we can't retry.
            if (runnable.closing) {
                handleFailure(throwable);
                return;
            }
            // If this is an UnsupportedVersionException that we can retry, do so. Note that a
            // protocol downgrade will not count against the total number of retries we get for
            // this RPC. That is why 'tries' is not incremented.
            if ((throwable instanceof UnsupportedVersionException) &&
                     handleUnsupportedVersionException((UnsupportedVersionException) throwable)) {
                log.debug("{} attempting protocol downgrade and then retry.", this);
                runnable.pendingCalls.add(this);
                return;
            }
            nextAllowedTryMs = now + retryBackoff.backoff(tries++);

            // If the call has timed out, fail.
            if (calcTimeoutMsRemainingAsInt(now, deadlineMs) <= 0) {
                handleTimeoutFailure(now, throwable);
                return;
            }
            // If the exception is not retriable, fail.
            if (!(throwable instanceof RetriableException)) {
                if (log.isDebugEnabled()) {
                    log.debug("{} failed with non-retriable exception after {} attempt(s)", this, tries,
                        new Exception(prettyPrintException(throwable)));
                }
                handleFailure(throwable);
                return;
            }
            // If we are out of retries, fail.
            if (tries > maxRetries) {
                handleTimeoutFailure(now, throwable);
                return;
            }
            if (log.isDebugEnabled()) {
                log.debug("{} failed: {}. Beginning retry #{}",
                    this, prettyPrintException(throwable), tries);
            }
            maybeRetry(now, throwable);
        }
Handle a failure.

Depending on what the exception is and how many times we have already tried, we may choose to
fail the Call, or retry it. It is important to print the stack traces here in some cases,
since they are not necessarily preserved in ApiVersionException objects.

@param now           The current time in milliseconds.
@param throwable     The failure exception.
clients/src/main/java/org/apache/kafka/clients/admin/KafkaAdminClient.java