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

com.proofpoint.http.client.balancing.TokenRetryBudget Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 Proofpoint, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.proofpoint.http.client.balancing;

import com.google.common.base.Ticker;
import com.google.common.primitives.Ints;
import com.proofpoint.stats.SparseCounterStat;
import com.proofpoint.units.Duration;
import org.weakref.jmx.Nested;

import java.math.BigDecimal;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Math.toIntExact;
import static java.math.BigDecimal.ROUND_HALF_UP;
import static java.math.BigDecimal.ZERO;
import static java.util.concurrent.TimeUnit.SECONDS;

class TokenRetryBudget
        implements RetryBudget
{
    private static final BigDecimal SCALE_FACTOR = new BigDecimal(1000);
    private final int depositAmount;
    private final int withdrawalAmount;
    private final LeakyTokenBucket tokenBucket;
    private final SparseCounterStat retryBudgetExhausted = new SparseCounterStat();

    private TokenRetryBudget(BigDecimal retryBudgetRatio, Duration retryBudgetRatioPeriod, int retryBudgetMinPerSecond, Ticker ticker)
    {
        // if you only have minRetries, everything costs 1 but you
        // get no credit for requests. all credits come via time.
        if (retryBudgetRatio.equals(ZERO)) {
            depositAmount = 0;
            withdrawalAmount = 1;
        }
        else {
            depositAmount = SCALE_FACTOR.intValue();
            withdrawalAmount = SCALE_FACTOR.divide(retryBudgetRatio, ROUND_HALF_UP).intValue();
        }

        // compute the reserve by scaling retryBudgetMinPerSecond by retryBudgetRatioPeriod and retry cost
        // to allow for clients that've just started or have low rps
        int reserve = retryBudgetMinPerSecond * toIntExact(retryBudgetRatioPeriod.roundTo(SECONDS)) * withdrawalAmount;
        tokenBucket = new LeakyTokenBucket(retryBudgetRatioPeriod, reserve, ticker);
    }

    static RetryBudget tokenRetryBudget(BigDecimal retryBudgetRatio, Duration retryBudgetRatioPeriod, int retryBudgetMinPerSecond, Ticker ticker)
    {
        checkArgument(retryBudgetRatio.compareTo(ZERO) >= 0, "retryBudgetRatio must be non-negative");
        checkArgument(retryBudgetRatio.compareTo(SCALE_FACTOR) <= 0, "retryBudgetRatio must be no greater than " + SCALE_FACTOR);
        checkArgument(retryBudgetRatioPeriod.compareTo(new Duration(1, SECONDS)) >= 0, " retryBudgetRatioPeriod must be at least 1s");
        checkArgument(retryBudgetRatioPeriod.compareTo(new Duration(60, SECONDS)) <= 0, " retryBudgetRatioPeriod must be at most 60s");
        checkArgument(retryBudgetMinPerSecond >= 0, "retryBudgetMinPerSecond must be non-negative");

        if (retryBudgetRatio.equals(ZERO) && retryBudgetMinPerSecond == 0) {
            return NoRetryBudget.INSTANCE;
        }
        return new TokenRetryBudget(retryBudgetRatio, retryBudgetRatioPeriod, retryBudgetMinPerSecond, ticker);
    }

    @Override
    public void initialAttempt()
    {
        tokenBucket.put(depositAmount);
    }

    @Override
    public boolean canRetry()
    {
        if (tokenBucket.tryGet(withdrawalAmount)) {
            return true;
        }
        retryBudgetExhausted.add(1);
        return false;
    }

    @Nested
    public SparseCounterStat getRetryBudgetExhausted()
    {
        return retryBudgetExhausted;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy