in finagle-core/src/main/scala/com/twitter/finagle/client/BackupRequestFilter.scala [389:490]
def this(
maxExtraLoadTunable: Tunable[Double],
sendInterrupts: Boolean,
minSendBackupAfterMs: Int,
responseClassifier: ResponseClassifier,
clientRetryBudget: RetryBudget,
statsReceiver: StatsReceiver,
timer: Timer,
serviceName: String
) =
this(
maxExtraLoadTunable,
sendInterrupts,
minSendBackupAfterMs,
responseClassifier,
newRetryBudget = BackupRequestFilter.newRetryBudget,
clientRetryBudget = clientRetryBudget,
Stopwatch.systemMillis,
statsReceiver,
timer,
() => new WindowedPercentileHistogram(timer),
serviceName
)
def this(
maxExtraLoadTunable: Tunable[Double],
sendInterrupts: Boolean,
minSendBackupAfterMs: Int,
responseClassifier: ResponseClassifier,
clientRetryBudget: RetryBudget,
lowestDiscernibleMsValue: Int,
highestTrackableMsValue: Int,
statsReceiver: StatsReceiver,
timer: Timer,
serviceName: String
) =
this(
maxExtraLoadTunable,
sendInterrupts,
minSendBackupAfterMs,
responseClassifier,
newRetryBudget = BackupRequestFilter.newRetryBudget,
clientRetryBudget = clientRetryBudget,
Stopwatch.systemMillis,
statsReceiver,
timer,
() =>
new WindowedPercentileHistogram(
WindowedPercentileHistogram.DefaultNumBuckets,
WindowedPercentileHistogram.DefaultBucketSize,
lowestDiscernibleMsValue,
highestTrackableMsValue,
timer
),
serviceName
)
@volatile private[this] var backupRequestRetryBudget: RetryBudget =
newRetryBudget(getAndValidateMaxExtraLoad(maxExtraLoadTunable), nowMs)
private[this] val SupersededRequestFailure = Failure
.ignorable(SupersededRequestFailureWhy)
.withSource(Failure.Source.Service, serviceName)
.withSource(Failure.Source.AppId, ServerInfo().id)
private[this] def percentileFromMaxExtraLoad(maxExtraLoad: Double): Double =
1.0 - maxExtraLoad
private[this] val windowedPercentile: WindowedPercentileHistogram =
windowedPercentileHistogramFac()
// Prevent sending a backup on the first request
@volatile private[this] var sendBackupAfterMillis: Int = Int.MaxValue
// For testing
private[client] def sendBackupAfterDuration: Duration =
Duration.fromMilliseconds(sendBackupAfterMillis)
private[this] val sendAfterStat = statsReceiver.stat("send_backup_after_ms")
private[this] val backupsSent = statsReceiver.counter("backups_sent")
// Indicates that the backup request returned first and it succeeded.
private[this] val backupsWon = statsReceiver.counter("backups_won")
private[this] val budgetExhausted = statsReceiver.counter("budget_exhausted")
// schedule timer to refresh `sendBackupAfter`, and refresh `backupRequestRetryBudget` in response
// to changes to the value of `maxExtraLoadTunable`,
private[this] val refreshTimerTask: TimerTask = {
@volatile var curMaxExtraLoad = getAndValidateMaxExtraLoad(maxExtraLoadTunable)
@volatile var percentile = percentileFromMaxExtraLoad(curMaxExtraLoad)
timer.schedule(RefreshPercentileInterval) {
val newMaxExtraLoad = getAndValidateMaxExtraLoad(maxExtraLoadTunable)
if (curMaxExtraLoad != newMaxExtraLoad) {
curMaxExtraLoad = newMaxExtraLoad
percentile = percentileFromMaxExtraLoad(curMaxExtraLoad)
backupRequestRetryBudget = newRetryBudget(curMaxExtraLoad, nowMs)
}
sendBackupAfterMillis =
Math.max(minSendBackupAfterMs, windowedPercentile.percentile(percentile))
sendAfterStat.add(sendBackupAfterMillis)
}
}