1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27 package org.apache.hc.client5.http.impl.classic;
28
29 import org.apache.hc.client5.http.HttpRoute;
30 import org.apache.hc.core5.pool.ConnPoolControl;
31 import org.apache.hc.core5.util.Args;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36 * A backoff manager implementation that uses an exponential backoff algorithm to adjust the maximum
37 * number of connections per HTTP route. The algorithm reduces the number of connections in response
38 * to adverse events, such as connection failures, and gradually increases the number of connections
39 * when the route is operating without issues.
40 *
41 * <p>This implementation is specifically designed for managing connections in an HTTP route context
42 * and provides methods for probing and backing off connections based on the performance of the route.
43 *
44 * <p>The exponential backoff algorithm is primarily implemented in the {@code getBackedOffPoolSize}
45 * method, which calculates the new connection pool size based on the current pool size, growth rate,
46 * and the number of time intervals.
47 *
48 * @since 5.3
49 */
50 public class ExponentialBackoffManager extends AbstractBackoff {
51
52 private static final Logger LOG = LoggerFactory.getLogger(ExponentialBackoffManager.class);
53
54
55 /**
56 * Constructs a new ExponentialBackoffManager with the specified connection pool control.
57 *
58 * @param connPerRoute the connection pool control to be used for managing connections
59 * @throws IllegalArgumentException if connPerRoute is null
60 */
61 public ExponentialBackoffManager(final ConnPoolControl<HttpRoute> connPerRoute) {
62 super(connPerRoute);
63
64 }
65
66 /**
67 * Calculates the new pool size after applying the exponential backoff algorithm.
68 * The new pool size is calculated using the formula: floor(curr / (1 + growthRate) ^ t),
69 * where curr is the current pool size, growthRate is the exponential growth rate, and t is the time interval.
70 *
71 * @param curr the current pool size
72 * @return the new pool size after applying the backoff
73 */
74 @Override
75 protected int getBackedOffPoolSize(final int curr) {
76 if (curr <= 1) {
77 return 1;
78 }
79 final int t = getTimeInterval().incrementAndGet();
80 final int result = Math.max(1, (int) Math.floor(curr / Math.pow(1 + getBackoffFactor().get(), t)));
81
82 if (LOG.isDebugEnabled()) {
83 LOG.debug("curr={}, t={}, growthRate={}, result={}", curr, t, getBackoffFactor().get(), result);
84 }
85 return result;
86 }
87
88 @Override
89 public void setBackoffFactor(final double rate) {
90 Args.check(rate > 0.0, "Growth rate must be greater than 0.0");
91 this.getBackoffFactor().set(rate);
92 }
93
94 }