{@inheritDoc}

<p>Handles the request with {@link BackOff}. That means that if back-off is required a call to
{@link Sleeper#sleep(long)} will be made.
494261
@Override
  public boolean handleResponse(HttpRequest request, HttpResponse response, boolean supportsRetry)
      throws IOException {
    if (!supportsRetry) {
      return false;
    }
    // check if back-off is required for this response
    if (backOffRequired.isRequired(response)) {
      try {
        return BackOffUtils.next(sleeper, backOff);
      } catch (InterruptedException exception) {
        // ignore
      }
    }
    return false;
  }
604183
private function backOff()
  {
    $delay = $this->getDelay();

    $this->client->getLogger()->debug(
        'Retrying task with backoff',
        array(
            'request' => $this->name,
            'retry' => $this->attempts,
            'backoff_seconds' => $delay
        )
    );

    usleep($delay * 1000000);
  }
808911
@GuardedBy("lock")
  private void scheduleBackoff(final Status status) {
    class EndOfCurrentBackoff implements Runnable {
      @Override
      public void run() {
        try {
          synchronized (lock) {
            reconnectTask = null;
            if (reconnectCanceled) {
              // Even though cancelReconnectTask() will cancel this task, the task may have already
              // started when it's being canceled.
              return;
            }
            channelLogger.log(ChannelLogLevel.INFO, "CONNECTING after backoff");
            gotoNonErrorState(CONNECTING);
            startNewTransport();
          }
        } catch (Throwable t) {
          // TODO(zhangkun): we may consider using SynchronizationContext to schedule the reconnect
          // timer, so that we don't need this catch, since SynchronizationContext would catch it.
          log.log(Level.WARNING, "Exception handling end of backoff", t);
        } finally {
          syncContext.drain();
        }
      }
    }

    gotoState(ConnectivityStateInfo.forTransientFailure(status));
    if (reconnectPolicy == null) {
      reconnectPolicy = backoffPolicyProvider.get();
    }
    long delayNanos =
        reconnectPolicy.nextBackoffNanos() - connectingTimer.elapsed(TimeUnit.NANOSECONDS);
    channelLogger.log(
        ChannelLogLevel.INFO,
        "TRANSIENT_FAILURE ({0}). Will reconnect after {1} ns",
        printShortStatus(status), delayNanos);
    Preconditions.checkState(reconnectTask == null, "previous reconnectTask is not done");
    reconnectCanceled = false;
    reconnectTask = scheduledExecutor.schedule(
        new LogExceptionRunnable(new EndOfCurrentBackoff()),
        delayNanos,
        TimeUnit.NANOSECONDS);
  }
605280
boolean detectAndHandleBackupTimeout(long timeoutMillis) {
        // if the backups have completed, we are done; this also filters out all non backup-aware operations
        // since the backupsAcksExpected will always be equal to the backupsAcksReceived
        boolean backupsCompleted = backupsAcksExpected == backupsAcksReceived;
        long responseReceivedMillis = pendingResponseReceivedMillis;

        // if this has not yet expired (so has not been in the system for a too long period) we ignore it
        long expirationTime = responseReceivedMillis + timeoutMillis;
        boolean timeout = expirationTime > 0 && expirationTime < Clock.currentTimeMillis();

        // if no response has yet been received, we we are done; we are only going to re-invoke an operation
        // if the response of the primary has been received, but the backups have not replied
        boolean responseReceived = pendingResponse != VOID;

        if (backupsCompleted || !responseReceived || !timeout) {
            return false;
        }

        if (shouldFailOnIndeterminateOperationState()) {
            complete(new IndeterminateOperationStateException(this + " failed because backup acks missed."));
            return true;
        }

        boolean targetDead = context.clusterService.getMember(targetAddress) == null;
        if (targetDead) {
            // the target doesn't exist, so we are going to re-invoke this invocation;
            // the reason for the re-invocation is that otherwise it's possible to lose data,
            // e.g. when a map.put() was done and the primary node has returned the response,
            // but has not yet completed the backups and then the primary node fails;
            // the consequence would be that the backups are never be made and the effects of the map.put() will never be visible,
            // even though the future returned a value;
            // so if we would complete the future, a response is sent even though its changes never made it into the system
            resetAndReInvoke();
            return false;
        }

        // the backups have not yet completed, but we are going to release the future anyway if a pendingResponse has been set
        complete(pendingResponse);
        return true;
    }
933392
public void wait(int retry) {
        long sleepMillis = BACKOFF[Math.min(retry, BACKOFF.length - 1)] * 1000L;
        try {
            Thread.sleep(sleepMillis);
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
            throw new WebbException(ie);
        }
    }
1116412
public CallbackRequest handle(HttpServletRequest req) throws LineBotCallbackException, IOException {
        // validate signature
        String signature = req.getHeader("X-Line-Signature");
        final byte[] json = ByteStreams.toByteArray(req.getInputStream());
        return handle(signature, new String(json, StandardCharsets.UTF_8));
    }
351261
private synchronized void sleep(long waitNanos) throws InterruptedException {
        while (waitNanos > 0 && isRunning()) {
            long start = System.nanoTime();
            TimeUnit.NANOSECONDS.timedWait(this, waitNanos);
            waitNanos -= System.nanoTime() - start;
        }
    }
1220380
public void requestDone() {
        currentRequest = null;

        if (anyAreSet(state, CLOSE_REQ)) {
            safeClose(connection);
        } else if (anyAreSet(state, UPGRADE_REQUESTED)) {
            safeClose(connection); //we don't support upgrade, just close the connection to be safe
            return;
        }

        AjpClientExchange next = pendingQueue.poll();

        if (next != null) {
            initiateRequest(next);
        }
    }
1236693
public void requestCancellation() {
        Collection<CompletableFuture<?>> toInvoke;
        synchronized (this.futures) {
            this.cancellationRequested = true;
            toInvoke = new ArrayList<>(this.futures);
        }

        toInvoke.forEach(f -> f.cancel(true));
        synchronized (this.futures) {
            this.futures.clear();
        }
    }
224890
static void sleep(long n) {
    try {
      Thread.sleep(n);
    } catch (InterruptedException e) {
      LOG.warn("Thread interrupted", e);
      Thread.currentThread().interrupt();
    }
  }
488045
@Override
    protected void onStop()
    {
        if( m_serviceCollection != null )
        {
            m_serviceCollection.stop();
            m_serviceCollection = null;
        }
        setService( null );
    }
565895
public void queueRequest(RestRequest<?> request) {
        final RatelimitBucket bucket;
        final boolean alreadyInQueue;
        synchronized (buckets) {
            // Search for a bucket that fits to this request
            bucket = buckets.stream()
                    .filter(b -> b.equals(request.getEndpoint(), request.getMajorUrlParameter().orElse(null)))
                    .findAny()
                    .orElseGet(() -> new RatelimitBucket(
                            api, request.getEndpoint(), request.getMajorUrlParameter().orElse(null)));

            // Must be executed BEFORE adding the request to the queue
            alreadyInQueue = bucket.peekRequestFromQueue() != null;

            // Add the bucket to the set of buckets (does nothing if it's already in the set)
            buckets.add(bucket);

            // Add the request to the bucket's queue
            bucket.addRequestToQueue(request);
        }

        // If the bucket is already in the queue, there's nothing more to do
        if (alreadyInQueue) {
            return;
        }

        // Start working of the queue
        api.getThreadPool().getExecutorService().submit(() -> {
            RestRequest<?> currentRequest = bucket.peekRequestFromQueue();
            RestRequestResult result = null;
            long responseTimestamp = System.currentTimeMillis();
            while (currentRequest != null) {
                try {
                    int sleepTime = bucket.getTimeTillSpaceGetsAvailable();
                    if (sleepTime > 0) {
                        logger.debug("Delaying requests to {} for {}ms to prevent hitting ratelimits",
                                bucket, sleepTime);
                    }

                    // Sleep until space is available
                    while (sleepTime > 0) {
                        try {
                            Thread.sleep(sleepTime);
                        } catch (InterruptedException e) {
                            logger.warn("We got interrupted while waiting for a rate limit!", e);
                        }
                        // Update in case something changed (e.g. because we hit a global ratelimit)
                        sleepTime = bucket.getTimeTillSpaceGetsAvailable();
                    }

                    // Execute the request
                    result = currentRequest.executeBlocking();

                    // Calculate the time offset, if it wasn't done before
                    responseTimestamp = System.currentTimeMillis();
                } catch (Throwable t) {
                    responseTimestamp = System.currentTimeMillis();
                    if (currentRequest.getResult().isDone()) {
                        logger.warn("Received exception for a request that is already done. "
                                + "This should not be able to happen!", t);
                    }
                    // Try to get the response from the exception if it exists
                    if (t instanceof DiscordException) {
                        result = ((DiscordException) t).getResponse()
                                .map(RestRequestResponseInformationImpl.class::cast)
                                .map(RestRequestResponseInformationImpl::getRestRequestResult)
                                .orElse(null);
                    }
                    // Complete the request
                    currentRequest.getResult().completeExceptionally(t);
                } finally {
                    try {
                        // Calculate offset
                        calculateOffset(responseTimestamp, result);
                        // Handle the response
                        handleResponse(currentRequest, result, bucket, responseTimestamp);
                    } catch (Throwable t) {
                        logger.warn("Encountered unexpected exception.", t);
                    }

                    // The request didn't finish, so let's try again
                    if (!currentRequest.getResult().isDone()) {
                        continue;
                    }

                    // Poll a new quest
                    synchronized (buckets) {
                        bucket.pollRequestFromQueue();
                        currentRequest = bucket.peekRequestFromQueue();
                        if (currentRequest == null) {
                            buckets.remove(bucket);
                        }
                    }
                }
            }
        });
    }
532684
@Override
    public final void initialize(final HttpRequest request) {
        request.setReadTimeout(2 * ONEMINITUES); // 2 minutes read timeout
        final HttpUnsuccessfulResponseHandler backoffHandler =
                new HttpBackOffUnsuccessfulResponseHandler(
                        new ExponentialBackOff())
                        .setSleeper(sleeper);
        request.setInterceptor(wrappedCredential);
    request.setUnsuccessfulResponseHandler(
        (request1, response, supportsRetry) -> {
          if (wrappedCredential.handleResponse(request1, response, supportsRetry)) {
            // If credential decides it can handle it, the return code or message indicated
            // something specific to authentication, and no backoff is desired.
            return true;
          } else if (backoffHandler.handleResponse(request1, response, supportsRetry)) {
            // Otherwise, we defer to the judgement of our internal backoff handler.
            LOG.info("Retrying " + request1.getUrl().toString());
            return true;
          } else {
            return false;
          }
        });
        request.setIOExceptionHandler(
                new HttpBackOffIOExceptionHandler(new ExponentialBackOff())
                        .setSleeper(sleeper));
    }
1052185
@Override
    public void handle(RequestContext context, AccessDeniedException e) throws SecurityProviderException, IOException {
        saveException(context, e);

        if (StringUtils.isNotEmpty(getErrorPageUrl())) {
            forwardToErrorPage(context);
        } else {
            sendError(e, context);
        }
    }
238182
@Override
    protected boolean performRequest() {

        SocketChannel sc = null;
        boolean closeOnError = false;

        // If we were woken up because we have work to do, do it.
        Set<SelectionKey> keySet = this.selector.selectedKeys();
        Iterator<SelectionKey> keyIterator = keySet.iterator();
        if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
            Tr.debug(this, tc, "performRequest - processing " + keySet.size() + " items");
        }

        while (keyIterator.hasNext()) {
            closeOnError = false;

            // If we get exceptions repeatedly, we may need to take a break for a number of reasons
            if (numExceptions >= 3100) {
                // if we don't recover after 290 more seconds, wait for 10 minutes
                if (pauseAccept()) {
                    resetExceptions(); // clear exceptions if we weren't interrupted
                }
                continue;
            } else if (numExceptions >= 200) {
                // if we get exceptions repeatedly, wait a tenth to give
                // other threads some time. It should take about 10 seconds for
                // us to get up to 200 exceptions (via trace analysis).
                if (numExceptions == 1500) {
                    FFDCFilter.processException(new Exception("TCP channel has received 1500 exceptions in a row on the accept selector"),
                                                getClass().getName(), "101", this);
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ie) {
                    // ignore it
                }
            }

            // PK40415 - change audit handling of errors
            SelectionKey key = keyIterator.next();
            TCPPort endPoint = (TCPPort) key.attachment();
            TCPChannel tcpChannel = endPoint.getTCPChannel();

            try {
                // safe remove from set while iterating
                keyIterator.remove();

                // perform accept
                ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();

                try {
                    sc = serverSocketChannel.accept();

                    // Configure all inbound channels to be non-blocking
                    if (sc != null) {
                        sc.configureBlocking(false);
                    }

                } catch (IOException ioe) {
                    incrementExceptions();
                    this.numAcceptIOExceptions++;
                    if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
                        Tr.event(this, tc, "TCP Channel: " + tcpChannel.getExternalName() + " caught IOException doing accept: " + ioe + " total=" + numExceptions + " count="
                                           + numAcceptIOExceptions);
                    }
                    // Since we could be monitoring several serverSocketChannels, we need
                    // to continue processing even though we got an IOException on this
                    // serverSocketChannel.
                    continue;
                }

                // sometimes the accept can return null. This seems to happen when
                // there is a network problem, and we got notified it was ready to
                // accept, but when we went to do the accept we couldn't complete the accept. If
                // this happens, just skip this and go on
                if (sc == null) {
                    incrementExceptions();
                    this.numAcceptNulls++;
                    if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
                        Tr.event(this, tc, "TCP Channel: " + tcpChannel.getExternalName() + " accept() returned null, total=" + numExceptions + " count=" + numAcceptNulls);
                    }
                    continue;
                }

                Socket socket = sc.socket();
                if (!testSocket(sc)) {
                    continue;
                }
                closeOnError = true;

                if (!tcpChannel.verifyConnection(socket)) {
                    closeSocketChannel(sc);

                    // if we made it this far, then the accept worked without exceptions
                    if (0 < this.numExceptions) {
                        resetExceptions();
                    }
                    continue;
                }

                SocketIOChannel ioSocket = null;
                try {
                    ioSocket = tcpChannel.createInboundSocketIOChannel(sc);
                } catch (IOException ioe) {
                    // no FFDC required
                    incrementExceptions();
                    this.numConfigureIOExceptions++;
                    if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
                        Tr.event(this, tc, "IOException caught while configuring socket: " + ioe + ", total=" + numExceptions + " count=" + numConfigureIOExceptions);
                    }
                    closeSocketChannel(sc);
                    continue;
                }
                endPoint.processNewConnection(ioSocket);

            } catch (CancelledKeyException cke) {
                // no FFDC required
                // Should only get this if the socket was closed. Therefore
                // log error and continue processing
                incrementExceptions();
                this.numCancelledKeys++;
                if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
                    Tr.event(this, tc, "Cancelled key exception found, cke=" + cke + " total=" + numExceptions + " count=" + numCancelledKeys);
                }
                continue;
            } catch (Throwable t) {
                // don't leak sockets if we can't proceed after the accept
                if (closeOnError) {
                    closeSocketChannel(sc);
                }
                // the catcher of the RTE will do the FFDC
                throw new RuntimeException(t);
            }

            // if we made it this far, then the accept worked without exceptions
            if (0 < this.numExceptions) {
                resetExceptions();
            }
        } // end-while
        return false;
    }
337127
@SuppressWarnings("unchecked")
  private void handleResponseOk(long requestId, Object response) {
    ContextualFuture future = futures.remove(requestId);
    if (future != null) {
      future.context.executor().execute(() -> future.complete(response));
    }
  }
496284
@Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String stackTrace = getStackTrace(baseRequest);
        if (stackTrace != null) {
            response.getWriter().print(getStackTrace(baseRequest));
        } else {
            super.handle(target, baseRequest, request, response);
        }
    }